1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pngread.cxx,v $
10 * $Revision: 1.28.78.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include <vcl/pngread.hxx>
38 #include <rtl/memory.h>
39 #include <rtl/alloc.h>
40 #include <tools/zcodec.hxx>
41 #include <tools/stream.hxx>
42 #include <vcl/bmpacc.hxx>
43 #include <vcl/svapp.hxx>
44 #include <vcl/alpha.hxx>
45 #include <osl/endian.h>
51 #define PNGCHUNK_IHDR 0x49484452
52 #define PNGCHUNK_PLTE 0x504c5445
53 #define PNGCHUNK_IDAT 0x49444154
54 #define PNGCHUNK_IEND 0x49454e44
55 #define PNGCHUNK_bKGD 0x624b4744
56 #define PNGCHUNK_cHRM 0x6348524d
57 #define PNGCHUNK_gAMA 0x67414d41
58 #define PNGCHUNK_hIST 0x68495354
59 #define PNGCHUNK_pHYs 0x70485973
60 #define PNGCHUNK_sBIT 0x73425420
61 #define PNGCHUNK_tIME 0x74494d45
62 #define PNGCHUNK_tEXt 0x74455874
63 #define PNGCHUNK_tRNS 0x74524e53
64 #define PNGCHUNK_zTXt 0x7a545874
65 #define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
67 #define VIEWING_GAMMA 2.35
68 #define DISPLAY_GAMMA 1.0
76 // ------------------------------------------------------------------------------
78 static const BYTE mpDefaultColorTable
[ 256 ] =
79 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
80 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
81 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
82 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
83 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
84 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
85 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
86 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
87 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
88 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
89 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
90 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
91 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
92 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
93 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
94 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
104 SvStream
& mrPNGStream
;
105 sal_uInt16 mnOrigStreamMode
;
107 std::vector
< vcl::PNGReader::ChunkData
> maChunkSeq
;
108 std::vector
< vcl::PNGReader::ChunkData
>::iterator maChunkIter
;
109 std::vector
< sal_uInt8
>::iterator maDataIter
;
112 BitmapWriteAccess
* mpAcc
;
114 AlphaMask
* mpAlphaMask
;
115 BitmapWriteAccess
* mpMaskAcc
;
117 BYTE
* mpInflateInBuf
; // as big as the size of a scanline + alphachannel + 1
118 BYTE
* mpScanPrior
; // pointer to the latest scanline
119 BYTE
* mpTransTab
; // for transparency in images with palette colortype
120 BYTE
* mpScanCurrent
; // pointer into the current scanline
121 BYTE
* mpColorTable
; //
122 sal_Size mnStreamSize
; // estimate of PNG file size
123 sal_uInt32 mnChunkType
; // Type of current PNG chunk
124 sal_Int32 mnChunkLen
; // Length of current PNG chunk
125 Size maOrigSize
; // pixel size of the full image
126 Size maTargetSize
; // pixel size of the result image
127 Size maPhysSize
; // prefered size in MAP_100TH_MM units
128 sal_uInt32 mnBPP
; // number of bytes per pixel
129 sal_uInt32 mnScansize
; // max size of scanline
130 sal_uInt32 mnYpos
; // latest y position in full image
131 int mnPass
; // if interlaced the latest pass ( 1..7 ) else 7
132 sal_uInt32 mnXStart
; // the starting X for the current pass
133 sal_uInt32 mnXAdd
; // the increment for input images X coords for the current pass
134 sal_uInt32 mnYAdd
; // the increment for input images Y coords for the current pass
135 int mnPreviewShift
; // shift to convert orig image coords into preview image coords
136 int mnPreviewMask
; // == ((1 << mnPreviewShift) - 1)
137 USHORT mnIStmOldMode
;
138 USHORT mnTargetDepth
; // pixel depth of target bitmap
142 BYTE mnPngDepth
; // pixel depth of PNG data
144 BYTE mnCompressionType
;
146 BYTE mnInterlaceType
;
147 BitmapColor mcTranspColor
; // transparency mask's transparency "color"
148 BitmapColor mcOpaqueColor
; // transparency mask's opaque "color"
149 BOOL mbTransparent
; // graphic includes an tRNS Chunk or an alpha Channel
150 BOOL mbAlphaChannel
; // is true for ColorType 4 and 6
152 BOOL mbPalette
; // FALSE if we need a Palette
156 BOOL mbIDAT
; // TRUE if finished with enough IDAT chunks
157 BOOL mbGamma
; // TRUE if Gamma Correction available
158 BOOL mbpHYs
; // TRUE if pysical size of pixel available
159 sal_Bool mbIgnoreGammaChunk
;
161 bool ReadNextChunk();
162 void ReadRemainingChunks();
163 void SkipRemainingChunks();
165 void ImplSetPixel( sal_uInt32 y
, sal_uInt32 x
, const BitmapColor
& );
166 void ImplSetPixel( sal_uInt32 y
, sal_uInt32 x
, BYTE nPalIndex
);
167 void ImplSetTranspPixel( sal_uInt32 y
, sal_uInt32 x
, const BitmapColor
&, BOOL bTrans
);
168 void ImplSetAlphaPixel( sal_uInt32 y
, sal_uInt32 x
, BYTE nPalIndex
, BYTE nAlpha
);
169 void ImplSetAlphaPixel( sal_uInt32 y
, sal_uInt32 x
, const BitmapColor
&, BYTE nAlpha
);
171 bool ImplPreparePass();
172 void ImplApplyFilter();
173 void ImplDrawScanline( sal_uInt32 nXStart
, sal_uInt32 nXAdd
);
174 BOOL
ImplReadTransparent();
176 void ImplGetBackground();
177 BYTE
ImplScaleColor();
178 BOOL
ImplReadHeader( const Size
& rPreviewSizeHint
);
179 BOOL
ImplReadPalette();
180 void ImplGetGrayPalette( sal_uInt16
);
181 sal_uInt32
ImplReadsal_uInt32();
185 PNGReaderImpl( SvStream
& );
188 BitmapEx
GetBitmapEx( const Size
& rPreviewSizeHint
);
189 const std::vector
< PNGReader::ChunkData
>& GetAllChunks();
190 void SetIgnoreGammaChunk( sal_Bool bIgnore
){ mbIgnoreGammaChunk
= bIgnore
; };
193 // ------------------------------------------------------------------------------
195 PNGReaderImpl::PNGReaderImpl( SvStream
& rPNGStream
)
196 : mrPNGStream( rPNGStream
),
200 mpAlphaMask ( NULL
),
202 mpZCodec ( new ZCodec( DEFAULT_IN_BUFSIZE
, DEFAULT_OUT_BUFSIZE
, MAX_MEM_USAGE
) ),
203 mpInflateInBuf ( NULL
),
204 mpScanPrior ( NULL
),
206 mpColorTable ( (sal_uInt8
*) mpDefaultColorTable
),
207 mbzCodecInUse ( sal_False
),
210 mbGamma ( sal_False
),
211 mbpHYs ( sal_False
),
212 mbIgnoreGammaChunk ( sal_False
)
214 // prepare the PNG data stream
215 mnOrigStreamMode
= mrPNGStream
.GetNumberFormatInt();
216 mrPNGStream
.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN
);
218 // prepare the chunk reader
219 maChunkSeq
.reserve( 16 );
220 maChunkIter
= maChunkSeq
.begin();
222 // estimate PNG file size (to allow sanity checks)
223 const sal_Size nStreamPos
= mrPNGStream
.Tell();
224 mrPNGStream
.Seek( STREAM_SEEK_TO_END
);
225 mnStreamSize
= mrPNGStream
.Tell();
226 mrPNGStream
.Seek( nStreamPos
);
228 // check the PNG header magic
229 sal_uInt32 nDummy
= 0;
230 mrPNGStream
>> nDummy
;
231 mbStatus
= (nDummy
== 0x89504e47);
232 mrPNGStream
>> nDummy
;
233 mbStatus
&= (nDummy
== 0x0d0a1a0a);
236 mnPreviewMask
= (1 << mnPreviewShift
) - 1;
239 // ------------------------------------------------------------------------
241 PNGReaderImpl::~PNGReaderImpl()
243 mrPNGStream
.SetNumberFormatInt( mnOrigStreamMode
);
246 mpZCodec
->EndCompression();
248 if( mpColorTable
!= mpDefaultColorTable
)
249 delete[] mpColorTable
;
255 delete[] mpInflateInBuf
;
256 delete[] mpScanPrior
;
260 // ------------------------------------------------------------------------
262 bool PNGReaderImpl::ReadNextChunk()
264 if( maChunkIter
== maChunkSeq
.end() )
266 // get the next chunk from the stream
268 // unless we are at the end of the PNG stream
269 if( mrPNGStream
.IsEof() || (mrPNGStream
.GetError() != ERRCODE_NONE
) )
271 if( !maChunkSeq
.empty() && (maChunkSeq
.back().nType
== PNGCHUNK_IEND
) )
274 PNGReader::ChunkData aDummyChunk
;
275 maChunkIter
= maChunkSeq
.insert( maChunkSeq
.end(), aDummyChunk
);
276 PNGReader::ChunkData
& rChunkData
= *maChunkIter
;
278 // read the chunk header
279 mrPNGStream
>> mnChunkLen
>> mnChunkType
;
280 rChunkData
.nType
= mnChunkType
;
282 // #128377#/#149343# sanity check for chunk length
285 const sal_Size nStreamPos
= mrPNGStream
.Tell();
286 if( nStreamPos
+ mnChunkLen
>= mnStreamSize
)
289 // calculate chunktype CRC (swap it back to original byte order)
290 sal_uInt32 nChunkType
= mnChunkType
;;
291 #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
292 nChunkType
= SWAPLONG( nChunkType
);
294 sal_uInt32 nCRC32
= rtl_crc32( 0, &nChunkType
, 4 );
296 // read the chunk data and check the CRC
297 if( mnChunkLen
&& !mrPNGStream
.IsEof() )
299 rChunkData
.aData
.resize( mnChunkLen
);
301 sal_Int32 nBytesRead
= 0;
303 sal_uInt8
* pPtr
= &rChunkData
.aData
[ nBytesRead
];
304 nBytesRead
+= mrPNGStream
.Read( pPtr
, mnChunkLen
- nBytesRead
);
305 } while ( ( nBytesRead
< mnChunkLen
) && ( mrPNGStream
.GetError() == ERRCODE_NONE
) );
307 nCRC32
= rtl_crc32( nCRC32
, &rChunkData
.aData
[ 0 ], mnChunkLen
);
308 maDataIter
= rChunkData
.aData
.begin();
311 mrPNGStream
>> nCheck
;
312 if( nCRC32
!= nCheck
)
317 // the next chunk was already read
318 mnChunkType
= (*maChunkIter
).nType
;
319 mnChunkLen
= (*maChunkIter
).aData
.size();
320 maDataIter
= (*maChunkIter
).aData
.begin();
324 if( mnChunkType
== PNGCHUNK_IEND
)
329 // ------------------------------------------------------------------------
331 // read the remaining chunks from mrPNGStream
332 void PNGReaderImpl::ReadRemainingChunks()
334 while( ReadNextChunk() ) ;
337 // ------------------------------------------------------------------------
339 // move position of mrPNGStream to the end of the file
340 void PNGReaderImpl::SkipRemainingChunks()
342 // nothing to skip if the last chunk was read
343 if( !maChunkSeq
.empty() && (maChunkSeq
.back().nType
== PNGCHUNK_IEND
) )
346 // read from the stream until the IEND chunk is found
347 const sal_Size nStreamPos
= mrPNGStream
.Tell();
348 while( !mrPNGStream
.IsEof() && (mrPNGStream
.GetError() == ERRCODE_NONE
) )
350 mrPNGStream
>> mnChunkLen
>> mnChunkType
;
353 if( nStreamPos
+ mnChunkLen
>= mnStreamSize
)
355 mrPNGStream
.SeekRel( mnChunkLen
+ 4 ); // skip data + CRC
356 if( mnChunkType
== PNGCHUNK_IEND
)
361 // ------------------------------------------------------------------------
363 const std::vector
< vcl::PNGReader::ChunkData
>& PNGReaderImpl::GetAllChunks()
365 ReadRemainingChunks();
369 // ------------------------------------------------------------------------
371 BitmapEx
PNGReaderImpl::GetBitmapEx( const Size
& rPreviewSizeHint
)
373 // reset to the first chunk
374 maChunkIter
= maChunkSeq
.begin();
377 while( mbStatus
&& !mbIDAT
&& ReadNextChunk() )
379 switch( mnChunkType
)
383 mbStatus
= ImplReadHeader( rPreviewSizeHint
);
387 case PNGCHUNK_gAMA
: // the gamma chunk must precede
388 { // the 'IDAT' and also the 'PLTE'(if available )
389 if ( !mbIgnoreGammaChunk
&& ( mbIDAT
== FALSE
) )
397 mbStatus
= ImplReadPalette();
403 if ( !mbIDAT
) // the tRNS chunk must precede the IDAT
404 mbStatus
= ImplReadTransparent();
408 case PNGCHUNK_bKGD
: // the background chunk must appear
410 if ( ( mbIDAT
== FALSE
) && mbPalette
) // before the 'IDAT' and after the
411 ImplGetBackground(); // PLTE(if available ) chunk.
417 if ( !mbIDAT
) // the gfx is finished, but there may be left a zlibCRC of about 4Bytes
424 if ( !mbIDAT
&& mnChunkLen
== 9 )
426 sal_uInt32 nXPixelPerMeter
= ImplReadsal_uInt32();
427 sal_uInt32 nYPixelPerMeter
= ImplReadsal_uInt32();
429 sal_uInt8 nUnitSpecifier
= *maDataIter
++;
430 if( (nUnitSpecifier
== 1) && nXPixelPerMeter
&& nXPixelPerMeter
)
434 // convert into MAP_100TH_MM
435 maPhysSize
.Width() = (sal_Int32
)( (100000.0 * maOrigSize
.Width()) / nXPixelPerMeter
);
436 maPhysSize
.Height() = (sal_Int32
)( (100000.0 * maOrigSize
.Height()) / nYPixelPerMeter
);
443 mbStatus
= mbIDAT
; // there is a problem if the image is not complete yet
448 // release write access of the bitmaps
450 mpBmp
->ReleaseAccess( mpAcc
), mpAcc
= NULL
;
455 mpAlphaMask
->ReleaseAccess( mpMaskAcc
);
456 else if ( mpMaskBmp
)
457 mpMaskBmp
->ReleaseAccess( mpMaskAcc
);
462 // return the resulting BitmapEx
465 if( !mbStatus
|| !mbIDAT
)
470 aRet
= BitmapEx( *mpBmp
, *mpAlphaMask
);
471 else if ( mpMaskBmp
)
472 aRet
= BitmapEx( *mpBmp
, *mpMaskBmp
);
476 if ( mbpHYs
&& maPhysSize
.Width() && maPhysSize
.Height() )
478 aRet
.SetPrefMapMode( MAP_100TH_MM
);
479 aRet
.SetPrefSize( maPhysSize
);
483 // TODO: make sure nobody depends on the stream being after the IEND chunks
484 // => let them do ReadChunks before
485 ReadRemainingChunks();
492 // ------------------------------------------------------------------------
494 BOOL
PNGReaderImpl::ImplReadHeader( const Size
& rPreviewSizeHint
)
496 if( mnChunkLen
< 13 )
499 maOrigSize
.Width() = ImplReadsal_uInt32();
500 maOrigSize
.Height() = ImplReadsal_uInt32();
502 if ( !maOrigSize
.Width() || !maOrigSize
.Height() )
505 mnPngDepth
= *(maDataIter
++);
506 mnColorType
= *(maDataIter
++);
508 mnCompressionType
= *(maDataIter
++);
509 if( mnCompressionType
!= 0 ) // unknown compression type
512 mnFilterType
= *(maDataIter
++);
513 if( mnFilterType
!= 0 ) // unknown filter type
516 mnInterlaceType
= *(maDataIter
++);
517 switch ( mnInterlaceType
) // filter type valid ?
519 case 0 : // progressive image
522 case 1 : // Adam7-interlaced image
530 mbIDAT
= mbAlphaChannel
= mbTransparent
= FALSE
;
531 mbGrayScale
= mbRGBTriple
= FALSE
;
532 mnTargetDepth
= mnPngDepth
;
533 mnScansize
= ( ( maOrigSize
.Width() * mnPngDepth
) + 7 ) >> 3;
535 // valid color types are 0,2,3,4 & 6
536 switch ( mnColorType
)
538 case 0 : // each pixel is a grayscale
540 switch ( mnPngDepth
)
542 case 2 : // 2bit target not available -> use four bits
543 mnTargetDepth
= 4; // we have to expand the bitmap
547 mnTargetDepth
= 8; // we have to reduce the bitmap
560 case 2 : // each pixel is an RGB triple
564 switch ( mnPngDepth
)
566 case 16 : // we have to reduce the bitmap
576 case 3 : // each pixel is a palette index
578 switch ( mnPngDepth
)
581 mnTargetDepth
= 4; // we have to expand the bitmap
594 case 4 : // each pixel is a grayscale sample followed by an alpha sample
597 mbAlphaChannel
= TRUE
;
598 switch ( mnPngDepth
)
601 mnTargetDepth
= 8; // we have to reduce the bitmap
611 case 6 : // each pixel is an RGB triple followed by an alpha sample
615 mbAlphaChannel
= TRUE
;
618 case 16 : // we have to reduce the bitmap
632 mnBPP
= mnScansize
/ maOrigSize
.Width();
636 mnScansize
++; // each scanline includes one filterbyte
638 // TODO: switch between both scanlines instead of copying
639 mpInflateInBuf
= new BYTE
[ mnScansize
];
640 mpScanCurrent
= mpInflateInBuf
;
641 mpScanPrior
= new BYTE
[ mnScansize
];
643 // calculate target size from original size and the preview hint
644 if( rPreviewSizeHint
.Width() || rPreviewSizeHint
.Height() )
646 Size
aPreviewSize( rPreviewSizeHint
.Width(), rPreviewSizeHint
.Height() );
647 maTargetSize
= maOrigSize
;
649 if( aPreviewSize
.Width() == 0 ) {
650 aPreviewSize
.setWidth( ( maOrigSize
.Width()*aPreviewSize
.Height() )/maOrigSize
.Height() );
651 if( aPreviewSize
.Width() <= 0 )
652 aPreviewSize
.setWidth( 1 );
653 } else if( aPreviewSize
.Height() == 0 ) {
654 aPreviewSize
.setHeight( ( maOrigSize
.Height()*aPreviewSize
.Width() )/maOrigSize
.Width() );
655 if( aPreviewSize
.Height() <= 0 )
656 aPreviewSize
.setHeight( 1 );
659 if( aPreviewSize
.Width() < maOrigSize
.Width() && aPreviewSize
.Height() < maOrigSize
.Height() ) {
660 OSL_TRACE("preview size %dx%d", aPreviewSize
.Width(), aPreviewSize
.Height() );
662 for( int i
= 1; i
< 5; ++i
)
664 if( (maTargetSize
.Width() >> i
) < aPreviewSize
.Width() )
666 if( (maTargetSize
.Height() >> i
) < aPreviewSize
.Height() )
670 mnPreviewMask
= (1 << mnPreviewShift
) - 1;
674 maTargetSize
.Width() = (maOrigSize
.Width() + mnPreviewMask
) >> mnPreviewShift
;
675 maTargetSize
.Height() = (maOrigSize
.Height() + mnPreviewMask
) >> mnPreviewShift
;
677 mpBmp
= new Bitmap( maTargetSize
, mnTargetDepth
);
678 mpAcc
= mpBmp
->AcquireWriteAccess();
682 mpBmp
->SetSourceSizePixel( maOrigSize
);
684 if ( mbAlphaChannel
)
686 mpAlphaMask
= new AlphaMask( maTargetSize
);
687 mpAlphaMask
->Erase( 128 );
688 mpMaskAcc
= mpAlphaMask
->AcquireWriteAccess();
694 ImplGetGrayPalette( mnPngDepth
);
701 // ------------------------------------------------------------------------
703 void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth
)
708 sal_uInt16 nPaletteEntryCount
= 1 << nBitDepth
;
709 sal_uInt32 nAdd
= 256 / (nPaletteEntryCount
- 1);
711 // no bitdepth==2 available
712 // but bitdepth==4 with two unused bits is close enough
714 nPaletteEntryCount
= 16;
716 mpAcc
->SetPaletteEntryCount( nPaletteEntryCount
);
717 for ( sal_uInt32 i
= 0, nStart
= 0; nStart
< 256; i
++, nStart
+= nAdd
)
718 mpAcc
->SetPaletteColor( (USHORT
)i
, BitmapColor( mpColorTable
[ nStart
],
719 mpColorTable
[ nStart
], mpColorTable
[ nStart
] ) );
722 // ------------------------------------------------------------------------
724 BOOL
PNGReaderImpl::ImplReadPalette()
726 sal_uInt16 nCount
= static_cast<sal_uInt16
>( mnChunkLen
/ 3 );
728 if ( ( ( mnChunkLen
% 3 ) == 0 ) && ( ( 0 < nCount
) && ( nCount
<= 256 ) ) && mpAcc
)
731 mpAcc
->SetPaletteEntryCount( (USHORT
) nCount
);
733 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
735 BYTE nRed
= mpColorTable
[ *maDataIter
++ ];
736 BYTE nGreen
= mpColorTable
[ *maDataIter
++ ];
737 BYTE nBlue
= mpColorTable
[ *maDataIter
++ ];
738 mpAcc
->SetPaletteColor( i
, Color( nRed
, nGreen
, nBlue
) );
747 // ------------------------------------------------------------------------
749 BOOL
PNGReaderImpl::ImplReadTransparent()
751 bool bNeedAlpha
= false;
753 if ( mpTransTab
== NULL
)
755 switch ( mnColorType
)
759 if ( mnChunkLen
== 2 )
761 mpTransTab
= new sal_uInt8
[ 256 ];
762 rtl_fillMemory( mpTransTab
, 256, 0xff );
763 // color type 0 and 4 is always greyscale,
764 // so the return value can be used as index
765 sal_uInt8 nIndex
= ImplScaleColor();
766 mpTransTab
[ nIndex
] = 0;
767 mbTransparent
= true;
774 if ( mnChunkLen
== 6 )
776 mnTransRed
= ImplScaleColor();
777 mnTransGreen
= ImplScaleColor();
778 mnTransBlue
= ImplScaleColor();
779 mbTransparent
= true;
786 if ( mnChunkLen
<= 256 )
788 mpTransTab
= new BYTE
[ 256 ];
789 rtl_fillMemory( mpTransTab
, 256, 0xff );
790 rtl_copyMemory( mpTransTab
, &(*maDataIter
), mnChunkLen
);
791 maDataIter
+= mnChunkLen
;
792 mbTransparent
= true;
793 // need alpha transparency if not on/off masking
794 for( int i
= 0; i
< mnChunkLen
; ++i
)
795 bNeedAlpha
|= (mpTransTab
[i
]!=0x00) && (mpTransTab
[i
]!=0xFF);
802 if( mbTransparent
&& !mbAlphaChannel
&& !mpMaskBmp
)
806 mpAlphaMask
= new AlphaMask( maTargetSize
);
807 mpMaskAcc
= mpAlphaMask
->AcquireWriteAccess();
811 mpMaskBmp
= new Bitmap( maTargetSize
, 1 );
812 mpMaskAcc
= mpMaskBmp
->AcquireWriteAccess();
814 mbTransparent
= (mpMaskAcc
!= NULL
);
817 mcOpaqueColor
= BitmapColor( 0x00 );
818 mcTranspColor
= BitmapColor( 0xFF );
819 mpMaskAcc
->Erase( 0x00 );
825 // ------------------------------------------------------------------------
827 void PNGReaderImpl::ImplGetGamma()
832 sal_uInt32 nGammaValue
= ImplReadsal_uInt32();
833 double fGamma
= ( ( VIEWING_GAMMA
/ DISPLAY_GAMMA
) * ( (double)nGammaValue
/ 100000 ) );
834 double fInvGamma
= ( fGamma
<= 0.0 || fGamma
> 10.0 ) ? 1.0 : ( 1.0 / fGamma
);
836 if ( fInvGamma
!= 1.0 )
840 if ( mpColorTable
== mpDefaultColorTable
)
841 mpColorTable
= new sal_uInt8
[ 256 ];
843 for ( sal_Int32 i
= 0; i
< 256; i
++ )
844 mpColorTable
[ i
] = (sal_uInt8
)(pow((double)i
/255.0, fInvGamma
) * 255.0 + 0.5);
847 ImplGetGrayPalette( mnPngDepth
);
851 // ------------------------------------------------------------------------
853 void PNGReaderImpl::ImplGetBackground()
855 switch ( mnColorType
)
859 if ( mnChunkLen
== 1 )
861 UINT16 nCol
= *maDataIter
++;
862 if ( nCol
< mpAcc
->GetPaletteEntryCount() )
864 mpAcc
->Erase( mpAcc
->GetPaletteColor( (BYTE
)nCol
) );
874 if ( mnChunkLen
== 2 )
876 // the color type 0 and 4 is always greyscale,
877 // so the return value can be used as index
878 sal_uInt8 nIndex
= ImplScaleColor();
879 mpAcc
->Erase( mpAcc
->GetPaletteColor( nIndex
) );
887 if ( mnChunkLen
== 6 )
889 sal_uInt8 nRed
= ImplScaleColor();
890 sal_uInt8 nGreen
= ImplScaleColor();
891 sal_uInt8 nBlue
= ImplScaleColor();
892 mpAcc
->Erase( Color( nRed
, nGreen
, nBlue
) );
899 // ------------------------------------------------------------------------
901 // for color type 0 and 4 (greyscale) the return value is always index to the color
902 // 2 and 6 (RGB) the return value is always the 8 bit color component
903 sal_uInt8
PNGReaderImpl::ImplScaleColor()
905 sal_uInt32 nMask
= ( ( 1 << mnPngDepth
) - 1 );
906 sal_uInt16 nCol
= ( *maDataIter
++ << 8 );
908 nCol
+= *maDataIter
++ & (sal_uInt16
)nMask
;
910 if ( mnPngDepth
> 8 ) // convert 16bit graphics to 8
913 return (sal_uInt8
) nCol
;
916 // ------------------------------------------------------------------------
917 // ImplReadIDAT reads as much image data as needed
919 void PNGReaderImpl::ImplReadIDAT()
923 if ( mbzCodecInUse
== FALSE
)
925 mbzCodecInUse
= TRUE
;
926 mpZCodec
->BeginCompression( ZCODEC_PNG_DEFAULT
);
928 mpZCodec
->SetBreak( mnChunkLen
);
929 SvMemoryStream
aIStrm( &(*maDataIter
), mnChunkLen
, STREAM_READ
);
931 while ( ( mpZCodec
->GetBreak() ) )
933 // get bytes needed to fill the current scanline
934 sal_Int32 nToRead
= mnScansize
- (mpScanCurrent
- mpInflateInBuf
);
935 sal_Int32 nRead
= mpZCodec
->ReadAsynchron( aIStrm
, mpScanCurrent
, nToRead
);
941 if ( nRead
< nToRead
)
943 mpScanCurrent
+= nRead
; // more ZStream data in the next IDAT chunk
946 else // this scanline is Finished
948 mpScanCurrent
= mpInflateInBuf
;
951 ImplDrawScanline( mnXStart
, mnXAdd
);
955 if ( mnYpos
>= (sal_uInt32
)maOrigSize
.Height() )
957 if( (mnPass
< 7) && mnInterlaceType
)
958 if( ImplPreparePass() )
968 mpZCodec
->EndCompression();
969 mbzCodecInUse
= FALSE
;
973 // ---------------------------------------------------------------------------------------------------
975 bool PNGReaderImpl::ImplPreparePass()
977 struct InterlaceParams
{ int mnXStart
, mnYStart
, mnXAdd
, mnYAdd
; };
978 static const InterlaceParams aInterlaceParams
[8] =
983 { 0, 0, 8, 8 }, // pass 1
984 { 4, 0, 8, 8 }, // pass 2
985 { 0, 4, 4, 8 }, // pass 3
986 { 2, 0, 4, 4 }, // pass 4
987 { 0, 2, 2, 4 }, // pass 5
988 { 1, 0, 2, 2 }, // pass 6
989 { 0, 1, 1, 2 } // pass 7
992 const InterlaceParams
* pParam
= &aInterlaceParams
[ 0 ];
993 if( mnInterlaceType
)
995 while( ++mnPass
<= 7 )
997 pParam
= &aInterlaceParams
[ mnPass
];
999 // skip this pass if the original image is too small for it
1000 if( (pParam
->mnXStart
< maOrigSize
.Width())
1001 && (pParam
->mnYStart
< maOrigSize
.Height()) )
1007 // skip the last passes if possible (for scaled down target images)
1008 if( mnPreviewMask
& (pParam
->mnXStart
| pParam
->mnYStart
) )
1012 mnYpos
= pParam
->mnYStart
;
1013 mnXStart
= pParam
->mnXStart
;
1014 mnXAdd
= pParam
->mnXAdd
;
1015 mnYAdd
= pParam
->mnYAdd
;
1017 // in Interlace mode the size of scanline is not constant
1018 // so first we calculate the number of entrys
1019 long nScanWidth
= (maOrigSize
.Width() - mnXStart
+ mnXAdd
- 1) / mnXAdd
;
1020 mnScansize
= nScanWidth
;
1023 mnScansize
= 3 * nScanWidth
;
1025 if( mbAlphaChannel
)
1026 mnScansize
+= nScanWidth
;
1028 // convert to width in bytes
1029 mnScansize
= ( mnScansize
*mnPngDepth
+ 7 ) >> 3;
1031 ++mnScansize
; // scan size also needs room for the filtertype byte
1032 rtl_zeroMemory( mpScanPrior
, mnScansize
);
1037 // ----------------------------------------------------------------------------
1038 // ImplApplyFilter writes the complete Scanline (nY)
1039 // in interlace mode the parameter nXStart and nXAdd are non-zero
1041 void PNGReaderImpl::ImplApplyFilter()
1043 OSL_ASSERT( mnScansize
>= mnBPP
+ 1 );
1044 const BYTE
* const pScanEnd
= mpInflateInBuf
+ mnScansize
;
1046 BYTE nFilterType
= *mpInflateInBuf
; // the filter type may change each scanline
1047 switch ( nFilterType
)
1049 default: // unknown Scanline Filter Type
1050 case 0: // Filter Type "None"
1051 // we let the pixels pass and display the data unfiltered
1054 case 1: // Scanline Filter Type "Sub"
1056 BYTE
* p1
= mpInflateInBuf
+ 1;
1057 const BYTE
* p2
= p1
;
1062 *p1
= static_cast<BYTE
>( *p1
+ *(p2
++) );
1063 while( ++p1
< pScanEnd
);
1067 case 2: // Scanline Filter Type "Up"
1069 BYTE
* p1
= mpInflateInBuf
+ 1;
1070 const BYTE
* p2
= mpScanPrior
+ 1;
1072 // use pixels from prior line
1073 while( p1
< pScanEnd
)
1075 *p1
= static_cast<BYTE
>( *p1
+ *(p2
++) );
1081 case 3: // Scanline Filter Type "Average"
1083 BYTE
* p1
= mpInflateInBuf
+ 1;
1084 const BYTE
* p2
= mpScanPrior
+ 1;
1085 const BYTE
* p3
= p1
;
1087 // use one pixel from prior line
1088 for( int n
= mnBPP
; --n
>= 0; ++p1
, ++p2
)
1089 *p1
= static_cast<BYTE
>( *p1
+ (*p2
>> 1) );
1091 // predict by averaging the left and prior line pixels
1092 while( p1
< pScanEnd
)
1094 *p1
= static_cast<BYTE
>( *p1
+ ((*(p2
++) + *(p3
++)) >> 1) );
1100 case 4: // Scanline Filter Type "PaethPredictor"
1102 BYTE
* p1
= mpInflateInBuf
+ 1;
1103 const BYTE
* p2
= mpScanPrior
+ 1;
1104 const BYTE
* p3
= p1
;
1105 const BYTE
* p4
= p2
;
1107 // use one pixel from prior line
1108 for( int n
= mnBPP
; --n
>= 0; ++p1
)
1109 *p1
= static_cast<BYTE
>( *p1
+ *(p2
++) );
1111 // predict by using the left and the prior line pixels
1112 while( p1
< pScanEnd
)
1118 int npa
= nb
- (int)nc
;
1119 int npb
= na
- (int)nc
;
1120 int npc
= npa
+ npb
;
1134 *p1
= static_cast<BYTE
>( *p1
+ na
);
1141 rtl_copyMemory( mpScanPrior
, mpInflateInBuf
, mnScansize
);
1144 // ---------------------------------------------------------------------------------------------------
1145 // ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
1146 // In interlace mode the parameter nXStart and nXAdd append to the currently used pass
1148 void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart
, sal_uInt32 nXAdd
)
1150 // optimization for downscaling
1151 if( mnYpos
& mnPreviewMask
)
1153 if( nXStart
& mnPreviewMask
)
1156 // convert nY to pixel units in the target image
1157 // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
1158 const sal_uInt32 nY
= mnYpos
>> mnPreviewShift
;
1160 const BYTE
* pTmp
= mpInflateInBuf
+ 1;
1161 if ( mpAcc
->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
1163 switch ( mpAcc
->GetBitCount() )
1167 if ( mbTransparent
)
1169 for ( sal_Int32 nX
= nXStart
, nShift
= 0; nX
< maOrigSize
.Width(); nX
+= nXAdd
)
1172 nShift
= (nShift
- 1) & 7;
1176 nCol
= static_cast<BYTE
>( *pTmp
>> nShift
);
1179 ImplSetAlphaPixel( nY
, nX
, nCol
, mpTransTab
[ nCol
] );
1183 { // BMP_FORMAT_1BIT_MSB_PAL
1184 for ( sal_Int32 nX
= nXStart
, nShift
= 0; nX
< maOrigSize
.Width(); nX
+= nXAdd
)
1186 nShift
= (nShift
- 1) & 7;
1192 nCol
= static_cast<BYTE
>( *pTmp
>> nShift
);
1195 ImplSetPixel( nY
, nX
, nCol
);
1203 if ( mbTransparent
)
1205 if ( mnPngDepth
== 4 ) // check if source has a two bit pixel format
1207 for ( sal_Int32 nX
= nXStart
, nXIndex
= 0; nX
< maOrigSize
.Width(); nX
+= nXAdd
, ++nXIndex
)
1211 ImplSetAlphaPixel( nY
, nX
, *pTmp
& 0x0f, mpTransTab
[ *pTmp
& 0x0f ] );
1216 ImplSetAlphaPixel( nY
, nX
, ( *pTmp
>> 4 ) & 0x0f, mpTransTab
[ *pTmp
>> 4 ] );
1220 else // if ( mnPngDepth == 2 )
1222 for ( sal_Int32 nX
= nXStart
, nXIndex
= 0; nX
< maOrigSize
.Width(); nX
+= nXAdd
, nXIndex
++ )
1225 switch( nXIndex
& 3 )
1232 nCol
= ( *pTmp
>> 4 ) & 0x03 ;
1236 nCol
= ( *pTmp
>> 2 ) & 0x03;
1240 nCol
= ( *pTmp
++ ) & 0x03;
1243 default: // get rid of nCol uninitialized warning
1248 ImplSetAlphaPixel( nY
, nX
, nCol
, mpTransTab
[ nCol
] );
1254 if ( mnPngDepth
== 4 ) // maybe the source is a two bitmap graphic
1255 { // BMP_FORMAT_4BIT_LSN_PAL
1256 for ( sal_Int32 nX
= nXStart
, nXIndex
= 0; nX
< maOrigSize
.Width(); nX
+= nXAdd
, nXIndex
++ )
1259 ImplSetPixel( nY
, nX
, *pTmp
++ & 0x0f );
1261 ImplSetPixel( nY
, nX
, ( *pTmp
>> 4 ) & 0x0f );
1264 else // if ( mnPngDepth == 2 )
1266 for ( sal_Int32 nX
= nXStart
, nXIndex
= 0; nX
< maOrigSize
.Width(); nX
+= nXAdd
, nXIndex
++ )
1268 switch( nXIndex
& 3 )
1271 ImplSetPixel( nY
, nX
, *pTmp
>> 6 );
1275 ImplSetPixel( nY
, nX
, ( *pTmp
>> 4 ) & 0x03 );
1279 ImplSetPixel( nY
, nX
, ( *pTmp
>> 2 ) & 0x03 );
1283 ImplSetPixel( nY
, nX
, *pTmp
++ & 0x03 );
1294 if ( mbAlphaChannel
)
1296 if ( mnPngDepth
== 8 ) // maybe the source is a 16 bit grayscale
1298 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 2 )
1299 ImplSetAlphaPixel( nY
, nX
, pTmp
[ 0 ], pTmp
[ 1 ] );
1303 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 4 )
1304 ImplSetAlphaPixel( nY
, nX
, pTmp
[ 0 ], pTmp
[ 2 ] );
1307 else if ( mbTransparent
)
1309 if ( mnPngDepth
== 8 ) // maybe the source is a 16 bit grayscale
1311 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
++ )
1312 ImplSetAlphaPixel( nY
, nX
, *pTmp
, mpTransTab
[ *pTmp
] );
1316 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 2 )
1317 ImplSetAlphaPixel( nY
, nX
, *pTmp
, mpTransTab
[ *pTmp
] );
1320 else // neither alpha nor transparency
1322 if ( mnPngDepth
== 8 ) // maybe the source is a 16 bit grayscale
1324 if( nXAdd
== 1 && mnPreviewShift
== 0 ) // copy raw line data if possible
1326 int nLineBytes
= maOrigSize
.Width();
1327 mpAcc
->CopyScanline( nY
, pTmp
, BMP_FORMAT_8BIT_PAL
, nLineBytes
);
1332 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
)
1333 ImplSetPixel( nY
, nX
, *pTmp
++ );
1338 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 2 )
1339 ImplSetPixel( nY
, nX
, *pTmp
);
1350 else // no palette => truecolor
1352 if( mbAlphaChannel
) // has RGB + alpha
1353 { // BMP_FORMAT_32BIT_TC_RGBA
1354 if ( mnPngDepth
== 8 ) // maybe the source has 16 bit per sample
1356 if ( mpColorTable
!= mpDefaultColorTable
)
1358 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 4 )
1359 ImplSetAlphaPixel( nY
, nX
, BitmapColor( mpColorTable
[ pTmp
[ 0 ] ],
1360 mpColorTable
[ pTmp
[ 1 ] ],
1361 mpColorTable
[ pTmp
[ 2 ] ] ), pTmp
[ 3 ] );
1365 // if ( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
1367 // int nLineBytes = 4 * maOrigSize.Width();
1368 // mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_32BIT_TC_RGBA, nLineBytes );
1369 // pTmp += nLineBytes;
1373 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 4 )
1374 ImplSetAlphaPixel( nY
, nX
, BitmapColor( pTmp
[0], pTmp
[1], pTmp
[2] ), pTmp
[3] );
1379 { // BMP_FORMAT_64BIT_TC_RGBA
1380 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 8 )
1381 ImplSetAlphaPixel( nY
, nX
, BitmapColor( mpColorTable
[ pTmp
[ 0 ] ],
1382 mpColorTable
[ pTmp
[ 2 ] ],
1383 mpColorTable
[ pTmp
[ 4 ] ] ), pTmp
[6] );
1386 else if( mbTransparent
) // has RGB + transparency
1387 { // BMP_FORMAT_24BIT_TC_RGB
1388 if ( mnPngDepth
== 8 ) // maybe the source has 16 bit per sample
1390 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 3 )
1392 sal_uInt8 nRed
= pTmp
[ 0 ];
1393 sal_uInt8 nGreen
= pTmp
[ 1 ];
1394 sal_uInt8 nBlue
= pTmp
[ 2 ];
1395 sal_Bool bTransparent
= ( ( nRed
== mnTransRed
)
1396 && ( nGreen
== mnTransGreen
)
1397 && ( nBlue
== mnTransBlue
) );
1399 ImplSetTranspPixel( nY
, nX
, BitmapColor( mpColorTable
[ nRed
],
1400 mpColorTable
[ nGreen
],
1401 mpColorTable
[ nBlue
] ), bTransparent
);
1405 { // BMP_FORMAT_48BIT_TC_RGB
1406 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 6 )
1408 sal_uInt8 nRed
= pTmp
[ 0 ];
1409 sal_uInt8 nGreen
= pTmp
[ 2 ];
1410 sal_uInt8 nBlue
= pTmp
[ 4 ];
1411 sal_Bool bTransparent
= ( ( nRed
== mnTransRed
)
1412 && ( nGreen
== mnTransGreen
)
1413 && ( nBlue
== mnTransBlue
) );
1415 ImplSetTranspPixel( nY
, nX
, BitmapColor( mpColorTable
[ nRed
],
1416 mpColorTable
[ nGreen
],
1417 mpColorTable
[ nBlue
] ), bTransparent
);
1421 else // has RGB but neither alpha nor transparency
1422 { // BMP_FORMAT_24BIT_TC_RGB
1423 if ( mnPngDepth
== 8 ) // maybe the source has 16 bit per sample
1425 if ( mpColorTable
!= mpDefaultColorTable
)
1427 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 3 )
1428 ImplSetPixel( nY
, nX
, BitmapColor( mpColorTable
[ pTmp
[ 0 ] ],
1429 mpColorTable
[ pTmp
[ 1 ] ],
1430 mpColorTable
[ pTmp
[ 2 ] ] ) );
1434 if( nXAdd
== 1 && mnPreviewShift
== 0 ) // copy raw line data if possible
1436 int nLineBytes
= maOrigSize
.Width() * 3;
1437 mpAcc
->CopyScanline( nY
, pTmp
, BMP_FORMAT_24BIT_TC_RGB
, nLineBytes
);
1442 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 3 )
1443 ImplSetPixel( nY
, nX
, BitmapColor( pTmp
[0], pTmp
[1], pTmp
[2] ) );
1448 { // BMP_FORMAT_48BIT_TC_RGB
1449 for ( sal_Int32 nX
= nXStart
; nX
< maOrigSize
.Width(); nX
+= nXAdd
, pTmp
+= 6 )
1450 ImplSetPixel( nY
, nX
, BitmapColor( mpColorTable
[ pTmp
[ 0 ] ],
1451 mpColorTable
[ pTmp
[ 2 ] ],
1452 mpColorTable
[ pTmp
[ 4 ] ] ) );
1458 // ------------------------------------------------------------------------
1460 void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY
, sal_uInt32 nX
, const BitmapColor
& rBitmapColor
)
1462 // TODO: get preview mode checks out of inner loop
1463 if( nX
& mnPreviewMask
)
1465 nX
>>= mnPreviewShift
;
1467 mpAcc
->SetPixel( nY
, nX
, rBitmapColor
);
1470 // ------------------------------------------------------------------------
1472 void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY
, sal_uInt32 nX
, BYTE nPalIndex
)
1474 // TODO: get preview mode checks out of inner loop
1475 if( nX
& mnPreviewMask
)
1477 nX
>>= mnPreviewShift
;
1479 mpAcc
->SetPixel( nY
, nX
, nPalIndex
);
1482 // ------------------------------------------------------------------------
1484 void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY
, sal_uInt32 nX
, const BitmapColor
& rBitmapColor
, BOOL bTrans
)
1486 // TODO: get preview mode checks out of inner loop
1487 if( nX
& mnPreviewMask
)
1489 nX
>>= mnPreviewShift
;
1491 mpAcc
->SetPixel( nY
, nX
, rBitmapColor
);
1494 mpMaskAcc
->SetPixel( nY
, nX
, mcTranspColor
);
1496 mpMaskAcc
->SetPixel( nY
, nX
, mcOpaqueColor
);
1499 // ------------------------------------------------------------------------
1501 void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY
, sal_uInt32 nX
,
1502 BYTE nPalIndex
, BYTE nAlpha
)
1504 // TODO: get preview mode checks out of inner loop
1505 if( nX
& mnPreviewMask
)
1507 nX
>>= mnPreviewShift
;
1509 mpAcc
->SetPixel( nY
, nX
, nPalIndex
);
1510 mpMaskAcc
->SetPixel( nY
, nX
, ~nAlpha
);
1513 // ------------------------------------------------------------------------
1515 void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY
, sal_uInt32 nX
,
1516 const BitmapColor
& rBitmapColor
, BYTE nAlpha
)
1518 // TODO: get preview mode checks out of inner loop
1519 if( nX
& mnPreviewMask
)
1521 nX
>>= mnPreviewShift
;
1523 mpAcc
->SetPixel( nY
, nX
, rBitmapColor
);
1524 mpMaskAcc
->SetPixel( nY
, nX
, ~nAlpha
);
1527 // ------------------------------------------------------------------------
1529 sal_uInt32
PNGReaderImpl::ImplReadsal_uInt32()
1532 nRet
= *maDataIter
++;
1534 nRet
|= *maDataIter
++;
1536 nRet
|= *maDataIter
++;
1538 nRet
|= *maDataIter
++;
1542 // ------------------------------------------------------------------------
1548 PNGReader::PNGReader( SvStream
& rIStm
) :
1549 mpImpl( new ::vcl::PNGReaderImpl( rIStm
) )
1553 // ------------------------------------------------------------------------
1555 PNGReader::~PNGReader()
1560 // ------------------------------------------------------------------------
1562 BitmapEx
PNGReader::Read( const Size
& i_rPreviewSizeHint
)
1564 return mpImpl
->GetBitmapEx( i_rPreviewSizeHint
);
1567 // ------------------------------------------------------------------------
1569 const std::vector
< vcl::PNGReader::ChunkData
>& PNGReader::GetChunks() const
1571 return mpImpl
->GetAllChunks();
1574 // ------------------------------------------------------------------------
1576 void PNGReader::SetIgnoreGammaChunk( sal_Bool b
)
1578 mpImpl
->SetIgnoreGammaChunk( b
);