xref: /AOO41X/main/vcl/source/gdi/pngread.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <vcl/pngread.hxx>
32 
33 #include <cmath>
34 #include <rtl/crc.h>
35 #include <rtl/memory.h>
36 #include <rtl/alloc.h>
37 #include <tools/zcodec.hxx>
38 #include <tools/stream.hxx>
39 #include <vcl/bmpacc.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/alpha.hxx>
42 #include <osl/endian.h>
43 
44 // -----------
45 // - Defines -
46 // -----------
47 
48 #define PNGCHUNK_IHDR 		0x49484452
49 #define PNGCHUNK_PLTE 		0x504c5445
50 #define PNGCHUNK_IDAT 		0x49444154
51 #define PNGCHUNK_IEND 		0x49454e44
52 #define PNGCHUNK_bKGD 		0x624b4744
53 #define PNGCHUNK_cHRM		0x6348524d
54 #define PNGCHUNK_gAMA 		0x67414d41
55 #define PNGCHUNK_hIST 		0x68495354
56 #define PNGCHUNK_pHYs 		0x70485973
57 #define PNGCHUNK_sBIT 		0x73425420
58 #define PNGCHUNK_tIME		0x74494d45
59 #define PNGCHUNK_tEXt		0x74455874
60 #define PNGCHUNK_tRNS 		0x74524e53
61 #define PNGCHUNK_zTXt 		0x7a545874
62 #define PMGCHUNG_msOG		0x6d734f47		// Microsoft Office Animated GIF
63 
64 #define VIEWING_GAMMA		2.35
65 #define DISPLAY_GAMMA		1.0
66 
67 namespace vcl
68 {
69 // -----------
70 // - statics -
71 // -----------
72 
73 // ------------------------------------------------------------------------------
74 
75 static const sal_uInt8 mpDefaultColorTable[ 256 ] =
76 {	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
77 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
78 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
79 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
80 	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
81 	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
82 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
83 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
84 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
85 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
86 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
87 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
88 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
89 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
90 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
91 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
92 };
93 
94 // -------------
95 // - PNGReaderImpl -
96 // -------------
97 
98 class PNGReaderImpl
99 {
100 private:
101     SvStream&           mrPNGStream;
102     sal_uInt16          mnOrigStreamMode;
103 
104     std::vector< vcl::PNGReader::ChunkData >    maChunkSeq;
105     std::vector< vcl::PNGReader::ChunkData >::iterator maChunkIter;
106     std::vector< sal_uInt8 >::iterator          maDataIter;
107 
108 	Bitmap*				mpBmp;
109 	BitmapWriteAccess*	mpAcc;
110 	Bitmap*				mpMaskBmp;
111 	AlphaMask*			mpAlphaMask;
112 	BitmapWriteAccess*	mpMaskAcc;
113 	ZCodec* 			mpZCodec;
114 	sal_uInt8*				mpInflateInBuf; // as big as the size of a scanline + alphachannel + 1
115 	sal_uInt8*				mpScanPrior;    // pointer to the latest scanline
116 	sal_uInt8*				mpTransTab;		// for transparency in images with palette colortype
117 	sal_uInt8*				mpScanCurrent;  // pointer into the current scanline
118 	sal_uInt8*				mpColorTable;	//
119     sal_Size            mnStreamSize;   // estimate of PNG file size
120     sal_uInt32          mnChunkType;    // Type of current PNG chunk
121     sal_Int32           mnChunkLen;     // Length of current PNG chunk
122     Size                maOrigSize;     // pixel size of the full image
123     Size                maTargetSize;   // pixel size of the result image
124     Size                maPhysSize;     // prefered size in MAP_100TH_MM units
125     sal_uInt32          mnBPP;          // number of bytes per pixel
126     sal_uInt32          mnScansize;     // max size of scanline
127     sal_uInt32          mnYpos;         // latest y position in full image
128     int                 mnPass;         // if interlaced the latest pass ( 1..7 ) else 7
129     sal_uInt32          mnXStart;       // the starting X for the current pass
130     sal_uInt32          mnXAdd;         // the increment for input images X coords for the current pass
131     sal_uInt32          mnYAdd;         // the increment for input images Y coords for the current pass
132     int                 mnPreviewShift; // shift to convert orig image coords into preview image coords
133     int                 mnPreviewMask;  // == ((1 << mnPreviewShift) - 1)
134 	sal_uInt16				mnIStmOldMode;
135 	sal_uInt16				mnTargetDepth;		// pixel depth of target bitmap
136 	sal_uInt8				mnTransRed;
137 	sal_uInt8				mnTransGreen;
138 	sal_uInt8				mnTransBlue;
139 	sal_uInt8				mnPngDepth;		// pixel depth of PNG data
140 	sal_uInt8				mnColorType;
141 	sal_uInt8				mnCompressionType;
142 	sal_uInt8				mnFilterType;
143 	sal_uInt8				mnInterlaceType;
144 	BitmapColor			mcTranspColor;  // transparency mask's transparency "color"
145 	BitmapColor			mcOpaqueColor;  // transparency mask's opaque "color"
146 	sal_Bool				mbTransparent;	// graphic includes an tRNS Chunk or an alpha Channel
147 	sal_Bool				mbAlphaChannel;	// is true for ColorType 4 and 6
148 	sal_Bool				mbRGBTriple;
149 	sal_Bool				mbPalette;		// sal_False if we need a Palette
150 	sal_Bool				mbGrayScale;
151 	sal_Bool				mbzCodecInUse;
152 	sal_Bool				mbStatus;
153 	sal_Bool				mbIDAT;			// sal_True if finished with enough IDAT chunks
154 	sal_Bool				mbGamma;		// sal_True if Gamma Correction available
155 	sal_Bool				mbpHYs;			// sal_True if pysical size of pixel available
156 	sal_Bool			mbIgnoreGammaChunk;
157 
158     bool                ReadNextChunk();
159     void                ReadRemainingChunks();
160     void                SkipRemainingChunks();
161 
162     void                ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor & );
163     void                ImplSetPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex );
164     void                ImplSetTranspPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, sal_Bool bTrans );
165     void                ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex, sal_uInt8 nAlpha );
166 	void				ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor&, sal_uInt8 nAlpha );
167 	void				ImplReadIDAT();
168     bool                ImplPreparePass();
169     void                ImplApplyFilter();
170     void                ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd );
171 	sal_Bool				ImplReadTransparent();
172 	void				ImplGetGamma();
173 	void				ImplGetBackground();
174 	sal_uInt8				ImplScaleColor();
175 	sal_Bool				ImplReadHeader( const Size& rPreviewSizeHint );
176 	sal_Bool				ImplReadPalette();
177 	void				ImplGetGrayPalette( sal_uInt16 );
178 	sal_uInt32			ImplReadsal_uInt32();
179 
180 public:
181 
182                         PNGReaderImpl( SvStream& );
183                         ~PNGReaderImpl();
184 
185     BitmapEx            GetBitmapEx( const Size& rPreviewSizeHint );
186     const std::vector< PNGReader::ChunkData >& GetAllChunks();
187 	void				SetIgnoreGammaChunk( sal_Bool bIgnore ){ mbIgnoreGammaChunk = bIgnore; };
188 };
189 
190 // ------------------------------------------------------------------------------
191 
192 PNGReaderImpl::PNGReaderImpl( SvStream& rPNGStream )
193 :   mrPNGStream( rPNGStream ),
194 	mpBmp			( NULL ),
195 	mpAcc			( NULL ),
196 	mpMaskBmp		( NULL ),
197 	mpAlphaMask		( NULL ),
198 	mpMaskAcc		( NULL ),
199 	mpZCodec		( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
200 	mpInflateInBuf	( NULL ),
201 	mpScanPrior 	( NULL ),
202 	mpTransTab		( NULL ),
203 	mpColorTable	( (sal_uInt8*) mpDefaultColorTable ),
204 	mbzCodecInUse	( sal_False ),
205     mbStatus( sal_True),
206     mbIDAT( sal_False ),
207 	mbGamma				( sal_False ),
208 	mbpHYs				( sal_False ),
209 	mbIgnoreGammaChunk	( sal_False )
210 {
211     // prepare the PNG data stream
212     mnOrigStreamMode = mrPNGStream.GetNumberFormatInt();
213     mrPNGStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
214 
215     // prepare the chunk reader
216     maChunkSeq.reserve( 16 );
217     maChunkIter = maChunkSeq.begin();
218 
219     // estimate PNG file size (to allow sanity checks)
220     const sal_Size nStreamPos = mrPNGStream.Tell();
221     mrPNGStream.Seek( STREAM_SEEK_TO_END );
222     mnStreamSize = mrPNGStream.Tell();
223     mrPNGStream.Seek( nStreamPos );
224 
225     // check the PNG header magic
226     sal_uInt32 nDummy = 0;
227     mrPNGStream >> nDummy;
228     mbStatus = (nDummy == 0x89504e47);
229     mrPNGStream >> nDummy;
230     mbStatus &= (nDummy == 0x0d0a1a0a);
231 
232     mnPreviewShift = 0;
233     mnPreviewMask = (1 << mnPreviewShift) - 1;
234 }
235 
236 // ------------------------------------------------------------------------
237 
238 PNGReaderImpl::~PNGReaderImpl()
239 {
240     mrPNGStream.SetNumberFormatInt( mnOrigStreamMode );
241 
242 	if ( mbzCodecInUse )
243 		mpZCodec->EndCompression();
244 
245 	if( mpColorTable != mpDefaultColorTable )
246 		delete[] mpColorTable;
247 
248     delete mpBmp;
249     delete mpAlphaMask;
250     delete mpMaskBmp;
251     delete[] mpTransTab;
252     delete[] mpInflateInBuf;
253     delete[] mpScanPrior;
254     delete mpZCodec;
255 }
256 
257 // ------------------------------------------------------------------------
258 
259 bool PNGReaderImpl::ReadNextChunk()
260 {
261     if( maChunkIter == maChunkSeq.end() )
262     {
263         // get the next chunk from the stream
264 
265         // unless we are at the end of the PNG stream
266         if( mrPNGStream.IsEof() || (mrPNGStream.GetError() != ERRCODE_NONE) )
267             return false;
268         if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
269             return false;
270 
271         PNGReader::ChunkData aDummyChunk;
272         maChunkIter = maChunkSeq.insert( maChunkSeq.end(), aDummyChunk );
273         PNGReader::ChunkData& rChunkData = *maChunkIter;
274 
275         // read the chunk header
276         mrPNGStream >> mnChunkLen >> mnChunkType;
277         rChunkData.nType = mnChunkType;
278 
279         // #128377#/#149343# sanity check for chunk length
280         if( mnChunkLen < 0 )
281             return false;
282         const sal_Size nStreamPos = mrPNGStream.Tell();
283         if( nStreamPos + mnChunkLen >= mnStreamSize )
284             return false;
285 
286         // calculate chunktype CRC (swap it back to original byte order)
287         sal_uInt32 nChunkType = mnChunkType;;
288         #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
289         nChunkType = SWAPLONG( nChunkType );
290         #endif
291         sal_uInt32 nCRC32 = rtl_crc32( 0, &nChunkType, 4 );
292 
293         // read the chunk data and check the CRC
294         if( mnChunkLen && !mrPNGStream.IsEof() )
295         {
296             rChunkData.aData.resize( mnChunkLen );
297 
298             sal_Int32 nBytesRead = 0;
299             do {
300                 sal_uInt8* pPtr = &rChunkData.aData[ nBytesRead ];
301                 nBytesRead += mrPNGStream.Read( pPtr, mnChunkLen - nBytesRead );
302             } while ( ( nBytesRead < mnChunkLen ) && ( mrPNGStream.GetError() == ERRCODE_NONE ) );
303 
304             nCRC32 = rtl_crc32( nCRC32, &rChunkData.aData[ 0 ], mnChunkLen );
305             maDataIter = rChunkData.aData.begin();
306         }
307         sal_uInt32 nCheck;
308         mrPNGStream >> nCheck;
309         if( nCRC32 != nCheck )
310             return false;
311     }
312     else
313     {
314         // the next chunk was already read
315         mnChunkType = (*maChunkIter).nType;
316         mnChunkLen = (*maChunkIter).aData.size();
317         maDataIter = (*maChunkIter).aData.begin();
318     }
319 
320     ++maChunkIter;
321     if( mnChunkType == PNGCHUNK_IEND )
322         return false;
323     return true;
324 }
325 
326 // ------------------------------------------------------------------------
327 
328 // read the remaining chunks from mrPNGStream
329 void PNGReaderImpl::ReadRemainingChunks()
330 {
331     while( ReadNextChunk() ) ;
332 }
333 
334 // ------------------------------------------------------------------------
335 
336 // move position of mrPNGStream to the end of the file
337 void PNGReaderImpl::SkipRemainingChunks()
338 {
339     // nothing to skip if the last chunk was read
340     if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
341         return;
342 
343     // read from the stream until the IEND chunk is found
344     const sal_Size nStreamPos = mrPNGStream.Tell();
345     while( !mrPNGStream.IsEof() && (mrPNGStream.GetError() == ERRCODE_NONE) )
346     {
347         mrPNGStream >> mnChunkLen >> mnChunkType;
348         if( mnChunkLen < 0 )
349             break;
350         if( nStreamPos + mnChunkLen >= mnStreamSize )
351             break;
352         mrPNGStream.SeekRel( mnChunkLen + 4 );  // skip data + CRC
353         if( mnChunkType == PNGCHUNK_IEND )
354             break;
355     }
356 }
357 
358 // ------------------------------------------------------------------------
359 
360 const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks()
361 {
362     ReadRemainingChunks();
363     return maChunkSeq;
364 }
365 
366 // ------------------------------------------------------------------------
367 
368 BitmapEx PNGReaderImpl::GetBitmapEx( const Size& rPreviewSizeHint )
369 {
370     // reset to the first chunk
371     maChunkIter = maChunkSeq.begin();
372 
373     // parse the chunks
374     while( mbStatus && !mbIDAT && ReadNextChunk() )
375     {
376         switch( mnChunkType )
377 		{
378 			case PNGCHUNK_IHDR :
379 			{
380 				mbStatus = ImplReadHeader( rPreviewSizeHint );
381 			}
382 			break;
383 
384 			case PNGCHUNK_gAMA :								// the gamma chunk must precede
385 			{													// the 'IDAT' and also the 'PLTE'(if available )
386 				if ( !mbIgnoreGammaChunk && ( mbIDAT == sal_False ) )
387 					ImplGetGamma();
388 			}
389 			break;
390 
391 			case PNGCHUNK_PLTE :
392 			{
393 				if ( !mbPalette )
394 					mbStatus = ImplReadPalette();
395 			}
396 			break;
397 
398 			case PNGCHUNK_tRNS :
399 			{
400 				if ( !mbIDAT )									// the tRNS chunk must precede the IDAT
401 					mbStatus = ImplReadTransparent();
402 			}
403 			break;
404 
405 			case PNGCHUNK_bKGD :								// the background chunk must appear
406 			{
407 				if ( ( mbIDAT == sal_False ) && mbPalette ) 		// before the 'IDAT' and after the
408 					ImplGetBackground();						// PLTE(if available ) chunk.
409 			}
410 			break;
411 
412 			case PNGCHUNK_IDAT :
413 			{
414 				if ( !mpInflateInBuf )	// taking care that the header has properly been read
415 					mbStatus = sal_False;
416 				else if ( !mbIDAT )		// the gfx is finished, but there may be left a zlibCRC of about 4Bytes
417 					ImplReadIDAT();
418 			}
419 			break;
420 
421 			case PNGCHUNK_pHYs :
422 			{
423 				if ( !mbIDAT && mnChunkLen == 9 )
424 				{
425                     sal_uInt32 nXPixelPerMeter = ImplReadsal_uInt32();
426                     sal_uInt32 nYPixelPerMeter = ImplReadsal_uInt32();
427 
428                     sal_uInt8 nUnitSpecifier = *maDataIter++;
429                     if( (nUnitSpecifier == 1) && nXPixelPerMeter && nXPixelPerMeter )
430                     {
431                         mbpHYs = sal_True;
432 
433                         // convert into MAP_100TH_MM
434                         maPhysSize.Width()  = (sal_Int32)( (100000.0 * maOrigSize.Width()) / nXPixelPerMeter );
435                         maPhysSize.Height() = (sal_Int32)( (100000.0 * maOrigSize.Height()) / nYPixelPerMeter );
436                     }
437 				}
438 			}
439 			break;
440 
441             case PNGCHUNK_IEND:
442                 mbStatus = mbIDAT;  // there is a problem if the image is not complete yet
443             break;
444 		}
445 	}
446 
447     // release write access of the bitmaps
448 	if ( mpAcc )
449 		mpBmp->ReleaseAccess( mpAcc ), mpAcc = NULL;
450 
451 	if ( mpMaskAcc )
452 	{
453 		if ( mpAlphaMask )
454 			mpAlphaMask->ReleaseAccess( mpMaskAcc );
455 		else if ( mpMaskBmp )
456 			mpMaskBmp->ReleaseAccess( mpMaskAcc );
457 
458 		mpMaskAcc = NULL;
459 	}
460 
461     // return the resulting BitmapEx
462     BitmapEx aRet;
463 
464     if( !mbStatus || !mbIDAT )
465         aRet.Clear();
466     else
467 	{
468 		if ( mpAlphaMask )
469 			aRet = BitmapEx( *mpBmp, *mpAlphaMask );
470 		else if ( mpMaskBmp )
471 			aRet = BitmapEx( *mpBmp, *mpMaskBmp );
472 		else
473 			aRet = *mpBmp;
474 
475 		if ( mbpHYs && maPhysSize.Width() && maPhysSize.Height() )
476 		{
477 			aRet.SetPrefMapMode( MAP_100TH_MM );
478 			aRet.SetPrefSize( maPhysSize );
479 		}
480 
481 #if 0
482         // TODO: make sure nobody depends on the stream being after the IEND chunks
483         // => let them do ReadChunks before
484         ReadRemainingChunks();
485 #endif
486 	}
487 
488 	return aRet;
489 }
490 
491 // ------------------------------------------------------------------------
492 
493 sal_Bool PNGReaderImpl::ImplReadHeader( const Size& rPreviewSizeHint )
494 {
495     if( mnChunkLen < 13 )
496         return sal_False;
497 
498     maOrigSize.Width()  = ImplReadsal_uInt32();
499     maOrigSize.Height() = ImplReadsal_uInt32();
500 
501     if ( !maOrigSize.Width() || !maOrigSize.Height() )
502         return sal_False;
503 
504     mnPngDepth = *(maDataIter++);
505     mnColorType = *(maDataIter++);
506 
507     mnCompressionType = *(maDataIter++);
508     if( mnCompressionType != 0 )    // unknown compression type
509         return sal_False;
510 
511     mnFilterType = *(maDataIter++);
512     if( mnFilterType != 0 )         // unknown filter type
513         return sal_False;
514 
515     mnInterlaceType = *(maDataIter++);
516     switch ( mnInterlaceType ) // filter type valid ?
517 	{
518 		case 0 :  // progressive image
519 			mnPass = 7;
520 			break;
521 		case 1 :  // Adam7-interlaced image
522 			mnPass = 0;
523 			break;
524 		default:
525 			return sal_False;
526 	}
527 
528 	mbPalette = sal_True;
529 	mbIDAT = mbAlphaChannel = mbTransparent = sal_False;
530 	mbGrayScale = mbRGBTriple = sal_False;
531 	mnTargetDepth = mnPngDepth;
532 	sal_uInt64 nScansize64 = ( ( static_cast< sal_uInt64 >( maOrigSize.Width() ) * mnPngDepth ) + 7 ) >> 3;
533 
534 	// valid color types are 0,2,3,4 & 6
535 	switch ( mnColorType )
536 	{
537 		case 0 :	// each pixel is a grayscale
538 		{
539 			switch ( mnPngDepth )
540 			{
541 				case 2 : // 2bit target not available -> use four bits
542 					mnTargetDepth = 4;	// we have to expand the bitmap
543 					mbGrayScale = sal_True;
544 					break;
545 				case 16 :
546 					mnTargetDepth = 8;	// we have to reduce the bitmap
547 					// fall through
548 				case 1 :
549 				case 4 :
550 				case 8 :
551 					mbGrayScale = sal_True;
552 					break;
553 				default :
554 					return sal_False;
555 			}
556 		}
557 		break;
558 
559 		case 2 :	// each pixel is an RGB triple
560 		{
561 			mbRGBTriple = sal_True;
562 			nScansize64 *= 3;
563 			switch ( mnPngDepth )
564 			{
565 				case 16 :			// we have to reduce the bitmap
566 				case 8 :
567 					mnTargetDepth = 24;
568 					break;
569 				default :
570 					return sal_False;
571 			}
572 		}
573 		break;
574 
575 		case 3 :	// each pixel is a palette index
576 		{
577 			switch ( mnPngDepth )
578 			{
579 				case 2 :
580 					mnTargetDepth = 4;	// we have to expand the bitmap
581 					// fall through
582 				case 1 :
583 				case 4 :
584 				case 8 :
585 					mbPalette = sal_False;
586 					break;
587 				default :
588 					return sal_False;
589 			}
590 		}
591 		break;
592 
593 		case 4 :	// each pixel is a grayscale sample followed by an alpha sample
594 		{
595 			nScansize64 *= 2;
596 			mbAlphaChannel = sal_True;
597 			switch ( mnPngDepth )
598 			{
599 				case 16 :
600 					mnTargetDepth = 8;	// we have to reduce the bitmap
601 				case 8 :
602 					mbGrayScale = sal_True;
603 					break;
604 				default :
605 					return sal_False;
606 			}
607 		}
608 		break;
609 
610 		case 6 :	// each pixel is an RGB triple followed by an alpha sample
611 		{
612 			mbRGBTriple = sal_True;
613 			nScansize64 *= 4;
614 			mbAlphaChannel = sal_True;
615 			switch (mnPngDepth )
616 			{
617 				case 16 :			// we have to reduce the bitmap
618 				case 8 :
619 					mnTargetDepth = 24;
620 					break;
621 				default :
622 					return sal_False;
623 			}
624 		}
625 		break;
626 
627 		default :
628 			return sal_False;
629 	}
630 
631     mnBPP = static_cast< sal_uInt32 >( nScansize64 / maOrigSize.Width() );
632     if ( !mnBPP )
633         mnBPP = 1;
634 
635     nScansize64++;       // each scanline includes one filterbyte
636 
637 	if ( nScansize64 > SAL_MAX_UINT32 )
638 		return sal_False;
639 
640 	mnScansize = static_cast< sal_uInt32 >( nScansize64 );
641 
642     // TODO: switch between both scanlines instead of copying
643 	mpInflateInBuf = new (std::nothrow) sal_uInt8[ mnScansize ];
644     mpScanCurrent = mpInflateInBuf;
645 	mpScanPrior = new (std::nothrow) sal_uInt8[ mnScansize ];
646 
647 	if ( !mpInflateInBuf || !mpScanPrior )
648 		return sal_False;
649 
650     // calculate target size from original size and the preview hint
651     if( rPreviewSizeHint.Width() || rPreviewSizeHint.Height() )
652     {
653 		Size aPreviewSize( rPreviewSizeHint.Width(), rPreviewSizeHint.Height() );
654         maTargetSize = maOrigSize;
655 
656 		if( aPreviewSize.Width() == 0 ) {
657 			aPreviewSize.setWidth( ( maOrigSize.Width()*aPreviewSize.Height() )/maOrigSize.Height() );
658 			if( aPreviewSize.Width() <= 0 )
659 				aPreviewSize.setWidth( 1 );
660 		} else if( aPreviewSize.Height() == 0 ) {
661 			aPreviewSize.setHeight( ( maOrigSize.Height()*aPreviewSize.Width() )/maOrigSize.Width() );
662 			if( aPreviewSize.Height() <= 0 )
663 				aPreviewSize.setHeight( 1 );
664 		}
665 
666 		if( aPreviewSize.Width() < maOrigSize.Width() && aPreviewSize.Height() < maOrigSize.Height() ) {
667 			OSL_TRACE("preview size %dx%d", aPreviewSize.Width(), aPreviewSize.Height() );
668 
669 			for( int i = 1; i < 5; ++i )
670 				{
671 					if( (maTargetSize.Width() >> i) < aPreviewSize.Width() )
672 						break;
673 					if( (maTargetSize.Height() >> i) < aPreviewSize.Height() )
674 						break;
675 					mnPreviewShift = i;
676 				}
677 			mnPreviewMask = (1 << mnPreviewShift) - 1;
678 		}
679     }
680 
681     maTargetSize.Width()  = (maOrigSize.Width() + mnPreviewMask) >> mnPreviewShift;
682     maTargetSize.Height() = (maOrigSize.Height() + mnPreviewMask) >> mnPreviewShift;
683 
684     mpBmp = new Bitmap( maTargetSize, mnTargetDepth );
685     mpAcc = mpBmp->AcquireWriteAccess();
686     if( !mpAcc )
687         return sal_False;
688 
689     mpBmp->SetSourceSizePixel( maOrigSize );
690 
691     if ( mbAlphaChannel )
692     {
693         mpAlphaMask = new AlphaMask( maTargetSize );
694         mpAlphaMask->Erase( 128 );
695         mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
696         if( !mpMaskAcc )
697             return sal_False;
698     }
699 
700 	if ( mbGrayScale )
701 		ImplGetGrayPalette( mnPngDepth );
702 
703     ImplPreparePass();
704 
705 	return sal_True;
706 }
707 
708 // ------------------------------------------------------------------------
709 
710 void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
711 {
712     if( nBitDepth > 8 )
713         nBitDepth = 8;
714 
715     sal_uInt16  nPaletteEntryCount = 1 << nBitDepth;
716 	sal_uInt32  nAdd = nBitDepth ? 256 / (nPaletteEntryCount - 1) : 0;
717 
718     // no bitdepth==2 available
719     // but bitdepth==4 with two unused bits is close enough
720     if( nBitDepth == 2 )
721         nPaletteEntryCount = 16;
722 
723 	mpAcc->SetPaletteEntryCount( nPaletteEntryCount );
724 	for ( sal_uInt32 i = 0, nStart = 0; nStart < 256; i++, nStart += nAdd )
725 		mpAcc->SetPaletteColor( (sal_uInt16)i, BitmapColor( mpColorTable[ nStart ],
726 			mpColorTable[ nStart ], mpColorTable[ nStart ] ) );
727 }
728 
729 // ------------------------------------------------------------------------
730 
731 sal_Bool PNGReaderImpl::ImplReadPalette()
732 {
733 	sal_uInt16 nCount = static_cast<sal_uInt16>( mnChunkLen / 3 );
734 
735 	if ( ( ( mnChunkLen % 3 ) == 0 ) && ( ( 0 < nCount ) && ( nCount <= 256 ) ) && mpAcc )
736 	{
737 		mbPalette = sal_True;
738 		mpAcc->SetPaletteEntryCount( (sal_uInt16) nCount );
739 
740 		for ( sal_uInt16 i = 0; i < nCount; i++ )
741 		{
742 			sal_uInt8 nRed =   mpColorTable[ *maDataIter++ ];
743 			sal_uInt8 nGreen = mpColorTable[ *maDataIter++ ];
744 			sal_uInt8 nBlue =  mpColorTable[ *maDataIter++ ];
745 			mpAcc->SetPaletteColor( i, Color( nRed, nGreen, nBlue ) );
746 		}
747 	}
748 	else
749 		mbStatus = sal_False;
750 
751 	return mbStatus;
752 }
753 
754 // ------------------------------------------------------------------------
755 
756 sal_Bool PNGReaderImpl::ImplReadTransparent()
757 {
758     bool bNeedAlpha = false;
759 
760 	if ( mpTransTab == NULL )
761 	{
762 		switch ( mnColorType )
763 		{
764 			case 0 :
765 			{
766 				if ( mnChunkLen == 2 )
767 				{
768 					mpTransTab = new sal_uInt8[ 256 ];
769 					rtl_fillMemory( mpTransTab, 256, 0xff );
770                     // color type 0 and 4 is always greyscale,
771                     // so the return value can be used as index
772 					sal_uInt8 nIndex = ImplScaleColor();
773 					mpTransTab[ nIndex ] = 0;
774 					mbTransparent = true;
775 				}
776 			}
777 			break;
778 
779 			case 2 :
780 			{
781 				if ( mnChunkLen == 6 )
782 				{
783 					mnTransRed = ImplScaleColor();
784 					mnTransGreen = ImplScaleColor();
785 					mnTransBlue = ImplScaleColor();
786 					mbTransparent = true;
787 				}
788 			}
789 			break;
790 
791 			case 3 :
792 			{
793 				if ( mnChunkLen <= 256 )
794 				{
795 					mpTransTab = new sal_uInt8 [ 256 ];
796 					rtl_fillMemory( mpTransTab, 256, 0xff );
797 					rtl_copyMemory( mpTransTab, &(*maDataIter), mnChunkLen );
798 					maDataIter += mnChunkLen;
799 					mbTransparent = true;
800 					// need alpha transparency if not on/off masking
801 					for( int i = 0; i < mnChunkLen; ++i )
802 					   bNeedAlpha |= (mpTransTab[i]!=0x00) && (mpTransTab[i]!=0xFF);
803 				}
804 			}
805 			break;
806 		}
807 	}
808 
809     if( mbTransparent && !mbAlphaChannel && !mpMaskBmp )
810     {
811         if( bNeedAlpha)
812         {
813             mpAlphaMask = new AlphaMask( maTargetSize );
814             mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
815         }
816         else
817         {
818             mpMaskBmp = new Bitmap( maTargetSize, 1 );
819             mpMaskAcc = mpMaskBmp->AcquireWriteAccess();
820         }
821         mbTransparent = (mpMaskAcc != NULL);
822         if( !mbTransparent )
823             return sal_False;
824         mcOpaqueColor = BitmapColor( 0x00 );
825         mcTranspColor = BitmapColor( 0xFF );
826         mpMaskAcc->Erase( 0x00 );
827     }
828 
829     return sal_True;
830 }
831 
832 // ------------------------------------------------------------------------
833 
834 void PNGReaderImpl::ImplGetGamma()
835 {
836 	if( mnChunkLen < 4 )
837 	    return;
838 
839 	sal_uInt32	nGammaValue = ImplReadsal_uInt32();
840 	double		fGamma = ( ( VIEWING_GAMMA / DISPLAY_GAMMA ) * ( (double)nGammaValue / 100000 ) );
841 	double 		fInvGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
842 
843 	if ( fInvGamma != 1.0 )
844 	{
845 		mbGamma = sal_True;
846 
847 		if ( mpColorTable == mpDefaultColorTable )
848 			mpColorTable = new sal_uInt8[ 256 ];
849 
850 		for ( sal_Int32 i = 0; i < 256; i++ )
851 			mpColorTable[ i ] = (sal_uInt8)(pow((double)i/255.0, fInvGamma) * 255.0 + 0.5);
852 
853 		if ( mbGrayScale )
854 			ImplGetGrayPalette( mnPngDepth );
855 	}
856 }
857 
858 // ------------------------------------------------------------------------
859 
860 void PNGReaderImpl::ImplGetBackground()
861 {
862 	switch ( mnColorType )
863 	{
864 		case 3 :
865 		{
866 			if ( mnChunkLen == 1 )
867 			{
868 				sal_uInt16 nCol = *maDataIter++;
869 				if ( nCol < mpAcc->GetPaletteEntryCount() )
870 				{
871 					mpAcc->Erase( mpAcc->GetPaletteColor( (sal_uInt8)nCol ) );
872 					break;
873 				}
874 			}
875 		}
876 		break;
877 
878 		case 0 :
879 		case 4 :
880 		{
881 			if ( mnChunkLen == 2 )
882 			{
883                 // the color type 0 and 4 is always greyscale,
884                 // so the return value can be used as index
885 				sal_uInt8 nIndex = ImplScaleColor();
886 				mpAcc->Erase( mpAcc->GetPaletteColor( nIndex ) );
887 			}
888 		}
889 		break;
890 
891 		case 2 :
892 		case 6 :
893 		{
894 			if ( mnChunkLen == 6 )
895 			{
896 				sal_uInt8 nRed = ImplScaleColor();
897 				sal_uInt8 nGreen = ImplScaleColor();
898 				sal_uInt8 nBlue = ImplScaleColor();
899 				mpAcc->Erase( Color( nRed, nGreen, nBlue ) );
900 			}
901 		}
902 		break;
903 	}
904 }
905 
906 // ------------------------------------------------------------------------
907 
908 // for color type 0 and 4 (greyscale) the return value is always index to the color
909 //                2 and 6 (RGB)       the return value is always the 8 bit color component
910 sal_uInt8 PNGReaderImpl::ImplScaleColor()
911 {
912     sal_uInt32 nMask = ( ( 1 << mnPngDepth ) - 1 );
913 	sal_uInt16 nCol = ( *maDataIter++ << 8 );
914 
915 	nCol += *maDataIter++ & (sal_uInt16)nMask;
916 
917 	if ( mnPngDepth > 8 )	// convert 16bit graphics to 8
918 		nCol >>= 8;
919 
920 	return (sal_uInt8) nCol;
921 }
922 
923 // ------------------------------------------------------------------------
924 // ImplReadIDAT reads as much image data as needed
925 
926 void PNGReaderImpl::ImplReadIDAT()
927 {
928 	if( mnChunkLen > 0 )
929 	{
930 		if ( mbzCodecInUse == sal_False )
931 		{
932 			mbzCodecInUse = sal_True;
933 			mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT );
934 		}
935 		mpZCodec->SetBreak( mnChunkLen );
936 		SvMemoryStream aIStrm( &(*maDataIter), mnChunkLen, STREAM_READ );
937 
938 		while ( ( mpZCodec->GetBreak() ) )
939 		{
940             // get bytes needed to fill the current scanline
941             sal_Int32 nToRead = mnScansize - (mpScanCurrent - mpInflateInBuf);
942             sal_Int32 nRead = mpZCodec->ReadAsynchron( aIStrm, mpScanCurrent, nToRead );
943             if ( nRead < 0 )
944 			{
945 				mbStatus = sal_False;
946 				break;
947 			}
948 			if ( nRead < nToRead )
949 			{
950 				mpScanCurrent += nRead; // more ZStream data in the next IDAT chunk
951 				break;
952 			}
953 			else  // this scanline is Finished
954 			{
955 				mpScanCurrent = mpInflateInBuf;
956                 ImplApplyFilter();
957 
958                 ImplDrawScanline( mnXStart, mnXAdd );
959                 mnYpos += mnYAdd;
960 			}
961 
962 			if ( mnYpos >= (sal_uInt32)maOrigSize.Height() )
963 			{
964                 if( (mnPass < 7) && mnInterlaceType )
965                     if( ImplPreparePass() )
966                         continue;
967                 mbIDAT = true;
968                 break;
969 			}
970 		}
971 	}
972 
973 	if( mbIDAT )
974 	{
975 		mpZCodec->EndCompression();
976 		mbzCodecInUse = sal_False;
977 	}
978 }
979 
980 // ---------------------------------------------------------------------------------------------------
981 
982 bool PNGReaderImpl::ImplPreparePass()
983 {
984     struct InterlaceParams{ int mnXStart, mnYStart, mnXAdd, mnYAdd; };
985     static const InterlaceParams aInterlaceParams[8] =
986     {
987         // non-interlaced
988         { 0, 0, 1, 1 },
989         // Adam7-interlaced
990         { 0, 0, 8, 8 },    // pass 1
991         { 4, 0, 8, 8 },    // pass 2
992         { 0, 4, 4, 8 },    // pass 3
993         { 2, 0, 4, 4 },    // pass 4
994         { 0, 2, 2, 4 },    // pass 5
995         { 1, 0, 2, 2 },    // pass 6
996         { 0, 1, 1, 2 }     // pass 7
997     };
998 
999     const InterlaceParams* pParam = &aInterlaceParams[ 0 ];
1000     if( mnInterlaceType )
1001     {
1002         while( ++mnPass <= 7 )
1003         {
1004             pParam = &aInterlaceParams[ mnPass ];
1005 
1006             // skip this pass if the original image is too small for it
1007             if( (pParam->mnXStart < maOrigSize.Width())
1008             &&  (pParam->mnYStart < maOrigSize.Height()) )
1009                 break;
1010         }
1011         if( mnPass > 7 )
1012             return false;
1013 
1014         // skip the last passes if possible (for scaled down target images)
1015         if( mnPreviewMask & (pParam->mnXStart | pParam->mnYStart) )
1016             return false;
1017     }
1018 
1019     mnYpos      = pParam->mnYStart;
1020     mnXStart    = pParam->mnXStart;
1021     mnXAdd      = pParam->mnXAdd;
1022     mnYAdd      = pParam->mnYAdd;
1023 
1024     // in Interlace mode the size of scanline is not constant
1025     // so first we calculate the number of entrys
1026     long nScanWidth = (maOrigSize.Width() - mnXStart + mnXAdd - 1) / mnXAdd;
1027     mnScansize = nScanWidth;
1028 
1029     if( mbRGBTriple )
1030         mnScansize = 3 * nScanWidth;
1031 
1032     if( mbAlphaChannel )
1033         mnScansize += nScanWidth;
1034 
1035     // convert to width in bytes
1036     mnScansize = ( mnScansize*mnPngDepth + 7 ) >> 3;
1037 
1038     ++mnScansize; // scan size also needs room for the filtertype byte
1039     rtl_zeroMemory( mpScanPrior, mnScansize );
1040 
1041     return true;
1042 }
1043 
1044 // ----------------------------------------------------------------------------
1045 // ImplApplyFilter writes the complete Scanline (nY)
1046 // in interlace mode the parameter nXStart and nXAdd are non-zero
1047 
1048 void PNGReaderImpl::ImplApplyFilter()
1049 {
1050 	OSL_ASSERT( mnScansize >= mnBPP + 1 );
1051     const sal_uInt8* const pScanEnd = mpInflateInBuf + mnScansize;
1052 
1053     sal_uInt8 nFilterType = *mpInflateInBuf; // the filter type may change each scanline
1054     switch ( nFilterType )
1055     {
1056         default: // unknown Scanline Filter Type
1057         case 0: // Filter Type "None"
1058             // we let the pixels pass and display the data unfiltered
1059             break;
1060 
1061         case 1: // Scanline Filter Type "Sub"
1062         {
1063             sal_uInt8* p1 = mpInflateInBuf + 1;
1064             const sal_uInt8* p2 = p1;
1065             p1 += mnBPP;
1066 
1067             // use left pixels
1068             do
1069                 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1070             while( ++p1 < pScanEnd );
1071         }
1072         break;
1073 
1074         case 2: // Scanline Filter Type "Up"
1075         {
1076             sal_uInt8* p1 = mpInflateInBuf + 1;
1077             const sal_uInt8* p2 = mpScanPrior + 1;
1078 
1079             // use pixels from prior line
1080 			while( p1 < pScanEnd )
1081 			{
1082                 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1083 				++p1;
1084 			}
1085         }
1086         break;
1087 
1088         case 3: // Scanline Filter Type "Average"
1089         {
1090             sal_uInt8* p1 = mpInflateInBuf + 1;
1091             const sal_uInt8* p2 = mpScanPrior + 1;
1092             const sal_uInt8* p3 = p1;
1093 
1094             // use one pixel from prior line
1095             for( int n = mnBPP; --n >= 0; ++p1, ++p2)
1096                 *p1 = static_cast<sal_uInt8>( *p1 + (*p2 >> 1) );
1097 
1098             // predict by averaging the left and prior line pixels
1099 			while( p1 < pScanEnd )
1100 			{
1101                 *p1 = static_cast<sal_uInt8>( *p1 + ((*(p2++) + *(p3++)) >> 1) );
1102 				++p1;
1103 			}
1104         }
1105         break;
1106 
1107         case 4: // Scanline Filter Type "PaethPredictor"
1108         {
1109             sal_uInt8* p1 = mpInflateInBuf + 1;
1110             const sal_uInt8* p2 = mpScanPrior + 1;
1111             const sal_uInt8* p3 = p1;
1112             const sal_uInt8* p4 = p2;
1113 
1114             // use one pixel from prior line
1115             for( int n = mnBPP; --n >= 0; ++p1)
1116                 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1117 
1118             // predict by using the left and the prior line pixels
1119             while( p1 < pScanEnd )
1120             {
1121                 int na = *(p2++);
1122                 int nb = *(p3++);
1123                 int nc = *(p4++);
1124 
1125                 int npa = nb - (int)nc;
1126                 int npb = na - (int)nc;
1127                 int npc = npa + npb;
1128 
1129                 if( npa < 0 )
1130                     npa =-npa;
1131                 if( npb < 0 )
1132                     npb =-npb;
1133                 if( npc < 0 )
1134                     npc =-npc;
1135 
1136                 if( npa > npb )
1137                     na = nb, npa = npb;
1138                 if( npa > npc )
1139                     na = nc;
1140 
1141                 *p1 = static_cast<sal_uInt8>( *p1 + na );
1142 				++p1;
1143 			}
1144         }
1145         break;
1146     }
1147 
1148     rtl_copyMemory( mpScanPrior, mpInflateInBuf, mnScansize );
1149 }
1150 
1151 // ---------------------------------------------------------------------------------------------------
1152 // ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
1153 // In interlace mode the parameter nXStart and nXAdd append to the currently used pass
1154 
1155 void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd )
1156 {
1157     // optimization for downscaling
1158     if( mnYpos & mnPreviewMask )
1159         return;
1160     if( nXStart & mnPreviewMask )
1161         return;
1162 
1163     // convert nY to pixel units in the target image
1164     // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
1165     const sal_uInt32 nY = mnYpos >> mnPreviewShift;
1166 
1167     const sal_uInt8* pTmp = mpInflateInBuf + 1;
1168 	if ( mpAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
1169 	{
1170 		switch ( mpAcc->GetBitCount() )
1171 		{
1172 			case 1 :
1173 			{
1174 				if ( mbTransparent )
1175 				{
1176                     for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1177 					{
1178                         sal_uInt8 nCol;
1179                         nShift = (nShift - 1) & 7;
1180 						if ( nShift == 0 )
1181 							nCol = *(pTmp++);
1182 						else
1183 							nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1184                         nCol &= 1;
1185 
1186 						ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1187 					}
1188 				}
1189 				else
1190 				{   // BMP_FORMAT_1BIT_MSB_PAL
1191 					for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1192 					{
1193                         nShift = (nShift - 1) & 7;
1194 
1195                         sal_uInt8 nCol;
1196 						if ( nShift == 0 )
1197 							nCol = *(pTmp++);
1198 						else
1199 							nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1200                         nCol &= 1;
1201 
1202                         ImplSetPixel( nY, nX, nCol );
1203 					}
1204 				}
1205 			}
1206 			break;
1207 
1208 			case 4 :
1209 			{
1210 				if ( mbTransparent )
1211 				{
1212 					if ( mnPngDepth == 4 )	// check if source has a two bit pixel format
1213 					{
1214 						for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, ++nXIndex )
1215 						{
1216 							if( nXIndex & 1 )
1217 							{
1218 								ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
1219 								pTmp++;
1220 							}
1221 							else
1222 							{
1223 								ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
1224 							}
1225 						}
1226 					}
1227 					else // if ( mnPngDepth == 2 )
1228 					{
1229 						for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1230 						{
1231                             sal_uInt8 nCol;
1232 							switch( nXIndex & 3 )
1233 							{
1234 								case 0 :
1235 									nCol = *pTmp >> 6;
1236 								break;
1237 
1238 								case 1 :
1239 									nCol = ( *pTmp >> 4 ) & 0x03 ;
1240 								break;
1241 
1242 								case 2 :
1243 									nCol = ( *pTmp >> 2 ) & 0x03;
1244 								break;
1245 
1246 								case 3 :
1247 									nCol = ( *pTmp++ ) & 0x03;
1248 								break;
1249 
1250                                 default:    // get rid of nCol uninitialized warning
1251                                     nCol = 0;
1252                                     break;
1253 							}
1254 
1255 							ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1256 						}
1257 					}
1258 				}
1259 				else
1260 				{
1261 					if ( mnPngDepth == 4 )	// maybe the source is a two bitmap graphic
1262 					{   // BMP_FORMAT_4BIT_LSN_PAL
1263 						for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1264 						{
1265 							if( nXIndex & 1 )
1266 								ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
1267 							else
1268 								ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
1269 						}
1270 					}
1271 					else // if ( mnPngDepth == 2 )
1272 					{
1273 						for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1274 						{
1275 							switch( nXIndex & 3 )
1276 							{
1277 								case 0 :
1278 									ImplSetPixel( nY, nX, *pTmp >> 6 );
1279 								break;
1280 
1281 								case 1 :
1282 									ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
1283 								break;
1284 
1285 								case 2 :
1286 									ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
1287 								break;
1288 
1289 								case 3 :
1290 									ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
1291 								break;
1292 							}
1293 						}
1294 					}
1295 				}
1296 			}
1297 			break;
1298 
1299 			case 8 :
1300 			{
1301 				if ( mbAlphaChannel )
1302 				{
1303 					if ( mnPngDepth == 8 )	// maybe the source is a 16 bit grayscale
1304 					{
1305 						for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1306 							ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
1307 					}
1308 					else
1309 					{
1310 						for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1311 							ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
1312 					}
1313 				}
1314 				else if ( mbTransparent )
1315 				{
1316 					if ( mnPngDepth == 8 )	// maybe the source is a 16 bit grayscale
1317 					{
1318 						for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp++ )
1319 							ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1320 					}
1321 					else
1322 					{
1323 						for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1324 							ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1325 					}
1326 				}
1327 				else // neither alpha nor transparency
1328 				{
1329 					if ( mnPngDepth == 8 )	// maybe the source is a 16 bit grayscale
1330 					{
1331                         if( nXAdd == 1 && mnPreviewShift == 0 )  // copy raw line data if possible
1332                         {
1333                             int nLineBytes = maOrigSize.Width();
1334                             mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_8BIT_PAL, nLineBytes );
1335                             pTmp += nLineBytes;
1336                         }
1337                         else
1338                         {
1339                             for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd )
1340                                 ImplSetPixel( nY, nX, *pTmp++ );
1341                         }
1342 					}
1343 					else
1344 					{
1345 						for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1346 							ImplSetPixel( nY, nX, *pTmp );
1347 					}
1348 				}
1349 			}
1350 			break;
1351 
1352 			default :
1353 				mbStatus = sal_False;
1354 			break;
1355 		}
1356 	}
1357 	else // no palette => truecolor
1358 	{
1359 		if( mbAlphaChannel ) // has RGB + alpha
1360 		{   // BMP_FORMAT_32BIT_TC_RGBA
1361 			if ( mnPngDepth == 8 )  // maybe the source has 16 bit per sample
1362 			{
1363                 if ( mpColorTable != mpDefaultColorTable )
1364                 {
1365                     for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1366                        ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1367                                                                mpColorTable[ pTmp[ 1 ] ],
1368                                                                mpColorTable[ pTmp[ 2 ] ] ), pTmp[ 3 ] );
1369                 }
1370                 else
1371                 {
1372 //                  if ( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
1373 //                  {
1374 //                      int nLineBytes = 4 * maOrigSize.Width();
1375 //                      mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_32BIT_TC_RGBA, nLineBytes );
1376 //                      pTmp += nLineBytes;
1377 //                  }
1378 //                  else
1379                     {
1380                         for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1381                             ImplSetAlphaPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ), pTmp[3] );
1382                     }
1383                 }
1384 			}
1385 			else
1386 			{   // BMP_FORMAT_64BIT_TC_RGBA
1387 				for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 8 )
1388 					ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1389 														mpColorTable[ pTmp[ 2 ] ],
1390 														mpColorTable[ pTmp[ 4 ] ] ), pTmp[6] );
1391 			}
1392 		}
1393 		else if( mbTransparent ) // has RGB + transparency
1394 		{   // BMP_FORMAT_24BIT_TC_RGB
1395 			if ( mnPngDepth == 8 )  // maybe the source has 16 bit per sample
1396 			{
1397 				for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1398 				{
1399 					sal_uInt8 nRed = pTmp[ 0 ];
1400 					sal_uInt8 nGreen = pTmp[ 1 ];
1401 					sal_uInt8 nBlue = pTmp[ 2 ];
1402 					sal_Bool bTransparent = ( ( nRed == mnTransRed )
1403 							 			&& ( nGreen == mnTransGreen )
1404 										&& ( nBlue == mnTransBlue ) );
1405 
1406 					ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1407 														mpColorTable[ nGreen ],
1408 														mpColorTable[ nBlue ] ), bTransparent );
1409 				}
1410 			}
1411 			else
1412 			{   // BMP_FORMAT_48BIT_TC_RGB
1413 				for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
1414 				{
1415 					sal_uInt8 nRed = pTmp[ 0 ];
1416 					sal_uInt8 nGreen = pTmp[ 2 ];
1417 					sal_uInt8 nBlue = pTmp[ 4 ];
1418 					sal_Bool bTransparent = ( ( nRed == mnTransRed )
1419 										&& ( nGreen == mnTransGreen )
1420 										&& ( nBlue == mnTransBlue ) );
1421 
1422 					ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1423 														mpColorTable[ nGreen ],
1424 														mpColorTable[ nBlue ] ), bTransparent );
1425 				}
1426 			}
1427 		}
1428 		else  // has RGB but neither alpha nor transparency
1429 		{   // BMP_FORMAT_24BIT_TC_RGB
1430 			if ( mnPngDepth == 8 )   // maybe the source has 16 bit per sample
1431 			{
1432                 if ( mpColorTable != mpDefaultColorTable )
1433                 {
1434                     for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1435                         ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1436                                                             mpColorTable[ pTmp[ 1 ] ],
1437                                                             mpColorTable[ pTmp[ 2 ] ] ) );
1438                 }
1439                 else
1440                 {
1441                     if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
1442                     {
1443                         int nLineBytes = maOrigSize.Width() * 3;
1444                         mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_24BIT_TC_RGB, nLineBytes );
1445                         pTmp += nLineBytes;
1446                     }
1447                     else
1448                     {
1449                         for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1450                             ImplSetPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ) );
1451                     }
1452                 }
1453 			}
1454 			else
1455 			{   // BMP_FORMAT_48BIT_TC_RGB
1456 				for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
1457 					ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1458 														mpColorTable[ pTmp[ 2 ] ],
1459 														mpColorTable[ pTmp[ 4 ] ] ) );
1460 			}
1461 		}
1462 	}
1463 }
1464 
1465 // ------------------------------------------------------------------------
1466 
1467 void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
1468 {
1469     // TODO: get preview mode checks out of inner loop
1470     if( nX & mnPreviewMask )
1471         return;
1472     nX >>= mnPreviewShift;
1473 
1474     mpAcc->SetPixel( nY, nX, rBitmapColor );
1475 }
1476 
1477 // ------------------------------------------------------------------------
1478 
1479 void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, sal_uInt8 nPalIndex )
1480 {
1481     // TODO: get preview mode checks out of inner loop
1482     if( nX & mnPreviewMask )
1483         return;
1484     nX >>= mnPreviewShift;
1485 
1486     mpAcc->SetPixel( nY, nX, nPalIndex );
1487 }
1488 
1489 // ------------------------------------------------------------------------
1490 
1491 void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, sal_Bool bTrans )
1492 {
1493     // TODO: get preview mode checks out of inner loop
1494     if( nX & mnPreviewMask )
1495         return;
1496     nX >>= mnPreviewShift;
1497 
1498     mpAcc->SetPixel( nY, nX, rBitmapColor );
1499 
1500     if ( bTrans )
1501         mpMaskAcc->SetPixel( nY, nX, mcTranspColor );
1502     else
1503         mpMaskAcc->SetPixel( nY, nX, mcOpaqueColor );
1504 }
1505 
1506 // ------------------------------------------------------------------------
1507 
1508 void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1509     sal_uInt8 nPalIndex, sal_uInt8 nAlpha )
1510 {
1511     // TODO: get preview mode checks out of inner loop
1512     if( nX & mnPreviewMask )
1513         return;
1514     nX >>= mnPreviewShift;
1515 
1516     mpAcc->SetPixel( nY, nX, nPalIndex );
1517     mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
1518 }
1519 
1520 // ------------------------------------------------------------------------
1521 
1522 void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1523     const BitmapColor& rBitmapColor, sal_uInt8 nAlpha )
1524 {
1525     // TODO: get preview mode checks out of inner loop
1526     if( nX & mnPreviewMask )
1527         return;
1528     nX >>= mnPreviewShift;
1529 
1530     mpAcc->SetPixel( nY, nX, rBitmapColor );
1531     mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
1532 }
1533 
1534 // ------------------------------------------------------------------------
1535 
1536 sal_uInt32 PNGReaderImpl::ImplReadsal_uInt32()
1537 {
1538 	sal_uInt32 nRet;
1539 	nRet = *maDataIter++;
1540 	nRet <<= 8;
1541 	nRet |= *maDataIter++;
1542 	nRet <<= 8;
1543 	nRet |= *maDataIter++;
1544 	nRet <<= 8;
1545 	nRet |= *maDataIter++;
1546 	return nRet;
1547 }
1548 
1549 // ------------------------------------------------------------------------
1550 
1551 // -------------
1552 // - PNGReader -
1553 // -------------
1554 
1555 PNGReader::PNGReader( SvStream& rIStm ) :
1556 	mpImpl( new ::vcl::PNGReaderImpl( rIStm ) )
1557 {
1558 }
1559 
1560 // ------------------------------------------------------------------------
1561 
1562 PNGReader::~PNGReader()
1563 {
1564 	delete mpImpl;
1565 }
1566 
1567 // ------------------------------------------------------------------------
1568 
1569 BitmapEx PNGReader::Read( const Size& i_rPreviewSizeHint )
1570 {
1571     return mpImpl->GetBitmapEx( i_rPreviewSizeHint );
1572 }
1573 
1574 // ------------------------------------------------------------------------
1575 
1576 const std::vector< vcl::PNGReader::ChunkData >& PNGReader::GetChunks() const
1577 {
1578 	return mpImpl->GetAllChunks();
1579 }
1580 
1581 // ------------------------------------------------------------------------
1582 
1583 void PNGReader::SetIgnoreGammaChunk( sal_Bool b )
1584 {
1585 	mpImpl->SetIgnoreGammaChunk( b );
1586 }
1587 
1588 
1589 } // namespace vcl
1590