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