Update ooo320-m1
[ooovba.git] / vcl / source / gdi / pngread.cxx
blobfe559f57160bf136037ab9252629ffd6423cbb8e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pngread.cxx,v $
10 * $Revision: 1.28.78.1 $
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_vcl.hxx"
34 #include <vcl/pngread.hxx>
36 #include <cmath>
37 #include <rtl/crc.h>
38 #include <rtl/memory.h>
39 #include <rtl/alloc.h>
40 #include <tools/zcodec.hxx>
41 #include <tools/stream.hxx>
42 #include <vcl/bmpacc.hxx>
43 #include <vcl/svapp.hxx>
44 #include <vcl/alpha.hxx>
45 #include <osl/endian.h>
47 // -----------
48 // - Defines -
49 // -----------
51 #define PNGCHUNK_IHDR 0x49484452
52 #define PNGCHUNK_PLTE 0x504c5445
53 #define PNGCHUNK_IDAT 0x49444154
54 #define PNGCHUNK_IEND 0x49454e44
55 #define PNGCHUNK_bKGD 0x624b4744
56 #define PNGCHUNK_cHRM 0x6348524d
57 #define PNGCHUNK_gAMA 0x67414d41
58 #define PNGCHUNK_hIST 0x68495354
59 #define PNGCHUNK_pHYs 0x70485973
60 #define PNGCHUNK_sBIT 0x73425420
61 #define PNGCHUNK_tIME 0x74494d45
62 #define PNGCHUNK_tEXt 0x74455874
63 #define PNGCHUNK_tRNS 0x74524e53
64 #define PNGCHUNK_zTXt 0x7a545874
65 #define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
67 #define VIEWING_GAMMA 2.35
68 #define DISPLAY_GAMMA 1.0
70 namespace vcl
72 // -----------
73 // - statics -
74 // -----------
76 // ------------------------------------------------------------------------------
78 static const BYTE mpDefaultColorTable[ 256 ] =
79 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
80 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
81 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
82 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
83 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
84 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
85 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
86 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
87 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
88 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
89 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
90 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
91 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
92 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
93 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
94 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
97 // -------------
98 // - PNGReaderImpl -
99 // -------------
101 class PNGReaderImpl
103 private:
104 SvStream& mrPNGStream;
105 sal_uInt16 mnOrigStreamMode;
107 std::vector< vcl::PNGReader::ChunkData > maChunkSeq;
108 std::vector< vcl::PNGReader::ChunkData >::iterator maChunkIter;
109 std::vector< sal_uInt8 >::iterator maDataIter;
111 Bitmap* mpBmp;
112 BitmapWriteAccess* mpAcc;
113 Bitmap* mpMaskBmp;
114 AlphaMask* mpAlphaMask;
115 BitmapWriteAccess* mpMaskAcc;
116 ZCodec* mpZCodec;
117 BYTE* mpInflateInBuf; // as big as the size of a scanline + alphachannel + 1
118 BYTE* mpScanPrior; // pointer to the latest scanline
119 BYTE* mpTransTab; // for transparency in images with palette colortype
120 BYTE* mpScanCurrent; // pointer into the current scanline
121 BYTE* mpColorTable; //
122 sal_Size mnStreamSize; // estimate of PNG file size
123 sal_uInt32 mnChunkType; // Type of current PNG chunk
124 sal_Int32 mnChunkLen; // Length of current PNG chunk
125 Size maOrigSize; // pixel size of the full image
126 Size maTargetSize; // pixel size of the result image
127 Size maPhysSize; // prefered size in MAP_100TH_MM units
128 sal_uInt32 mnBPP; // number of bytes per pixel
129 sal_uInt32 mnScansize; // max size of scanline
130 sal_uInt32 mnYpos; // latest y position in full image
131 int mnPass; // if interlaced the latest pass ( 1..7 ) else 7
132 sal_uInt32 mnXStart; // the starting X for the current pass
133 sal_uInt32 mnXAdd; // the increment for input images X coords for the current pass
134 sal_uInt32 mnYAdd; // the increment for input images Y coords for the current pass
135 int mnPreviewShift; // shift to convert orig image coords into preview image coords
136 int mnPreviewMask; // == ((1 << mnPreviewShift) - 1)
137 USHORT mnIStmOldMode;
138 USHORT mnTargetDepth; // pixel depth of target bitmap
139 BYTE mnTransRed;
140 BYTE mnTransGreen;
141 BYTE mnTransBlue;
142 BYTE mnPngDepth; // pixel depth of PNG data
143 BYTE mnColorType;
144 BYTE mnCompressionType;
145 BYTE mnFilterType;
146 BYTE mnInterlaceType;
147 BitmapColor mcTranspColor; // transparency mask's transparency "color"
148 BitmapColor mcOpaqueColor; // transparency mask's opaque "color"
149 BOOL mbTransparent; // graphic includes an tRNS Chunk or an alpha Channel
150 BOOL mbAlphaChannel; // is true for ColorType 4 and 6
151 BOOL mbRGBTriple;
152 BOOL mbPalette; // FALSE if we need a Palette
153 BOOL mbGrayScale;
154 BOOL mbzCodecInUse;
155 BOOL mbStatus;
156 BOOL mbIDAT; // TRUE if finished with enough IDAT chunks
157 BOOL mbGamma; // TRUE if Gamma Correction available
158 BOOL mbpHYs; // TRUE if pysical size of pixel available
159 sal_Bool mbIgnoreGammaChunk;
161 bool ReadNextChunk();
162 void ReadRemainingChunks();
163 void SkipRemainingChunks();
165 void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor & );
166 void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, BYTE nPalIndex );
167 void ImplSetTranspPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, BOOL bTrans );
168 void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, BYTE nPalIndex, BYTE nAlpha );
169 void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor&, BYTE nAlpha );
170 void ImplReadIDAT();
171 bool ImplPreparePass();
172 void ImplApplyFilter();
173 void ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd );
174 BOOL ImplReadTransparent();
175 void ImplGetGamma();
176 void ImplGetBackground();
177 BYTE ImplScaleColor();
178 BOOL ImplReadHeader( const Size& rPreviewSizeHint );
179 BOOL ImplReadPalette();
180 void ImplGetGrayPalette( sal_uInt16 );
181 sal_uInt32 ImplReadsal_uInt32();
183 public:
185 PNGReaderImpl( SvStream& );
186 ~PNGReaderImpl();
188 BitmapEx GetBitmapEx( const Size& rPreviewSizeHint );
189 const std::vector< PNGReader::ChunkData >& GetAllChunks();
190 void SetIgnoreGammaChunk( sal_Bool bIgnore ){ mbIgnoreGammaChunk = bIgnore; };
193 // ------------------------------------------------------------------------------
195 PNGReaderImpl::PNGReaderImpl( SvStream& rPNGStream )
196 : mrPNGStream( rPNGStream ),
197 mpBmp ( NULL ),
198 mpAcc ( NULL ),
199 mpMaskBmp ( NULL ),
200 mpAlphaMask ( NULL ),
201 mpMaskAcc ( NULL ),
202 mpZCodec ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
203 mpInflateInBuf ( NULL ),
204 mpScanPrior ( NULL ),
205 mpTransTab ( NULL ),
206 mpColorTable ( (sal_uInt8*) mpDefaultColorTable ),
207 mbzCodecInUse ( sal_False ),
208 mbStatus( TRUE),
209 mbIDAT( FALSE ),
210 mbGamma ( sal_False ),
211 mbpHYs ( sal_False ),
212 mbIgnoreGammaChunk ( sal_False )
214 // prepare the PNG data stream
215 mnOrigStreamMode = mrPNGStream.GetNumberFormatInt();
216 mrPNGStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
218 // prepare the chunk reader
219 maChunkSeq.reserve( 16 );
220 maChunkIter = maChunkSeq.begin();
222 // estimate PNG file size (to allow sanity checks)
223 const sal_Size nStreamPos = mrPNGStream.Tell();
224 mrPNGStream.Seek( STREAM_SEEK_TO_END );
225 mnStreamSize = mrPNGStream.Tell();
226 mrPNGStream.Seek( nStreamPos );
228 // check the PNG header magic
229 sal_uInt32 nDummy = 0;
230 mrPNGStream >> nDummy;
231 mbStatus = (nDummy == 0x89504e47);
232 mrPNGStream >> nDummy;
233 mbStatus &= (nDummy == 0x0d0a1a0a);
235 mnPreviewShift = 0;
236 mnPreviewMask = (1 << mnPreviewShift) - 1;
239 // ------------------------------------------------------------------------
241 PNGReaderImpl::~PNGReaderImpl()
243 mrPNGStream.SetNumberFormatInt( mnOrigStreamMode );
245 if ( mbzCodecInUse )
246 mpZCodec->EndCompression();
248 if( mpColorTable != mpDefaultColorTable )
249 delete[] mpColorTable;
251 delete mpBmp;
252 delete mpAlphaMask;
253 delete mpMaskBmp;
254 delete[] mpTransTab;
255 delete[] mpInflateInBuf;
256 delete[] mpScanPrior;
257 delete mpZCodec;
260 // ------------------------------------------------------------------------
262 bool PNGReaderImpl::ReadNextChunk()
264 if( maChunkIter == maChunkSeq.end() )
266 // get the next chunk from the stream
268 // unless we are at the end of the PNG stream
269 if( mrPNGStream.IsEof() || (mrPNGStream.GetError() != ERRCODE_NONE) )
270 return false;
271 if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
272 return false;
274 PNGReader::ChunkData aDummyChunk;
275 maChunkIter = maChunkSeq.insert( maChunkSeq.end(), aDummyChunk );
276 PNGReader::ChunkData& rChunkData = *maChunkIter;
278 // read the chunk header
279 mrPNGStream >> mnChunkLen >> mnChunkType;
280 rChunkData.nType = mnChunkType;
282 // #128377#/#149343# sanity check for chunk length
283 if( mnChunkLen < 0 )
284 return false;
285 const sal_Size nStreamPos = mrPNGStream.Tell();
286 if( nStreamPos + mnChunkLen >= mnStreamSize )
287 return false;
289 // calculate chunktype CRC (swap it back to original byte order)
290 sal_uInt32 nChunkType = mnChunkType;;
291 #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
292 nChunkType = SWAPLONG( nChunkType );
293 #endif
294 sal_uInt32 nCRC32 = rtl_crc32( 0, &nChunkType, 4 );
296 // read the chunk data and check the CRC
297 if( mnChunkLen && !mrPNGStream.IsEof() )
299 rChunkData.aData.resize( mnChunkLen );
301 sal_Int32 nBytesRead = 0;
302 do {
303 sal_uInt8* pPtr = &rChunkData.aData[ nBytesRead ];
304 nBytesRead += mrPNGStream.Read( pPtr, mnChunkLen - nBytesRead );
305 } while ( ( nBytesRead < mnChunkLen ) && ( mrPNGStream.GetError() == ERRCODE_NONE ) );
307 nCRC32 = rtl_crc32( nCRC32, &rChunkData.aData[ 0 ], mnChunkLen );
308 maDataIter = rChunkData.aData.begin();
310 sal_uInt32 nCheck;
311 mrPNGStream >> nCheck;
312 if( nCRC32 != nCheck )
313 return false;
315 else
317 // the next chunk was already read
318 mnChunkType = (*maChunkIter).nType;
319 mnChunkLen = (*maChunkIter).aData.size();
320 maDataIter = (*maChunkIter).aData.begin();
323 ++maChunkIter;
324 if( mnChunkType == PNGCHUNK_IEND )
325 return false;
326 return true;
329 // ------------------------------------------------------------------------
331 // read the remaining chunks from mrPNGStream
332 void PNGReaderImpl::ReadRemainingChunks()
334 while( ReadNextChunk() ) ;
337 // ------------------------------------------------------------------------
339 // move position of mrPNGStream to the end of the file
340 void PNGReaderImpl::SkipRemainingChunks()
342 // nothing to skip if the last chunk was read
343 if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
344 return;
346 // read from the stream until the IEND chunk is found
347 const sal_Size nStreamPos = mrPNGStream.Tell();
348 while( !mrPNGStream.IsEof() && (mrPNGStream.GetError() == ERRCODE_NONE) )
350 mrPNGStream >> mnChunkLen >> mnChunkType;
351 if( mnChunkLen < 0 )
352 break;
353 if( nStreamPos + mnChunkLen >= mnStreamSize )
354 break;
355 mrPNGStream.SeekRel( mnChunkLen + 4 ); // skip data + CRC
356 if( mnChunkType == PNGCHUNK_IEND )
357 break;
361 // ------------------------------------------------------------------------
363 const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks()
365 ReadRemainingChunks();
366 return maChunkSeq;
369 // ------------------------------------------------------------------------
371 BitmapEx PNGReaderImpl::GetBitmapEx( const Size& rPreviewSizeHint )
373 // reset to the first chunk
374 maChunkIter = maChunkSeq.begin();
376 // parse the chunks
377 while( mbStatus && !mbIDAT && ReadNextChunk() )
379 switch( mnChunkType )
381 case PNGCHUNK_IHDR :
383 mbStatus = ImplReadHeader( rPreviewSizeHint );
385 break;
387 case PNGCHUNK_gAMA : // the gamma chunk must precede
388 { // the 'IDAT' and also the 'PLTE'(if available )
389 if ( !mbIgnoreGammaChunk && ( mbIDAT == FALSE ) )
390 ImplGetGamma();
392 break;
394 case PNGCHUNK_PLTE :
396 if ( !mbPalette )
397 mbStatus = ImplReadPalette();
399 break;
401 case PNGCHUNK_tRNS :
403 if ( !mbIDAT ) // the tRNS chunk must precede the IDAT
404 mbStatus = ImplReadTransparent();
406 break;
408 case PNGCHUNK_bKGD : // the background chunk must appear
410 if ( ( mbIDAT == FALSE ) && mbPalette ) // before the 'IDAT' and after the
411 ImplGetBackground(); // PLTE(if available ) chunk.
413 break;
415 case PNGCHUNK_IDAT :
417 if ( !mbIDAT ) // the gfx is finished, but there may be left a zlibCRC of about 4Bytes
418 ImplReadIDAT();
420 break;
422 case PNGCHUNK_pHYs :
424 if ( !mbIDAT && mnChunkLen == 9 )
426 sal_uInt32 nXPixelPerMeter = ImplReadsal_uInt32();
427 sal_uInt32 nYPixelPerMeter = ImplReadsal_uInt32();
429 sal_uInt8 nUnitSpecifier = *maDataIter++;
430 if( (nUnitSpecifier == 1) && nXPixelPerMeter && nXPixelPerMeter )
432 mbpHYs = sal_True;
434 // convert into MAP_100TH_MM
435 maPhysSize.Width() = (sal_Int32)( (100000.0 * maOrigSize.Width()) / nXPixelPerMeter );
436 maPhysSize.Height() = (sal_Int32)( (100000.0 * maOrigSize.Height()) / nYPixelPerMeter );
440 break;
442 case PNGCHUNK_IEND:
443 mbStatus = mbIDAT; // there is a problem if the image is not complete yet
444 break;
448 // release write access of the bitmaps
449 if ( mpAcc )
450 mpBmp->ReleaseAccess( mpAcc ), mpAcc = NULL;
452 if ( mpMaskAcc )
454 if ( mpAlphaMask )
455 mpAlphaMask->ReleaseAccess( mpMaskAcc );
456 else if ( mpMaskBmp )
457 mpMaskBmp->ReleaseAccess( mpMaskAcc );
459 mpMaskAcc = NULL;
462 // return the resulting BitmapEx
463 BitmapEx aRet;
465 if( !mbStatus || !mbIDAT )
466 aRet.Clear();
467 else
469 if ( mpAlphaMask )
470 aRet = BitmapEx( *mpBmp, *mpAlphaMask );
471 else if ( mpMaskBmp )
472 aRet = BitmapEx( *mpBmp, *mpMaskBmp );
473 else
474 aRet = *mpBmp;
476 if ( mbpHYs && maPhysSize.Width() && maPhysSize.Height() )
478 aRet.SetPrefMapMode( MAP_100TH_MM );
479 aRet.SetPrefSize( maPhysSize );
482 #if 0
483 // TODO: make sure nobody depends on the stream being after the IEND chunks
484 // => let them do ReadChunks before
485 ReadRemainingChunks();
486 #endif
489 return aRet;
492 // ------------------------------------------------------------------------
494 BOOL PNGReaderImpl::ImplReadHeader( const Size& rPreviewSizeHint )
496 if( mnChunkLen < 13 )
497 return FALSE;
499 maOrigSize.Width() = ImplReadsal_uInt32();
500 maOrigSize.Height() = ImplReadsal_uInt32();
502 if ( !maOrigSize.Width() || !maOrigSize.Height() )
503 return FALSE;
505 mnPngDepth = *(maDataIter++);
506 mnColorType = *(maDataIter++);
508 mnCompressionType = *(maDataIter++);
509 if( mnCompressionType != 0 ) // unknown compression type
510 return FALSE;
512 mnFilterType = *(maDataIter++);
513 if( mnFilterType != 0 ) // unknown filter type
514 return FALSE;
516 mnInterlaceType = *(maDataIter++);
517 switch ( mnInterlaceType ) // filter type valid ?
519 case 0 : // progressive image
520 mnPass = 7;
521 break;
522 case 1 : // Adam7-interlaced image
523 mnPass = 0;
524 break;
525 default:
526 return FALSE;
529 mbPalette = TRUE;
530 mbIDAT = mbAlphaChannel = mbTransparent = FALSE;
531 mbGrayScale = mbRGBTriple = FALSE;
532 mnTargetDepth = mnPngDepth;
533 mnScansize = ( ( maOrigSize.Width() * mnPngDepth ) + 7 ) >> 3;
535 // valid color types are 0,2,3,4 & 6
536 switch ( mnColorType )
538 case 0 : // each pixel is a grayscale
540 switch ( mnPngDepth )
542 case 2 : // 2bit target not available -> use four bits
543 mnTargetDepth = 4; // we have to expand the bitmap
544 mbGrayScale = TRUE;
545 break;
546 case 16 :
547 mnTargetDepth = 8; // we have to reduce the bitmap
548 // fall through
549 case 1 :
550 case 4 :
551 case 8 :
552 mbGrayScale = TRUE;
553 break;
554 default :
555 return FALSE;
558 break;
560 case 2 : // each pixel is an RGB triple
562 mbRGBTriple = TRUE;
563 mnScansize *= 3;
564 switch ( mnPngDepth )
566 case 16 : // we have to reduce the bitmap
567 case 8 :
568 mnTargetDepth = 24;
569 break;
570 default :
571 return FALSE;
574 break;
576 case 3 : // each pixel is a palette index
578 switch ( mnPngDepth )
580 case 2 :
581 mnTargetDepth = 4; // we have to expand the bitmap
582 // fall through
583 case 1 :
584 case 4 :
585 case 8 :
586 mbPalette = FALSE;
587 break;
588 default :
589 return FALSE;
592 break;
594 case 4 : // each pixel is a grayscale sample followed by an alpha sample
596 mnScansize *= 2;
597 mbAlphaChannel = TRUE;
598 switch ( mnPngDepth )
600 case 16 :
601 mnTargetDepth = 8; // we have to reduce the bitmap
602 case 8 :
603 mbGrayScale = TRUE;
604 break;
605 default :
606 return FALSE;
609 break;
611 case 6 : // each pixel is an RGB triple followed by an alpha sample
613 mbRGBTriple = TRUE;
614 mnScansize *= 4;
615 mbAlphaChannel = TRUE;
616 switch (mnPngDepth )
618 case 16 : // we have to reduce the bitmap
619 case 8 :
620 mnTargetDepth = 24;
621 break;
622 default :
623 return FALSE;
626 break;
628 default :
629 return FALSE;
632 mnBPP = mnScansize / maOrigSize.Width();
633 if ( !mnBPP )
634 mnBPP = 1;
636 mnScansize++; // each scanline includes one filterbyte
638 // TODO: switch between both scanlines instead of copying
639 mpInflateInBuf = new BYTE[ mnScansize ];
640 mpScanCurrent = mpInflateInBuf;
641 mpScanPrior = new BYTE[ mnScansize ];
643 // calculate target size from original size and the preview hint
644 if( rPreviewSizeHint.Width() || rPreviewSizeHint.Height() )
646 Size aPreviewSize( rPreviewSizeHint.Width(), rPreviewSizeHint.Height() );
647 maTargetSize = maOrigSize;
649 if( aPreviewSize.Width() == 0 ) {
650 aPreviewSize.setWidth( ( maOrigSize.Width()*aPreviewSize.Height() )/maOrigSize.Height() );
651 if( aPreviewSize.Width() <= 0 )
652 aPreviewSize.setWidth( 1 );
653 } else if( aPreviewSize.Height() == 0 ) {
654 aPreviewSize.setHeight( ( maOrigSize.Height()*aPreviewSize.Width() )/maOrigSize.Width() );
655 if( aPreviewSize.Height() <= 0 )
656 aPreviewSize.setHeight( 1 );
659 if( aPreviewSize.Width() < maOrigSize.Width() && aPreviewSize.Height() < maOrigSize.Height() ) {
660 OSL_TRACE("preview size %dx%d", aPreviewSize.Width(), aPreviewSize.Height() );
662 for( int i = 1; i < 5; ++i )
664 if( (maTargetSize.Width() >> i) < aPreviewSize.Width() )
665 break;
666 if( (maTargetSize.Height() >> i) < aPreviewSize.Height() )
667 break;
668 mnPreviewShift = i;
670 mnPreviewMask = (1 << mnPreviewShift) - 1;
674 maTargetSize.Width() = (maOrigSize.Width() + mnPreviewMask) >> mnPreviewShift;
675 maTargetSize.Height() = (maOrigSize.Height() + mnPreviewMask) >> mnPreviewShift;
677 mpBmp = new Bitmap( maTargetSize, mnTargetDepth );
678 mpAcc = mpBmp->AcquireWriteAccess();
679 if( !mpAcc )
680 return FALSE;
682 mpBmp->SetSourceSizePixel( maOrigSize );
684 if ( mbAlphaChannel )
686 mpAlphaMask = new AlphaMask( maTargetSize );
687 mpAlphaMask->Erase( 128 );
688 mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
689 if( !mpMaskAcc )
690 return FALSE;
693 if ( mbGrayScale )
694 ImplGetGrayPalette( mnPngDepth );
696 ImplPreparePass();
698 return TRUE;
701 // ------------------------------------------------------------------------
703 void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
705 if( nBitDepth > 8 )
706 nBitDepth = 8;
708 sal_uInt16 nPaletteEntryCount = 1 << nBitDepth;
709 sal_uInt32 nAdd = 256 / (nPaletteEntryCount - 1);
711 // no bitdepth==2 available
712 // but bitdepth==4 with two unused bits is close enough
713 if( nBitDepth == 2 )
714 nPaletteEntryCount = 16;
716 mpAcc->SetPaletteEntryCount( nPaletteEntryCount );
717 for ( sal_uInt32 i = 0, nStart = 0; nStart < 256; i++, nStart += nAdd )
718 mpAcc->SetPaletteColor( (USHORT)i, BitmapColor( mpColorTable[ nStart ],
719 mpColorTable[ nStart ], mpColorTable[ nStart ] ) );
722 // ------------------------------------------------------------------------
724 BOOL PNGReaderImpl::ImplReadPalette()
726 sal_uInt16 nCount = static_cast<sal_uInt16>( mnChunkLen / 3 );
728 if ( ( ( mnChunkLen % 3 ) == 0 ) && ( ( 0 < nCount ) && ( nCount <= 256 ) ) && mpAcc )
730 mbPalette = TRUE;
731 mpAcc->SetPaletteEntryCount( (USHORT) nCount );
733 for ( sal_uInt16 i = 0; i < nCount; i++ )
735 BYTE nRed = mpColorTable[ *maDataIter++ ];
736 BYTE nGreen = mpColorTable[ *maDataIter++ ];
737 BYTE nBlue = mpColorTable[ *maDataIter++ ];
738 mpAcc->SetPaletteColor( i, Color( nRed, nGreen, nBlue ) );
741 else
742 mbStatus = FALSE;
744 return mbStatus;
747 // ------------------------------------------------------------------------
749 BOOL PNGReaderImpl::ImplReadTransparent()
751 bool bNeedAlpha = false;
753 if ( mpTransTab == NULL )
755 switch ( mnColorType )
757 case 0 :
759 if ( mnChunkLen == 2 )
761 mpTransTab = new sal_uInt8[ 256 ];
762 rtl_fillMemory( mpTransTab, 256, 0xff );
763 // color type 0 and 4 is always greyscale,
764 // so the return value can be used as index
765 sal_uInt8 nIndex = ImplScaleColor();
766 mpTransTab[ nIndex ] = 0;
767 mbTransparent = true;
770 break;
772 case 2 :
774 if ( mnChunkLen == 6 )
776 mnTransRed = ImplScaleColor();
777 mnTransGreen = ImplScaleColor();
778 mnTransBlue = ImplScaleColor();
779 mbTransparent = true;
782 break;
784 case 3 :
786 if ( mnChunkLen <= 256 )
788 mpTransTab = new BYTE [ 256 ];
789 rtl_fillMemory( mpTransTab, 256, 0xff );
790 rtl_copyMemory( mpTransTab, &(*maDataIter), mnChunkLen );
791 maDataIter += mnChunkLen;
792 mbTransparent = true;
793 // need alpha transparency if not on/off masking
794 for( int i = 0; i < mnChunkLen; ++i )
795 bNeedAlpha |= (mpTransTab[i]!=0x00) && (mpTransTab[i]!=0xFF);
798 break;
802 if( mbTransparent && !mbAlphaChannel && !mpMaskBmp )
804 if( bNeedAlpha)
806 mpAlphaMask = new AlphaMask( maTargetSize );
807 mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
809 else
811 mpMaskBmp = new Bitmap( maTargetSize, 1 );
812 mpMaskAcc = mpMaskBmp->AcquireWriteAccess();
814 mbTransparent = (mpMaskAcc != NULL);
815 if( !mbTransparent )
816 return FALSE;
817 mcOpaqueColor = BitmapColor( 0x00 );
818 mcTranspColor = BitmapColor( 0xFF );
819 mpMaskAcc->Erase( 0x00 );
822 return TRUE;
825 // ------------------------------------------------------------------------
827 void PNGReaderImpl::ImplGetGamma()
829 if( mnChunkLen < 4 )
830 return;
832 sal_uInt32 nGammaValue = ImplReadsal_uInt32();
833 double fGamma = ( ( VIEWING_GAMMA / DISPLAY_GAMMA ) * ( (double)nGammaValue / 100000 ) );
834 double fInvGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
836 if ( fInvGamma != 1.0 )
838 mbGamma = TRUE;
840 if ( mpColorTable == mpDefaultColorTable )
841 mpColorTable = new sal_uInt8[ 256 ];
843 for ( sal_Int32 i = 0; i < 256; i++ )
844 mpColorTable[ i ] = (sal_uInt8)(pow((double)i/255.0, fInvGamma) * 255.0 + 0.5);
846 if ( mbGrayScale )
847 ImplGetGrayPalette( mnPngDepth );
851 // ------------------------------------------------------------------------
853 void PNGReaderImpl::ImplGetBackground()
855 switch ( mnColorType )
857 case 3 :
859 if ( mnChunkLen == 1 )
861 UINT16 nCol = *maDataIter++;
862 if ( nCol < mpAcc->GetPaletteEntryCount() )
864 mpAcc->Erase( mpAcc->GetPaletteColor( (BYTE)nCol ) );
865 break;
869 break;
871 case 0 :
872 case 4 :
874 if ( mnChunkLen == 2 )
876 // the color type 0 and 4 is always greyscale,
877 // so the return value can be used as index
878 sal_uInt8 nIndex = ImplScaleColor();
879 mpAcc->Erase( mpAcc->GetPaletteColor( nIndex ) );
882 break;
884 case 2 :
885 case 6 :
887 if ( mnChunkLen == 6 )
889 sal_uInt8 nRed = ImplScaleColor();
890 sal_uInt8 nGreen = ImplScaleColor();
891 sal_uInt8 nBlue = ImplScaleColor();
892 mpAcc->Erase( Color( nRed, nGreen, nBlue ) );
895 break;
899 // ------------------------------------------------------------------------
901 // for color type 0 and 4 (greyscale) the return value is always index to the color
902 // 2 and 6 (RGB) the return value is always the 8 bit color component
903 sal_uInt8 PNGReaderImpl::ImplScaleColor()
905 sal_uInt32 nMask = ( ( 1 << mnPngDepth ) - 1 );
906 sal_uInt16 nCol = ( *maDataIter++ << 8 );
908 nCol += *maDataIter++ & (sal_uInt16)nMask;
910 if ( mnPngDepth > 8 ) // convert 16bit graphics to 8
911 nCol >>= 8;
913 return (sal_uInt8) nCol;
916 // ------------------------------------------------------------------------
917 // ImplReadIDAT reads as much image data as needed
919 void PNGReaderImpl::ImplReadIDAT()
921 if( mnChunkLen > 0 )
923 if ( mbzCodecInUse == FALSE )
925 mbzCodecInUse = TRUE;
926 mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT );
928 mpZCodec->SetBreak( mnChunkLen );
929 SvMemoryStream aIStrm( &(*maDataIter), mnChunkLen, STREAM_READ );
931 while ( ( mpZCodec->GetBreak() ) )
933 // get bytes needed to fill the current scanline
934 sal_Int32 nToRead = mnScansize - (mpScanCurrent - mpInflateInBuf);
935 sal_Int32 nRead = mpZCodec->ReadAsynchron( aIStrm, mpScanCurrent, nToRead );
936 if ( nRead < 0 )
938 mbStatus = FALSE;
939 break;
941 if ( nRead < nToRead )
943 mpScanCurrent += nRead; // more ZStream data in the next IDAT chunk
944 break;
946 else // this scanline is Finished
948 mpScanCurrent = mpInflateInBuf;
949 ImplApplyFilter();
951 ImplDrawScanline( mnXStart, mnXAdd );
952 mnYpos += mnYAdd;
955 if ( mnYpos >= (sal_uInt32)maOrigSize.Height() )
957 if( (mnPass < 7) && mnInterlaceType )
958 if( ImplPreparePass() )
959 continue;
960 mbIDAT = true;
961 break;
966 if( mbIDAT )
968 mpZCodec->EndCompression();
969 mbzCodecInUse = FALSE;
973 // ---------------------------------------------------------------------------------------------------
975 bool PNGReaderImpl::ImplPreparePass()
977 struct InterlaceParams{ int mnXStart, mnYStart, mnXAdd, mnYAdd; };
978 static const InterlaceParams aInterlaceParams[8] =
980 // non-interlaced
981 { 0, 0, 1, 1 },
982 // Adam7-interlaced
983 { 0, 0, 8, 8 }, // pass 1
984 { 4, 0, 8, 8 }, // pass 2
985 { 0, 4, 4, 8 }, // pass 3
986 { 2, 0, 4, 4 }, // pass 4
987 { 0, 2, 2, 4 }, // pass 5
988 { 1, 0, 2, 2 }, // pass 6
989 { 0, 1, 1, 2 } // pass 7
992 const InterlaceParams* pParam = &aInterlaceParams[ 0 ];
993 if( mnInterlaceType )
995 while( ++mnPass <= 7 )
997 pParam = &aInterlaceParams[ mnPass ];
999 // skip this pass if the original image is too small for it
1000 if( (pParam->mnXStart < maOrigSize.Width())
1001 && (pParam->mnYStart < maOrigSize.Height()) )
1002 break;
1004 if( mnPass > 7 )
1005 return false;
1007 // skip the last passes if possible (for scaled down target images)
1008 if( mnPreviewMask & (pParam->mnXStart | pParam->mnYStart) )
1009 return false;
1012 mnYpos = pParam->mnYStart;
1013 mnXStart = pParam->mnXStart;
1014 mnXAdd = pParam->mnXAdd;
1015 mnYAdd = pParam->mnYAdd;
1017 // in Interlace mode the size of scanline is not constant
1018 // so first we calculate the number of entrys
1019 long nScanWidth = (maOrigSize.Width() - mnXStart + mnXAdd - 1) / mnXAdd;
1020 mnScansize = nScanWidth;
1022 if( mbRGBTriple )
1023 mnScansize = 3 * nScanWidth;
1025 if( mbAlphaChannel )
1026 mnScansize += nScanWidth;
1028 // convert to width in bytes
1029 mnScansize = ( mnScansize*mnPngDepth + 7 ) >> 3;
1031 ++mnScansize; // scan size also needs room for the filtertype byte
1032 rtl_zeroMemory( mpScanPrior, mnScansize );
1034 return true;
1037 // ----------------------------------------------------------------------------
1038 // ImplApplyFilter writes the complete Scanline (nY)
1039 // in interlace mode the parameter nXStart and nXAdd are non-zero
1041 void PNGReaderImpl::ImplApplyFilter()
1043 OSL_ASSERT( mnScansize >= mnBPP + 1 );
1044 const BYTE* const pScanEnd = mpInflateInBuf + mnScansize;
1046 BYTE nFilterType = *mpInflateInBuf; // the filter type may change each scanline
1047 switch ( nFilterType )
1049 default: // unknown Scanline Filter Type
1050 case 0: // Filter Type "None"
1051 // we let the pixels pass and display the data unfiltered
1052 break;
1054 case 1: // Scanline Filter Type "Sub"
1056 BYTE* p1 = mpInflateInBuf + 1;
1057 const BYTE* p2 = p1;
1058 p1 += mnBPP;
1060 // use left pixels
1062 *p1 = static_cast<BYTE>( *p1 + *(p2++) );
1063 while( ++p1 < pScanEnd );
1065 break;
1067 case 2: // Scanline Filter Type "Up"
1069 BYTE* p1 = mpInflateInBuf + 1;
1070 const BYTE* p2 = mpScanPrior + 1;
1072 // use pixels from prior line
1073 while( p1 < pScanEnd )
1075 *p1 = static_cast<BYTE>( *p1 + *(p2++) );
1076 ++p1;
1079 break;
1081 case 3: // Scanline Filter Type "Average"
1083 BYTE* p1 = mpInflateInBuf + 1;
1084 const BYTE* p2 = mpScanPrior + 1;
1085 const BYTE* p3 = p1;
1087 // use one pixel from prior line
1088 for( int n = mnBPP; --n >= 0; ++p1, ++p2)
1089 *p1 = static_cast<BYTE>( *p1 + (*p2 >> 1) );
1091 // predict by averaging the left and prior line pixels
1092 while( p1 < pScanEnd )
1094 *p1 = static_cast<BYTE>( *p1 + ((*(p2++) + *(p3++)) >> 1) );
1095 ++p1;
1098 break;
1100 case 4: // Scanline Filter Type "PaethPredictor"
1102 BYTE* p1 = mpInflateInBuf + 1;
1103 const BYTE* p2 = mpScanPrior + 1;
1104 const BYTE* p3 = p1;
1105 const BYTE* p4 = p2;
1107 // use one pixel from prior line
1108 for( int n = mnBPP; --n >= 0; ++p1)
1109 *p1 = static_cast<BYTE>( *p1 + *(p2++) );
1111 // predict by using the left and the prior line pixels
1112 while( p1 < pScanEnd )
1114 int na = *(p2++);
1115 int nb = *(p3++);
1116 int nc = *(p4++);
1118 int npa = nb - (int)nc;
1119 int npb = na - (int)nc;
1120 int npc = npa + npb;
1122 if( npa < 0 )
1123 npa =-npa;
1124 if( npb < 0 )
1125 npb =-npb;
1126 if( npc < 0 )
1127 npc =-npc;
1129 if( npa > npb )
1130 na = nb, npa = npb;
1131 if( npa > npc )
1132 na = nc;
1134 *p1 = static_cast<BYTE>( *p1 + na );
1135 ++p1;
1138 break;
1141 rtl_copyMemory( mpScanPrior, mpInflateInBuf, mnScansize );
1144 // ---------------------------------------------------------------------------------------------------
1145 // ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
1146 // In interlace mode the parameter nXStart and nXAdd append to the currently used pass
1148 void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd )
1150 // optimization for downscaling
1151 if( mnYpos & mnPreviewMask )
1152 return;
1153 if( nXStart & mnPreviewMask )
1154 return;
1156 // convert nY to pixel units in the target image
1157 // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
1158 const sal_uInt32 nY = mnYpos >> mnPreviewShift;
1160 const BYTE* pTmp = mpInflateInBuf + 1;
1161 if ( mpAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
1163 switch ( mpAcc->GetBitCount() )
1165 case 1 :
1167 if ( mbTransparent )
1169 for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1171 BYTE nCol;
1172 nShift = (nShift - 1) & 7;
1173 if ( nShift == 0 )
1174 nCol = *(pTmp++);
1175 else
1176 nCol = static_cast<BYTE>( *pTmp >> nShift );
1177 nCol &= 1;
1179 ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1182 else
1183 { // BMP_FORMAT_1BIT_MSB_PAL
1184 for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1186 nShift = (nShift - 1) & 7;
1188 BYTE nCol;
1189 if ( nShift == 0 )
1190 nCol = *(pTmp++);
1191 else
1192 nCol = static_cast<BYTE>( *pTmp >> nShift );
1193 nCol &= 1;
1195 ImplSetPixel( nY, nX, nCol );
1199 break;
1201 case 4 :
1203 if ( mbTransparent )
1205 if ( mnPngDepth == 4 ) // check if source has a two bit pixel format
1207 for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, ++nXIndex )
1209 if( nXIndex & 1 )
1211 ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
1212 pTmp++;
1214 else
1216 ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
1220 else // if ( mnPngDepth == 2 )
1222 for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1224 BYTE nCol;
1225 switch( nXIndex & 3 )
1227 case 0 :
1228 nCol = *pTmp >> 6;
1229 break;
1231 case 1 :
1232 nCol = ( *pTmp >> 4 ) & 0x03 ;
1233 break;
1235 case 2 :
1236 nCol = ( *pTmp >> 2 ) & 0x03;
1237 break;
1239 case 3 :
1240 nCol = ( *pTmp++ ) & 0x03;
1241 break;
1243 default: // get rid of nCol uninitialized warning
1244 nCol = 0;
1245 break;
1248 ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1252 else
1254 if ( mnPngDepth == 4 ) // maybe the source is a two bitmap graphic
1255 { // BMP_FORMAT_4BIT_LSN_PAL
1256 for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1258 if( nXIndex & 1 )
1259 ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
1260 else
1261 ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
1264 else // if ( mnPngDepth == 2 )
1266 for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1268 switch( nXIndex & 3 )
1270 case 0 :
1271 ImplSetPixel( nY, nX, *pTmp >> 6 );
1272 break;
1274 case 1 :
1275 ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
1276 break;
1278 case 2 :
1279 ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
1280 break;
1282 case 3 :
1283 ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
1284 break;
1290 break;
1292 case 8 :
1294 if ( mbAlphaChannel )
1296 if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
1298 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1299 ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
1301 else
1303 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1304 ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
1307 else if ( mbTransparent )
1309 if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
1311 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp++ )
1312 ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1314 else
1316 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1317 ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1320 else // neither alpha nor transparency
1322 if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
1324 if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
1326 int nLineBytes = maOrigSize.Width();
1327 mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_8BIT_PAL, nLineBytes );
1328 pTmp += nLineBytes;
1330 else
1332 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd )
1333 ImplSetPixel( nY, nX, *pTmp++ );
1336 else
1338 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1339 ImplSetPixel( nY, nX, *pTmp );
1343 break;
1345 default :
1346 mbStatus = FALSE;
1347 break;
1350 else // no palette => truecolor
1352 if( mbAlphaChannel ) // has RGB + alpha
1353 { // BMP_FORMAT_32BIT_TC_RGBA
1354 if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
1356 if ( mpColorTable != mpDefaultColorTable )
1358 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1359 ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1360 mpColorTable[ pTmp[ 1 ] ],
1361 mpColorTable[ pTmp[ 2 ] ] ), pTmp[ 3 ] );
1363 else
1365 // if ( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
1366 // {
1367 // int nLineBytes = 4 * maOrigSize.Width();
1368 // mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_32BIT_TC_RGBA, nLineBytes );
1369 // pTmp += nLineBytes;
1370 // }
1371 // else
1373 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1374 ImplSetAlphaPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ), pTmp[3] );
1378 else
1379 { // BMP_FORMAT_64BIT_TC_RGBA
1380 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 8 )
1381 ImplSetAlphaPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1382 mpColorTable[ pTmp[ 2 ] ],
1383 mpColorTable[ pTmp[ 4 ] ] ), pTmp[6] );
1386 else if( mbTransparent ) // has RGB + transparency
1387 { // BMP_FORMAT_24BIT_TC_RGB
1388 if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
1390 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1392 sal_uInt8 nRed = pTmp[ 0 ];
1393 sal_uInt8 nGreen = pTmp[ 1 ];
1394 sal_uInt8 nBlue = pTmp[ 2 ];
1395 sal_Bool bTransparent = ( ( nRed == mnTransRed )
1396 && ( nGreen == mnTransGreen )
1397 && ( nBlue == mnTransBlue ) );
1399 ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1400 mpColorTable[ nGreen ],
1401 mpColorTable[ nBlue ] ), bTransparent );
1404 else
1405 { // BMP_FORMAT_48BIT_TC_RGB
1406 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
1408 sal_uInt8 nRed = pTmp[ 0 ];
1409 sal_uInt8 nGreen = pTmp[ 2 ];
1410 sal_uInt8 nBlue = pTmp[ 4 ];
1411 sal_Bool bTransparent = ( ( nRed == mnTransRed )
1412 && ( nGreen == mnTransGreen )
1413 && ( nBlue == mnTransBlue ) );
1415 ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1416 mpColorTable[ nGreen ],
1417 mpColorTable[ nBlue ] ), bTransparent );
1421 else // has RGB but neither alpha nor transparency
1422 { // BMP_FORMAT_24BIT_TC_RGB
1423 if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
1425 if ( mpColorTable != mpDefaultColorTable )
1427 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1428 ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1429 mpColorTable[ pTmp[ 1 ] ],
1430 mpColorTable[ pTmp[ 2 ] ] ) );
1432 else
1434 if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
1436 int nLineBytes = maOrigSize.Width() * 3;
1437 mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_24BIT_TC_RGB, nLineBytes );
1438 pTmp += nLineBytes;
1440 else
1442 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1443 ImplSetPixel( nY, nX, BitmapColor( pTmp[0], pTmp[1], pTmp[2] ) );
1447 else
1448 { // BMP_FORMAT_48BIT_TC_RGB
1449 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
1450 ImplSetPixel( nY, nX, BitmapColor( mpColorTable[ pTmp[ 0 ] ],
1451 mpColorTable[ pTmp[ 2 ] ],
1452 mpColorTable[ pTmp[ 4 ] ] ) );
1458 // ------------------------------------------------------------------------
1460 void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
1462 // TODO: get preview mode checks out of inner loop
1463 if( nX & mnPreviewMask )
1464 return;
1465 nX >>= mnPreviewShift;
1467 mpAcc->SetPixel( nY, nX, rBitmapColor );
1470 // ------------------------------------------------------------------------
1472 void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, BYTE nPalIndex )
1474 // TODO: get preview mode checks out of inner loop
1475 if( nX & mnPreviewMask )
1476 return;
1477 nX >>= mnPreviewShift;
1479 mpAcc->SetPixel( nY, nX, nPalIndex );
1482 // ------------------------------------------------------------------------
1484 void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, BOOL bTrans )
1486 // TODO: get preview mode checks out of inner loop
1487 if( nX & mnPreviewMask )
1488 return;
1489 nX >>= mnPreviewShift;
1491 mpAcc->SetPixel( nY, nX, rBitmapColor );
1493 if ( bTrans )
1494 mpMaskAcc->SetPixel( nY, nX, mcTranspColor );
1495 else
1496 mpMaskAcc->SetPixel( nY, nX, mcOpaqueColor );
1499 // ------------------------------------------------------------------------
1501 void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1502 BYTE nPalIndex, BYTE nAlpha )
1504 // TODO: get preview mode checks out of inner loop
1505 if( nX & mnPreviewMask )
1506 return;
1507 nX >>= mnPreviewShift;
1509 mpAcc->SetPixel( nY, nX, nPalIndex );
1510 mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
1513 // ------------------------------------------------------------------------
1515 void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1516 const BitmapColor& rBitmapColor, BYTE nAlpha )
1518 // TODO: get preview mode checks out of inner loop
1519 if( nX & mnPreviewMask )
1520 return;
1521 nX >>= mnPreviewShift;
1523 mpAcc->SetPixel( nY, nX, rBitmapColor );
1524 mpMaskAcc->SetPixel( nY, nX, ~nAlpha );
1527 // ------------------------------------------------------------------------
1529 sal_uInt32 PNGReaderImpl::ImplReadsal_uInt32()
1531 sal_uInt32 nRet;
1532 nRet = *maDataIter++;
1533 nRet <<= 8;
1534 nRet |= *maDataIter++;
1535 nRet <<= 8;
1536 nRet |= *maDataIter++;
1537 nRet <<= 8;
1538 nRet |= *maDataIter++;
1539 return nRet;
1542 // ------------------------------------------------------------------------
1544 // -------------
1545 // - PNGReader -
1546 // -------------
1548 PNGReader::PNGReader( SvStream& rIStm ) :
1549 mpImpl( new ::vcl::PNGReaderImpl( rIStm ) )
1553 // ------------------------------------------------------------------------
1555 PNGReader::~PNGReader()
1557 delete mpImpl;
1560 // ------------------------------------------------------------------------
1562 BitmapEx PNGReader::Read( const Size& i_rPreviewSizeHint )
1564 return mpImpl->GetBitmapEx( i_rPreviewSizeHint );
1567 // ------------------------------------------------------------------------
1569 const std::vector< vcl::PNGReader::ChunkData >& PNGReader::GetChunks() const
1571 return mpImpl->GetAllChunks();
1574 // ------------------------------------------------------------------------
1576 void PNGReader::SetIgnoreGammaChunk( sal_Bool b )
1578 mpImpl->SetIgnoreGammaChunk( b );
1582 } // namespace vcl