1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: etiff.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_goodies.hxx"
34 #include <vcl/graph.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <vcl/bmpacc.hxx>
38 #include <svtools/solar.hrc>
39 #include <svtools/fltcall.hxx>
40 #include <svtools/FilterConfigItem.hxx>
42 #define NewSubfileType 254
43 #define ImageWidth 256
44 #define ImageLength 257
45 #define BitsPerSample 258
46 #define Compression 259
47 #define PhotometricInterpretation 262
48 #define StripOffsets 273
49 #define SamplesPerPixel 277
50 #define RowsPerStrip 278
51 #define StripByteCounts 279
52 #define XResolution 282
53 #define YResolution 283
54 #define PlanarConfiguration 284
55 #define ResolutionUnit 296
57 #define ReferenceBlackWhite 532
63 struct TIFFLZWCTreeNode
66 TIFFLZWCTreeNode
* pBrother
; // naechster Knoten, der den selben Vater hat
67 TIFFLZWCTreeNode
* pFirstChild
; // erster Sohn
68 USHORT nCode
; // Der Code fuer den String von Pixelwerten, der sich ergibt, wenn
69 USHORT nValue
; // Der Pixelwert
80 BitmapReadAccess
* mpAcc
;
82 UINT32 mnWidth
, mnHeight
, mnColors
;
83 UINT32 mnCurAllPictHeight
;
84 UINT32 mnSumOfAllPictHeight
;
85 UINT32 mnBitsPerPixel
;
88 UINT32 mnLatestIfdPos
;
89 UINT16 mnTagCount
; // number of tags already written
90 UINT32 mnCurrentTagCountPos
; // offset to the position where the current
91 // tag count is to insert
93 UINT32 mnXResPos
; // if != 0 this DWORDs stores the
94 UINT32 mnYResPos
; // actual streamposition of the
95 UINT32 mnPalPos
; // Tag Entry
97 UINT32 mnStripByteCountPos
;
99 TIFFLZWCTreeNode
* pTable
;
100 TIFFLZWCTreeNode
* pPrefix
;
109 com::sun::star::uno::Reference
< com::sun::star::task::XStatusIndicator
> xStatusIndicator
;
111 void ImplCallback( UINT32 nPercent
);
112 BOOL
ImplWriteHeader( BOOL bMultiPage
);
113 void ImplWritePalette();
114 BOOL
ImplWriteBody();
115 void ImplWriteTag( UINT16 TagID
, UINT16 DataType
, UINT32 NumberOfItems
, UINT32 Value
);
116 void ImplWriteResolution( ULONG nStreamPos
, sal_uInt32 nResolutionUnit
);
117 void StartCompression();
118 void Compress( BYTE nSrc
);
119 void EndCompression();
120 inline void WriteBits( USHORT nCode
, USHORT nCodeLen
);
127 BOOL
WriteTIFF( const Graphic
& rGraphic
, SvStream
& rTIFF
, FilterConfigItem
* pFilterConfigItem
);
130 // ------------------------------------------------------------------------
132 TIFFWriter::TIFFWriter() :
135 mnCurAllPictHeight ( 0 ),
136 mnSumOfAllPictHeight( 0 ),
141 mnStripByteCountPos ( 0 )
145 // ------------------------------------------------------------------------
147 TIFFWriter::~TIFFWriter()
151 // ------------------------------------------------------------------------
153 BOOL
TIFFWriter::WriteTIFF( const Graphic
& rGraphic
, SvStream
& rTIFF
, FilterConfigItem
* pFilterConfigItem
)
155 ULONG
* pDummy
= new ULONG
; delete pDummy
; // damit unter OS/2
156 // das richtige (Tools-)new
157 // verwendet wird, da es sonst
158 // in dieser DLL nur Vector-news
161 if ( pFilterConfigItem
)
163 xStatusIndicator
= pFilterConfigItem
->GetStatusIndicator();
164 if ( xStatusIndicator
.is() )
167 xStatusIndicator
->start( aMsg
, 100 );
171 // #i69169# copy stream
174 const UINT16 nOldFormat
= mpOStm
->GetNumberFormatInt();
175 mnStreamOfs
= mpOStm
->Tell();
177 // we will use the BIG Endian Mode
179 mpOStm
->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN
);
180 *mpOStm
<< (UINT32
)0x4d4d002a; // TIFF identifier
181 mnLatestIfdPos
= mpOStm
->Tell();
182 *mpOStm
<< (UINT32
)0;
184 Animation aAnimation
;
189 if ( rGraphic
.IsAnimated() )
190 aAnimation
= rGraphic
.GetAnimation();
193 AnimationBitmap
aAnimationBitmap( rGraphic
.GetBitmap(), Point(), Size() );
194 aAnimation
.Insert( aAnimationBitmap
);
198 for ( i
= 0; i
< aAnimation
.Count(); i
++ )
199 mnSumOfAllPictHeight
+= aAnimation
.Get( i
).aBmpEx
.GetSizePixel().Height();
201 for ( i
= 0; mbStatus
&& ( i
< aAnimation
.Count() ); i
++ )
204 const AnimationBitmap
& rAnimationBitmap
= aAnimation
.Get( i
);
205 aBmp
= rAnimationBitmap
.aBmpEx
.GetBitmap();
206 mpAcc
= aBmp
.AcquireReadAccess();
209 mnBitsPerPixel
= aBmp
.GetBitCount();
211 // export code below only handles four discrete cases
213 mnBitsPerPixel
<= 1 ? 1 : mnBitsPerPixel
<= 4 ? 4 : mnBitsPerPixel
<= 8 ? 8 : 24;
215 if ( ImplWriteHeader( ( aAnimation
.Count() > 0 ) ) )
217 Size
aDestMapSize( 300, 300 );
218 const MapMode
aMapMode( aBmp
.GetPrefMapMode() );
219 if ( aMapMode
.GetMapUnit() != MAP_PIXEL
)
221 const Size
aPrefSize( rGraphic
.GetPrefSize() );
222 aDestMapSize
= OutputDevice::LogicToLogic( aPrefSize
, aMapMode
, MAP_INCH
);
224 ImplWriteResolution( mnXResPos
, aDestMapSize
.Width() );
225 ImplWriteResolution( mnYResPos
, aDestMapSize
.Height() );
230 UINT32 nCurPos
= mpOStm
->Tell();
231 mpOStm
->Seek( mnCurrentTagCountPos
);
232 *mpOStm
<< mnTagCount
;
233 mpOStm
->Seek( nCurPos
);
235 aBmp
.ReleaseAccess( mpAcc
);
241 mpOStm
->SetNumberFormatInt( nOldFormat
);
243 if ( xStatusIndicator
.is() )
244 xStatusIndicator
->end();
249 // ------------------------------------------------------------------------
251 void TIFFWriter::ImplCallback( UINT32 nPercent
)
253 if ( xStatusIndicator
.is() )
255 if( nPercent
>= mnLastPercent
+ 3 )
257 mnLastPercent
= nPercent
;
258 if ( nPercent
<= 100 )
259 xStatusIndicator
->setValue( nPercent
);
265 // ------------------------------------------------------------------------
267 BOOL
TIFFWriter::ImplWriteHeader( BOOL bMultiPage
)
270 mnWidth
= mpAcc
->Width();
271 mnHeight
= mpAcc
->Height();
273 if ( mnWidth
&& mnHeight
&& mnBitsPerPixel
&& mbStatus
)
275 UINT32 nCurrentPos
= mpOStm
->Tell();
276 mpOStm
->Seek( mnLatestIfdPos
);
277 *mpOStm
<< (UINT32
)( nCurrentPos
- mnStreamOfs
); // offset to the IFD
278 mpOStm
->Seek( nCurrentPos
);
280 // (OFS8) TIFF image file directory (IFD)
281 mnCurrentTagCountPos
= mpOStm
->Tell();
282 *mpOStm
<< (UINT16
)0; // the number of tagentrys is to insert later
284 UINT32 nSubFileFlags
= 0;
287 ImplWriteTag( NewSubfileType
, 4, 1, nSubFileFlags
);
288 ImplWriteTag( ImageWidth
, 4, 1, mnWidth
);
289 ImplWriteTag( ImageLength
, 4, 1, mnHeight
);
290 ImplWriteTag( BitsPerSample
, 3, 1, ( mnBitsPerPixel
== 24 ) ? 8 : mnBitsPerPixel
);
291 ImplWriteTag( Compression
, 3, 1, 5 );
293 switch ( mnBitsPerPixel
)
306 nTemp
= 0; // -Wall set a default...
309 ImplWriteTag( PhotometricInterpretation
, 3, 1, nTemp
);
310 mnBitmapPos
= mpOStm
->Tell();
311 ImplWriteTag( StripOffsets
, 4, 1, 0 );
312 ImplWriteTag( SamplesPerPixel
, 3, 1, ( mnBitsPerPixel
== 24 ) ? 3 : 1 );
313 ImplWriteTag( RowsPerStrip
, 4, 1, mnHeight
); //0xffffffff );
314 mnStripByteCountPos
= mpOStm
->Tell();
315 ImplWriteTag( StripByteCounts
, 4, 1, ( ( mnWidth
* mnBitsPerPixel
* mnHeight
) + 7 ) >> 3 );
316 mnXResPos
= mpOStm
->Tell();
317 ImplWriteTag( XResolution
, 5, 1, 0 );
318 mnYResPos
= mpOStm
->Tell();
319 ImplWriteTag( YResolution
, 5, 1, 0 );
320 if ( mnBitsPerPixel
!= 1 )
321 ImplWriteTag( PlanarConfiguration
, 3, 1, 1 ); // ( RGB ORDER )
322 ImplWriteTag( ResolutionUnit
, 3, 1, 2); // Resolution Unit is Inch
323 if ( ( mnBitsPerPixel
== 4 ) || ( mnBitsPerPixel
== 8 ) )
325 mnColors
= mpAcc
->GetPaletteEntryCount();
326 mnPalPos
= mpOStm
->Tell();
327 ImplWriteTag( ColorMap
, 3, 3 * mnColors
, 0 );
330 // and last we write zero to close the num dir entries list
331 mnLatestIfdPos
= mpOStm
->Tell();
332 *mpOStm
<< (UINT32
)0; // there are no more IFD
340 // ------------------------------------------------------------------------
342 void TIFFWriter::ImplWritePalette()
345 ULONG nCurrentPos
= mpOStm
->Tell();
346 mpOStm
->Seek( mnPalPos
+ 8 ); // the palette tag entry needs the offset
347 *mpOStm
<< static_cast<sal_uInt32
>(nCurrentPos
- mnStreamOfs
); // to the palette colors
348 mpOStm
->Seek( nCurrentPos
);
350 for ( i
= 0; i
< mnColors
; i
++ )
352 const BitmapColor
& rColor
= mpAcc
->GetPaletteColor( i
);
353 *mpOStm
<< (UINT16
)( rColor
.GetRed() << 8 );
355 for ( i
= 0; i
< mnColors
; i
++ )
357 const BitmapColor
& rColor
= mpAcc
->GetPaletteColor( i
);
358 *mpOStm
<< (UINT16
)( rColor
.GetGreen() << 8 );
360 for ( i
= 0; i
< mnColors
; i
++ )
362 const BitmapColor
& rColor
= mpAcc
->GetPaletteColor( i
);
363 *mpOStm
<< (UINT16
)( rColor
.GetBlue() << 8 );
367 // ------------------------------------------------------------------------
369 BOOL
TIFFWriter::ImplWriteBody()
375 ULONG nGfxBegin
= mpOStm
->Tell();
376 mpOStm
->Seek( mnBitmapPos
+ 8 ); // the strip offset tag entry needs the offset
377 *mpOStm
<< static_cast<sal_uInt32
>(nGfxBegin
- mnStreamOfs
); // to the bitmap data
378 mpOStm
->Seek( nGfxBegin
);
382 switch( mnBitsPerPixel
)
386 for ( y
= 0; y
< mnHeight
; y
++, mnCurAllPictHeight
++ )
388 ImplCallback( 100 * mnCurAllPictHeight
/ mnSumOfAllPictHeight
);
389 for ( x
= 0; x
< mnWidth
; x
++ )
391 const BitmapColor
& rColor
= mpAcc
->GetPixel( y
, x
);
392 Compress( rColor
.GetRed() );
393 Compress( rColor
.GetGreen() );
394 Compress( rColor
.GetBlue() );
402 for ( y
= 0; y
< mnHeight
; y
++, mnCurAllPictHeight
++ )
404 ImplCallback( 100 * mnCurAllPictHeight
/ mnSumOfAllPictHeight
);
405 for ( x
= 0; x
< mnWidth
; x
++ )
407 Compress( mpAcc
->GetPixel( y
, x
) );
415 for ( nShift
= 0, y
= 0; y
< mnHeight
; y
++, mnCurAllPictHeight
++ )
417 ImplCallback( 100 * mnCurAllPictHeight
/ mnSumOfAllPictHeight
);
418 for ( x
= 0; x
< mnWidth
; x
++, nShift
++ )
421 nTemp
= ( (BYTE
)mpAcc
->GetPixel( y
, x
) << 4 );
423 Compress( (BYTE
)( nTemp
| ( mpAcc
->GetPixel( y
, x
) & 0xf ) ) );
434 for ( y
= 0; y
< mnHeight
; y
++, mnCurAllPictHeight
++ )
436 ImplCallback( 100 * mnCurAllPictHeight
/ mnSumOfAllPictHeight
);
437 for ( x
= 0; x
< mnWidth
; x
++)
440 j
|= ( ( ~mpAcc
->GetPixel( y
, x
) ) & 1 );
449 Compress( (BYTE
)(j
<< ( ( ( x
& 7) ^ 7 ) + 1 ) ) );
465 if ( mnStripByteCountPos
&& mbStatus
)
467 ULONG nGfxEnd
= mpOStm
->Tell();
468 mpOStm
->Seek( mnStripByteCountPos
+ 8 );
469 *mpOStm
<< static_cast<sal_uInt32
>( nGfxEnd
- nGfxBegin
); // mnStripByteCountPos needs the size of the compression data
470 mpOStm
->Seek( nGfxEnd
);
475 // ------------------------------------------------------------------------
477 void TIFFWriter::ImplWriteResolution( ULONG nStreamPos
, sal_uInt32 nResolutionUnit
)
479 ULONG nCurrentPos
= mpOStm
->Tell();
480 mpOStm
->Seek( nStreamPos
+ 8 );
481 *mpOStm
<< (UINT32
)nCurrentPos
- mnStreamOfs
;
482 mpOStm
->Seek( nCurrentPos
);
483 *mpOStm
<< (UINT32
)1;
484 *mpOStm
<< nResolutionUnit
;
487 // ------------------------------------------------------------------------
489 void TIFFWriter::ImplWriteTag( UINT16 nTagID
, UINT16 nDataType
, UINT32 nNumberOfItems
, UINT32 nValue
)
494 *mpOStm
<< nDataType
;
495 *mpOStm
<< nNumberOfItems
;
496 if ( nDataType
== 3 )
497 nValue
<<=16; // in Big Endian Mode WORDS needed to be shifted to a DWORD
501 // ------------------------------------------------------------------------
503 inline void TIFFWriter::WriteBits( USHORT nCode
, USHORT nCodeLen
)
505 dwShift
|= ( nCode
<< ( nOffset
- nCodeLen
) );
507 while ( nOffset
< 24 )
509 *mpOStm
<< (BYTE
)( dwShift
>> 24 );
513 if ( nCode
== 257 && nOffset
!= 32 )
515 *mpOStm
<< (BYTE
)( dwShift
>> 24 );
519 // ------------------------------------------------------------------------
521 void TIFFWriter::StartCompression()
526 nClearCode
= 1 << nDataSize
;
527 nEOICode
= nClearCode
+ 1;
528 nTableSize
= nEOICode
+ 1;
529 nCodeSize
= nDataSize
+ 1;
531 nOffset
= 32; // anzahl freier bits in dwShift
534 pTable
= new TIFFLZWCTreeNode
[ 4096 ];
536 for ( i
= 0; i
< 4096; i
++)
538 pTable
[ i
].pBrother
= pTable
[ i
].pFirstChild
= NULL
;
539 pTable
[ i
].nValue
= (BYTE
)( pTable
[ i
].nCode
= i
);
543 WriteBits( nClearCode
, nCodeSize
);
546 // ------------------------------------------------------------------------
548 void TIFFWriter::Compress( BYTE nCompThis
)
556 pPrefix
= pTable
+ nCompThis
;
561 for( p
= pPrefix
->pFirstChild
; p
!= NULL
; p
= p
->pBrother
)
563 if ( p
->nValue
== nV
)
571 WriteBits( pPrefix
->nCode
, nCodeSize
);
573 if ( nTableSize
== 409 )
575 WriteBits( nClearCode
, nCodeSize
);
577 for ( i
= 0; i
< nClearCode
; i
++ )
578 pTable
[ i
].pFirstChild
= NULL
;
580 nCodeSize
= nDataSize
+ 1;
581 nTableSize
= nEOICode
+ 1;
585 if( nTableSize
== (USHORT
)( ( 1 << nCodeSize
) - 1 ) )
588 p
= pTable
+ ( nTableSize
++ );
589 p
->pBrother
= pPrefix
->pFirstChild
;
590 pPrefix
->pFirstChild
= p
;
592 p
->pFirstChild
= NULL
;
595 pPrefix
= pTable
+ nV
;
600 // ------------------------------------------------------------------------
602 void TIFFWriter::EndCompression()
605 WriteBits( pPrefix
->nCode
, nCodeSize
);
607 WriteBits( nEOICode
, nCodeSize
);
611 // ------------------------------------------------------------------------
613 // ---------------------
614 // - exported function -
615 // ---------------------
617 extern "C" BOOL __LOADONCALLAPI
GraphicExport( SvStream
& rStream
, Graphic
& rGraphic
, FilterConfigItem
* pFilterConfigItem
, BOOL
)
619 return TIFFWriter().WriteTIFF( rGraphic
, rStream
, pFilterConfigItem
);
631 static HINSTANCE hDLLInst
= 0;
633 extern "C" int CALLBACK
LibMain( HINSTANCE hDLL
, WORD
, WORD nHeap
, LPSTR
)
643 // ------------------------------------------------------------------------
645 extern "C" int CALLBACK
WEP( int )