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