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