xref: /trunk/main/vcl/source/gdi/pngread.cxx (revision 6bcc9fe0e9ad8e3adcad10b35c622961480f57f3)
19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
229f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_vcl.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <vcl/pngread.hxx>
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <cmath>
30cdf0e10cSrcweir #include <rtl/crc.h>
31cdf0e10cSrcweir #include <rtl/memory.h>
32cdf0e10cSrcweir #include <rtl/alloc.h>
33cdf0e10cSrcweir #include <tools/zcodec.hxx>
34cdf0e10cSrcweir #include <tools/stream.hxx>
35cdf0e10cSrcweir #include <vcl/bmpacc.hxx>
36cdf0e10cSrcweir #include <vcl/svapp.hxx>
37cdf0e10cSrcweir #include <vcl/alpha.hxx>
38cdf0e10cSrcweir #include <osl/endian.h>
39cbfee35eSDamjan Jovanovic #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
40cdf0e10cSrcweir 
41cdf0e10cSrcweir // -----------
42cdf0e10cSrcweir // - Defines -
43cdf0e10cSrcweir // -----------
44cdf0e10cSrcweir 
45cdf0e10cSrcweir #define PNGCHUNK_IHDR       0x49484452
46cdf0e10cSrcweir #define PNGCHUNK_PLTE       0x504c5445
47cdf0e10cSrcweir #define PNGCHUNK_IDAT       0x49444154
48cdf0e10cSrcweir #define PNGCHUNK_IEND       0x49454e44
49cdf0e10cSrcweir #define PNGCHUNK_bKGD       0x624b4744
50cdf0e10cSrcweir #define PNGCHUNK_cHRM       0x6348524d
51cdf0e10cSrcweir #define PNGCHUNK_gAMA       0x67414d41
52cdf0e10cSrcweir #define PNGCHUNK_hIST       0x68495354
53cdf0e10cSrcweir #define PNGCHUNK_pHYs       0x70485973
54cdf0e10cSrcweir #define PNGCHUNK_sBIT       0x73425420
55cdf0e10cSrcweir #define PNGCHUNK_tIME       0x74494d45
56cdf0e10cSrcweir #define PNGCHUNK_tEXt       0x74455874
57cdf0e10cSrcweir #define PNGCHUNK_tRNS       0x74524e53
58cdf0e10cSrcweir #define PNGCHUNK_zTXt       0x7a545874
59cdf0e10cSrcweir #define PMGCHUNG_msOG       0x6d734f47      // Microsoft Office Animated GIF
60cdf0e10cSrcweir 
61cdf0e10cSrcweir #define VIEWING_GAMMA       2.35
62cdf0e10cSrcweir #define DISPLAY_GAMMA       1.0
63cdf0e10cSrcweir 
64cdf0e10cSrcweir namespace vcl
65cdf0e10cSrcweir {
66cdf0e10cSrcweir // -----------
67cdf0e10cSrcweir // - statics -
68cdf0e10cSrcweir // -----------
69cdf0e10cSrcweir 
70cdf0e10cSrcweir // ------------------------------------------------------------------------------
71cdf0e10cSrcweir 
72cdf0e10cSrcweir static const sal_uInt8 mpDefaultColorTable[ 256 ] =
73cdf0e10cSrcweir {   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
74cdf0e10cSrcweir     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
75cdf0e10cSrcweir     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
76cdf0e10cSrcweir     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
77cdf0e10cSrcweir     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
78cdf0e10cSrcweir     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
79cdf0e10cSrcweir     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
80cdf0e10cSrcweir     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
81cdf0e10cSrcweir     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
82cdf0e10cSrcweir     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
83cdf0e10cSrcweir     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
84cdf0e10cSrcweir     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
85cdf0e10cSrcweir     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
86cdf0e10cSrcweir     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
87cdf0e10cSrcweir     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
88cdf0e10cSrcweir     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
89cdf0e10cSrcweir };
90cdf0e10cSrcweir 
91cdf0e10cSrcweir // -------------
92cdf0e10cSrcweir // - PNGReaderImpl -
93cdf0e10cSrcweir // -------------
94cdf0e10cSrcweir 
95cdf0e10cSrcweir class PNGReaderImpl
96cdf0e10cSrcweir {
97cdf0e10cSrcweir private:
98cdf0e10cSrcweir     SvStream&           mrPNGStream;
99cdf0e10cSrcweir     sal_uInt16          mnOrigStreamMode;
100cdf0e10cSrcweir 
101cdf0e10cSrcweir     std::vector< vcl::PNGReader::ChunkData >    maChunkSeq;
102cdf0e10cSrcweir     std::vector< vcl::PNGReader::ChunkData >::iterator maChunkIter;
103cdf0e10cSrcweir     std::vector< sal_uInt8 >::iterator          maDataIter;
104cdf0e10cSrcweir 
105cdf0e10cSrcweir     Bitmap*             mpBmp;
106cdf0e10cSrcweir     BitmapWriteAccess*  mpAcc;
107cdf0e10cSrcweir     Bitmap*             mpMaskBmp;
108cdf0e10cSrcweir     AlphaMask*          mpAlphaMask;
109cdf0e10cSrcweir     BitmapWriteAccess*  mpMaskAcc;
110cdf0e10cSrcweir     ZCodec*             mpZCodec;
111cdf0e10cSrcweir     sal_uInt8*              mpInflateInBuf; // as big as the size of a scanline + alphachannel + 1
112cdf0e10cSrcweir     sal_uInt8*              mpScanPrior;    // pointer to the latest scanline
113cdf0e10cSrcweir     sal_uInt8*              mpTransTab;     // for transparency in images with palette colortype
114cdf0e10cSrcweir     sal_uInt8*              mpScanCurrent;  // pointer into the current scanline
115cdf0e10cSrcweir     sal_uInt8*              mpColorTable;   //
116cdf0e10cSrcweir     sal_Size            mnStreamSize;   // estimate of PNG file size
117cdf0e10cSrcweir     sal_uInt32          mnChunkType;    // Type of current PNG chunk
118cdf0e10cSrcweir     sal_Int32           mnChunkLen;     // Length of current PNG chunk
119cdf0e10cSrcweir     Size                maOrigSize;     // pixel size of the full image
120cdf0e10cSrcweir     Size                maTargetSize;   // pixel size of the result image
12186e1cf34SPedro Giffuni     Size                maPhysSize;     // preferred size in MAP_100TH_MM units
122cdf0e10cSrcweir     sal_uInt32          mnBPP;          // number of bytes per pixel
123cdf0e10cSrcweir     sal_uInt32          mnScansize;     // max size of scanline
124cdf0e10cSrcweir     sal_uInt32          mnYpos;         // latest y position in full image
125cdf0e10cSrcweir     int                 mnPass;         // if interlaced the latest pass ( 1..7 ) else 7
126cdf0e10cSrcweir     sal_uInt32          mnXStart;       // the starting X for the current pass
127cdf0e10cSrcweir     sal_uInt32          mnXAdd;         // the increment for input images X coords for the current pass
128cdf0e10cSrcweir     sal_uInt32          mnYAdd;         // the increment for input images Y coords for the current pass
129cdf0e10cSrcweir     int                 mnPreviewShift; // shift to convert orig image coords into preview image coords
130cdf0e10cSrcweir     int                 mnPreviewMask;  // == ((1 << mnPreviewShift) - 1)
131cdf0e10cSrcweir     sal_uInt16              mnIStmOldMode;
132cdf0e10cSrcweir     sal_uInt16              mnTargetDepth;      // pixel depth of target bitmap
133cdf0e10cSrcweir     sal_uInt8               mnTransRed;
134cdf0e10cSrcweir     sal_uInt8               mnTransGreen;
135cdf0e10cSrcweir     sal_uInt8               mnTransBlue;
136cdf0e10cSrcweir     sal_uInt8               mnPngDepth;     // pixel depth of PNG data
137cdf0e10cSrcweir     sal_uInt8               mnColorType;
138cdf0e10cSrcweir     sal_uInt8               mnCompressionType;
139cdf0e10cSrcweir     sal_uInt8               mnFilterType;
140cdf0e10cSrcweir     sal_uInt8               mnInterlaceType;
141cdf0e10cSrcweir     BitmapColor         mcTranspColor;  // transparency mask's transparency "color"
142cdf0e10cSrcweir     BitmapColor         mcOpaqueColor;  // transparency mask's opaque "color"
143cdf0e10cSrcweir     sal_Bool                mbTransparent;  // graphic includes an tRNS Chunk or an alpha Channel
144cdf0e10cSrcweir     sal_Bool                mbAlphaChannel; // is true for ColorType 4 and 6
145cdf0e10cSrcweir     sal_Bool                mbRGBTriple;
146cdf0e10cSrcweir     sal_Bool                mbPalette;      // sal_False if we need a Palette
147cdf0e10cSrcweir     sal_Bool                mbGrayScale;
148cdf0e10cSrcweir     sal_Bool                mbzCodecInUse;
149cdf0e10cSrcweir     sal_Bool                mbStatus;
150cdf0e10cSrcweir     sal_Bool                mbIDAT;         // sal_True if finished with enough IDAT chunks
151cdf0e10cSrcweir     sal_Bool                mbGamma;        // sal_True if Gamma Correction available
152cdf0e10cSrcweir     sal_Bool                mbpHYs;         // sal_True if pysical size of pixel available
153cdf0e10cSrcweir     sal_Bool            mbIgnoreGammaChunk;
154cdf0e10cSrcweir 
15588b53a7cSArmin Le Grand #ifdef DBG_UTIL
15688b53a7cSArmin Le Grand     // do some checks in debug mode
15788b53a7cSArmin Le Grand     sal_uInt32          mnAllocSizeScanline;
15888b53a7cSArmin Le Grand     sal_uInt32          mnAllocSizeScanlineAlpha;
15988b53a7cSArmin Le Grand #endif
16088b53a7cSArmin Le Grand     // the temporary Scanline (and alpha) for direct scanline copy to Bitmap
16188b53a7cSArmin Le Grand     sal_uInt8*          mpScanline;
16288b53a7cSArmin Le Grand     sal_uInt8*          mpScanlineAlpha;
16388b53a7cSArmin Le Grand 
164cdf0e10cSrcweir     bool                ReadNextChunk();
165cdf0e10cSrcweir     void                ReadRemainingChunks();
166cdf0e10cSrcweir     void                SkipRemainingChunks();
167cdf0e10cSrcweir 
168cdf0e10cSrcweir     void                ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor & );
169cdf0e10cSrcweir     void                ImplSetPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex );
170cdf0e10cSrcweir     void                ImplSetTranspPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, sal_Bool bTrans );
171cdf0e10cSrcweir     void                ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex, sal_uInt8 nAlpha );
172cdf0e10cSrcweir     void                ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor&, sal_uInt8 nAlpha );
173cdf0e10cSrcweir     void                ImplReadIDAT();
174cdf0e10cSrcweir     bool                ImplPreparePass();
175cdf0e10cSrcweir     void                ImplApplyFilter();
176cdf0e10cSrcweir     void                ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd );
177cdf0e10cSrcweir     sal_Bool                ImplReadTransparent();
178cdf0e10cSrcweir     void                ImplGetGamma();
179cdf0e10cSrcweir     void                ImplGetBackground();
180cdf0e10cSrcweir     sal_uInt8               ImplScaleColor();
181cdf0e10cSrcweir     sal_Bool                ImplReadHeader( const Size& rPreviewSizeHint );
182cdf0e10cSrcweir     sal_Bool                ImplReadPalette();
183cdf0e10cSrcweir     void                ImplGetGrayPalette( sal_uInt16 );
184cdf0e10cSrcweir     sal_uInt32          ImplReadsal_uInt32();
185cdf0e10cSrcweir 
186cdf0e10cSrcweir public:
187cdf0e10cSrcweir 
188cdf0e10cSrcweir                         PNGReaderImpl( SvStream& );
189cdf0e10cSrcweir                         ~PNGReaderImpl();
190cdf0e10cSrcweir 
191cdf0e10cSrcweir     BitmapEx            GetBitmapEx( const Size& rPreviewSizeHint );
192cdf0e10cSrcweir     const std::vector< PNGReader::ChunkData >& GetAllChunks();
193cdf0e10cSrcweir     void                SetIgnoreGammaChunk( sal_Bool bIgnore ){ mbIgnoreGammaChunk = bIgnore; };
194cdf0e10cSrcweir };
195cdf0e10cSrcweir 
196cdf0e10cSrcweir // ------------------------------------------------------------------------------
197cdf0e10cSrcweir 
198cdf0e10cSrcweir PNGReaderImpl::PNGReaderImpl( SvStream& rPNGStream )
199cdf0e10cSrcweir :   mrPNGStream( rPNGStream ),
200cdf0e10cSrcweir     mpBmp           ( NULL ),
201cdf0e10cSrcweir     mpAcc           ( NULL ),
202cdf0e10cSrcweir     mpMaskBmp       ( NULL ),
203cdf0e10cSrcweir     mpAlphaMask     ( NULL ),
204cdf0e10cSrcweir     mpMaskAcc       ( NULL ),
205cdf0e10cSrcweir     mpZCodec        ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
206cdf0e10cSrcweir     mpInflateInBuf  ( NULL ),
207cdf0e10cSrcweir     mpScanPrior     ( NULL ),
208cdf0e10cSrcweir     mpTransTab      ( NULL ),
209cdf0e10cSrcweir     mpColorTable    ( (sal_uInt8*) mpDefaultColorTable ),
2103447fe24SHerbert Dürr     mnColorType( 0xFF ),
2113447fe24SHerbert Dürr     mbPalette( false ),
212cdf0e10cSrcweir     mbzCodecInUse   ( sal_False ),
213cdf0e10cSrcweir     mbStatus( sal_True),
214cdf0e10cSrcweir     mbIDAT( sal_False ),
215cdf0e10cSrcweir     mbGamma             ( sal_False ),
216cdf0e10cSrcweir     mbpHYs              ( sal_False ),
21788b53a7cSArmin Le Grand     mbIgnoreGammaChunk  ( sal_False ),
21888b53a7cSArmin Le Grand #ifdef DBG_UTIL
21988b53a7cSArmin Le Grand     mnAllocSizeScanline(0),
22088b53a7cSArmin Le Grand     mnAllocSizeScanlineAlpha(0),
22188b53a7cSArmin Le Grand #endif
22288b53a7cSArmin Le Grand     mpScanline(0),
22388b53a7cSArmin Le Grand     mpScanlineAlpha(0)
224cdf0e10cSrcweir {
225cdf0e10cSrcweir     // prepare the PNG data stream
226cdf0e10cSrcweir     mnOrigStreamMode = mrPNGStream.GetNumberFormatInt();
227cdf0e10cSrcweir     mrPNGStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
228cdf0e10cSrcweir 
229cdf0e10cSrcweir     // prepare the chunk reader
230cdf0e10cSrcweir     maChunkSeq.reserve( 16 );
231cdf0e10cSrcweir     maChunkIter = maChunkSeq.begin();
232cdf0e10cSrcweir 
233cdf0e10cSrcweir     // estimate PNG file size (to allow sanity checks)
234cdf0e10cSrcweir     const sal_Size nStreamPos = mrPNGStream.Tell();
235cdf0e10cSrcweir     mrPNGStream.Seek( STREAM_SEEK_TO_END );
236cdf0e10cSrcweir     mnStreamSize = mrPNGStream.Tell();
237cdf0e10cSrcweir     mrPNGStream.Seek( nStreamPos );
238cdf0e10cSrcweir 
239cdf0e10cSrcweir     // check the PNG header magic
240cdf0e10cSrcweir     sal_uInt32 nDummy = 0;
241cdf0e10cSrcweir     mrPNGStream >> nDummy;
242cdf0e10cSrcweir     mbStatus = (nDummy == 0x89504e47);
243cdf0e10cSrcweir     mrPNGStream >> nDummy;
244cdf0e10cSrcweir     mbStatus &= (nDummy == 0x0d0a1a0a);
245cdf0e10cSrcweir 
246cdf0e10cSrcweir     mnPreviewShift = 0;
247cdf0e10cSrcweir     mnPreviewMask = (1 << mnPreviewShift) - 1;
248cdf0e10cSrcweir }
249cdf0e10cSrcweir 
250cdf0e10cSrcweir // ------------------------------------------------------------------------
251cdf0e10cSrcweir 
252cdf0e10cSrcweir PNGReaderImpl::~PNGReaderImpl()
253cdf0e10cSrcweir {
254cdf0e10cSrcweir     mrPNGStream.SetNumberFormatInt( mnOrigStreamMode );
255cdf0e10cSrcweir 
256cdf0e10cSrcweir     if ( mbzCodecInUse )
257cdf0e10cSrcweir         mpZCodec->EndCompression();
258cdf0e10cSrcweir 
259cdf0e10cSrcweir     if( mpColorTable != mpDefaultColorTable )
260cdf0e10cSrcweir         delete[] mpColorTable;
261cdf0e10cSrcweir 
262cdf0e10cSrcweir     delete mpBmp;
263cdf0e10cSrcweir     delete mpAlphaMask;
264cdf0e10cSrcweir     delete mpMaskBmp;
265cdf0e10cSrcweir     delete[] mpTransTab;
266cdf0e10cSrcweir     delete[] mpInflateInBuf;
267cdf0e10cSrcweir     delete[] mpScanPrior;
268cdf0e10cSrcweir     delete mpZCodec;
26988b53a7cSArmin Le Grand 
27088b53a7cSArmin Le Grand     delete[] mpScanline;
27188b53a7cSArmin Le Grand     delete[] mpScanlineAlpha;
272cdf0e10cSrcweir }
273cdf0e10cSrcweir 
274cdf0e10cSrcweir // ------------------------------------------------------------------------
275cdf0e10cSrcweir 
276cdf0e10cSrcweir bool PNGReaderImpl::ReadNextChunk()
277cdf0e10cSrcweir {
278cdf0e10cSrcweir     if( maChunkIter == maChunkSeq.end() )
279cdf0e10cSrcweir     {
280cdf0e10cSrcweir         // get the next chunk from the stream
281cdf0e10cSrcweir 
282cdf0e10cSrcweir         // unless we are at the end of the PNG stream
283cdf0e10cSrcweir         if( mrPNGStream.IsEof() || (mrPNGStream.GetError() != ERRCODE_NONE) )
284cdf0e10cSrcweir             return false;
285cdf0e10cSrcweir         if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
286cdf0e10cSrcweir             return false;
287cdf0e10cSrcweir 
288cdf0e10cSrcweir         PNGReader::ChunkData aDummyChunk;
289cdf0e10cSrcweir         maChunkIter = maChunkSeq.insert( maChunkSeq.end(), aDummyChunk );
290cdf0e10cSrcweir         PNGReader::ChunkData& rChunkData = *maChunkIter;
291cdf0e10cSrcweir 
292cdf0e10cSrcweir         // read the chunk header
293cdf0e10cSrcweir         mrPNGStream >> mnChunkLen >> mnChunkType;
294cdf0e10cSrcweir         rChunkData.nType = mnChunkType;
295cdf0e10cSrcweir 
296cdf0e10cSrcweir         // #128377#/#149343# sanity check for chunk length
297cdf0e10cSrcweir         if( mnChunkLen < 0 )
298cdf0e10cSrcweir             return false;
299cdf0e10cSrcweir         const sal_Size nStreamPos = mrPNGStream.Tell();
300cbfee35eSDamjan Jovanovic         if( nStreamPos + mnChunkLen + 4 >= mnStreamSize )
301cdf0e10cSrcweir             return false;
302cdf0e10cSrcweir 
303cdf0e10cSrcweir         // calculate chunktype CRC (swap it back to original byte order)
304*6bcc9fe0Smseidel         sal_uInt32 nChunkType = mnChunkType;
305cdf0e10cSrcweir         #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
306cdf0e10cSrcweir         nChunkType = SWAPLONG( nChunkType );
307cdf0e10cSrcweir         #endif
308cdf0e10cSrcweir         sal_uInt32 nCRC32 = rtl_crc32( 0, &nChunkType, 4 );
309cdf0e10cSrcweir 
310cdf0e10cSrcweir         // read the chunk data and check the CRC
311cdf0e10cSrcweir         if( mnChunkLen && !mrPNGStream.IsEof() )
312cdf0e10cSrcweir         {
313cdf0e10cSrcweir             rChunkData.aData.resize( mnChunkLen );
314cdf0e10cSrcweir 
315cdf0e10cSrcweir             sal_Int32 nBytesRead = 0;
316cdf0e10cSrcweir             do {
317cdf0e10cSrcweir                 sal_uInt8* pPtr = &rChunkData.aData[ nBytesRead ];
318cdf0e10cSrcweir                 nBytesRead += mrPNGStream.Read( pPtr, mnChunkLen - nBytesRead );
319cdf0e10cSrcweir             } while ( ( nBytesRead < mnChunkLen ) && ( mrPNGStream.GetError() == ERRCODE_NONE ) );
320cdf0e10cSrcweir 
321cdf0e10cSrcweir             nCRC32 = rtl_crc32( nCRC32, &rChunkData.aData[ 0 ], mnChunkLen );
322cdf0e10cSrcweir             maDataIter = rChunkData.aData.begin();
323cdf0e10cSrcweir         }
324cdf0e10cSrcweir         sal_uInt32 nCheck;
325cdf0e10cSrcweir         mrPNGStream >> nCheck;
326cdf0e10cSrcweir         if( nCRC32 != nCheck )
327cdf0e10cSrcweir             return false;
328cdf0e10cSrcweir     }
329cdf0e10cSrcweir     else
330cdf0e10cSrcweir     {
331cdf0e10cSrcweir         // the next chunk was already read
332cdf0e10cSrcweir         mnChunkType = (*maChunkIter).nType;
333cdf0e10cSrcweir         mnChunkLen = (*maChunkIter).aData.size();
334cdf0e10cSrcweir         maDataIter = (*maChunkIter).aData.begin();
335cdf0e10cSrcweir     }
336cdf0e10cSrcweir 
337cdf0e10cSrcweir     ++maChunkIter;
338cdf0e10cSrcweir     if( mnChunkType == PNGCHUNK_IEND )
339cdf0e10cSrcweir         return false;
340cdf0e10cSrcweir     return true;
341cdf0e10cSrcweir }
342cdf0e10cSrcweir 
343cdf0e10cSrcweir // ------------------------------------------------------------------------
344cdf0e10cSrcweir 
345cdf0e10cSrcweir // read the remaining chunks from mrPNGStream
346cdf0e10cSrcweir void PNGReaderImpl::ReadRemainingChunks()
347cdf0e10cSrcweir {
348cdf0e10cSrcweir     while( ReadNextChunk() ) ;
349cdf0e10cSrcweir }
350cdf0e10cSrcweir 
351cdf0e10cSrcweir // ------------------------------------------------------------------------
352cdf0e10cSrcweir 
353cdf0e10cSrcweir // move position of mrPNGStream to the end of the file
354cdf0e10cSrcweir void PNGReaderImpl::SkipRemainingChunks()
355cdf0e10cSrcweir {
356cdf0e10cSrcweir     // nothing to skip if the last chunk was read
357cdf0e10cSrcweir     if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
358cdf0e10cSrcweir         return;
359cdf0e10cSrcweir 
360cdf0e10cSrcweir     // read from the stream until the IEND chunk is found
361cdf0e10cSrcweir     const sal_Size nStreamPos = mrPNGStream.Tell();
362cdf0e10cSrcweir     while( !mrPNGStream.IsEof() && (mrPNGStream.GetError() == ERRCODE_NONE) )
363cdf0e10cSrcweir     {
364cdf0e10cSrcweir         mrPNGStream >> mnChunkLen >> mnChunkType;
365cdf0e10cSrcweir         if( mnChunkLen < 0 )
366cdf0e10cSrcweir             break;
367cdf0e10cSrcweir         if( nStreamPos + mnChunkLen >= mnStreamSize )
368cdf0e10cSrcweir             break;
369cdf0e10cSrcweir         mrPNGStream.SeekRel( mnChunkLen + 4 );  // skip data + CRC
370cdf0e10cSrcweir         if( mnChunkType == PNGCHUNK_IEND )
371cdf0e10cSrcweir             break;
372cdf0e10cSrcweir     }
373cdf0e10cSrcweir }
374cdf0e10cSrcweir 
375cdf0e10cSrcweir // ------------------------------------------------------------------------
376cdf0e10cSrcweir 
377cdf0e10cSrcweir const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks()
378cdf0e10cSrcweir {
379cdf0e10cSrcweir     ReadRemainingChunks();
380cdf0e10cSrcweir     return maChunkSeq;
381cdf0e10cSrcweir }
382cdf0e10cSrcweir 
383cdf0e10cSrcweir // ------------------------------------------------------------------------
384cdf0e10cSrcweir 
385cdf0e10cSrcweir BitmapEx PNGReaderImpl::GetBitmapEx( const Size& rPreviewSizeHint )
386cdf0e10cSrcweir {
387cdf0e10cSrcweir     // reset to the first chunk
388cdf0e10cSrcweir     maChunkIter = maChunkSeq.begin();
389cdf0e10cSrcweir 
3903447fe24SHerbert Dürr     // read the first chunk which must be the IHDR chunk
3913447fe24SHerbert Dürr     ReadNextChunk();
3923447fe24SHerbert Dürr     mbStatus = (mnChunkType == PNGCHUNK_IHDR) && ImplReadHeader( rPreviewSizeHint );
3933447fe24SHerbert Dürr 
394cdf0e10cSrcweir     // parse the chunks
395cdf0e10cSrcweir     while( mbStatus && !mbIDAT && ReadNextChunk() )
396cdf0e10cSrcweir     {
397cdf0e10cSrcweir         switch( mnChunkType )
398cdf0e10cSrcweir         {
399cdf0e10cSrcweir             case PNGCHUNK_IHDR :
400cdf0e10cSrcweir             {
4013447fe24SHerbert Dürr                 mbStatus = false; // only one IHDR possible
402cdf0e10cSrcweir             }
403cdf0e10cSrcweir             break;
404cdf0e10cSrcweir 
405cdf0e10cSrcweir             case PNGCHUNK_gAMA :                                // the gamma chunk must precede
406cdf0e10cSrcweir             {                                                   // the 'IDAT' and also the 'PLTE'(if available )
407cdf0e10cSrcweir                 if ( !mbIgnoreGammaChunk && ( mbIDAT == sal_False ) )
408cdf0e10cSrcweir                     ImplGetGamma();
409cdf0e10cSrcweir             }
410cdf0e10cSrcweir             break;
411cdf0e10cSrcweir 
412cdf0e10cSrcweir             case PNGCHUNK_PLTE :
413cdf0e10cSrcweir             {
414cdf0e10cSrcweir                 if ( !mbPalette )
415cdf0e10cSrcweir                     mbStatus = ImplReadPalette();
416cdf0e10cSrcweir             }
417cdf0e10cSrcweir             break;
418cdf0e10cSrcweir 
419cdf0e10cSrcweir             case PNGCHUNK_tRNS :
420cdf0e10cSrcweir             {
421cdf0e10cSrcweir                 if ( !mbIDAT )                                  // the tRNS chunk must precede the IDAT
422cdf0e10cSrcweir                     mbStatus = ImplReadTransparent();
423cdf0e10cSrcweir             }
424cdf0e10cSrcweir             break;
425cdf0e10cSrcweir 
426cdf0e10cSrcweir             case PNGCHUNK_bKGD :                                // the background chunk must appear
427cdf0e10cSrcweir             {
428cdf0e10cSrcweir                 if ( ( mbIDAT == sal_False ) && mbPalette )         // before the 'IDAT' and after the
429cdf0e10cSrcweir                     ImplGetBackground();                        // PLTE(if available ) chunk.
430cdf0e10cSrcweir             }
431cdf0e10cSrcweir             break;
432cdf0e10cSrcweir 
433cdf0e10cSrcweir             case PNGCHUNK_IDAT :
434cdf0e10cSrcweir             {
435cdf0e10cSrcweir                 if ( !mpInflateInBuf )  // taking care that the header has properly been read
436cdf0e10cSrcweir                     mbStatus = sal_False;
437cdf0e10cSrcweir                 else if ( !mbIDAT )     // the gfx is finished, but there may be left a zlibCRC of about 4Bytes
438cbfee35eSDamjan Jovanovic                 {
439cbfee35eSDamjan Jovanovic                     try
440cbfee35eSDamjan Jovanovic                     {
441cdf0e10cSrcweir                         ImplReadIDAT();
442cdf0e10cSrcweir                     }
443cbfee35eSDamjan Jovanovic                     catch (::com::sun::star::lang::IndexOutOfBoundsException&)
444cbfee35eSDamjan Jovanovic                     {
445cbfee35eSDamjan Jovanovic                         mbStatus = sal_False;
446cbfee35eSDamjan Jovanovic                     }
447cbfee35eSDamjan Jovanovic                 }
448cbfee35eSDamjan Jovanovic             }
449cdf0e10cSrcweir             break;
450cdf0e10cSrcweir 
451cdf0e10cSrcweir             case PNGCHUNK_pHYs :
452cdf0e10cSrcweir             {
453cdf0e10cSrcweir                 if ( !mbIDAT && mnChunkLen == 9 )
454cdf0e10cSrcweir                 {
455cdf0e10cSrcweir                     sal_uInt32 nXPixelPerMeter = ImplReadsal_uInt32();
456cdf0e10cSrcweir                     sal_uInt32 nYPixelPerMeter = ImplReadsal_uInt32();
457cdf0e10cSrcweir 
458cdf0e10cSrcweir                     sal_uInt8 nUnitSpecifier = *maDataIter++;
459cdf0e10cSrcweir                     if( (nUnitSpecifier == 1) && nXPixelPerMeter && nXPixelPerMeter )
460cdf0e10cSrcweir                     {
461cdf0e10cSrcweir                         mbpHYs = sal_True;
462cdf0e10cSrcweir 
463cdf0e10cSrcweir                         // convert into MAP_100TH_MM
464cdf0e10cSrcweir                         maPhysSize.Width()  = (sal_Int32)( (100000.0 * maOrigSize.Width()) / nXPixelPerMeter );
465cdf0e10cSrcweir                         maPhysSize.Height() = (sal_Int32)( (100000.0 * maOrigSize.Height()) / nYPixelPerMeter );
466cdf0e10cSrcweir                     }
467cdf0e10cSrcweir                 }
468cdf0e10cSrcweir             }
469cdf0e10cSrcweir             break;
470cdf0e10cSrcweir 
471cdf0e10cSrcweir             case PNGCHUNK_IEND:
472cdf0e10cSrcweir                 mbStatus = mbIDAT;  // there is a problem if the image is not complete yet
473cdf0e10cSrcweir             break;
474cdf0e10cSrcweir         }
475cdf0e10cSrcweir     }
476cdf0e10cSrcweir 
477cdf0e10cSrcweir     // release write access of the bitmaps
478cdf0e10cSrcweir     if ( mpAcc )
479cdf0e10cSrcweir         mpBmp->ReleaseAccess( mpAcc ), mpAcc = NULL;
480cdf0e10cSrcweir 
481cdf0e10cSrcweir     if ( mpMaskAcc )
482cdf0e10cSrcweir     {
483cdf0e10cSrcweir         if ( mpAlphaMask )
484cdf0e10cSrcweir             mpAlphaMask->ReleaseAccess( mpMaskAcc );
485cdf0e10cSrcweir         else if ( mpMaskBmp )
486cdf0e10cSrcweir             mpMaskBmp->ReleaseAccess( mpMaskAcc );
487cdf0e10cSrcweir 
488cdf0e10cSrcweir         mpMaskAcc = NULL;
489cdf0e10cSrcweir     }
490cdf0e10cSrcweir 
491cdf0e10cSrcweir     // return the resulting BitmapEx
492cdf0e10cSrcweir     BitmapEx aRet;
493cdf0e10cSrcweir 
494cdf0e10cSrcweir     if( !mbStatus || !mbIDAT )
495cdf0e10cSrcweir         aRet.Clear();
496cdf0e10cSrcweir     else
497cdf0e10cSrcweir     {
498cdf0e10cSrcweir         if ( mpAlphaMask )
499cdf0e10cSrcweir             aRet = BitmapEx( *mpBmp, *mpAlphaMask );
500cdf0e10cSrcweir         else if ( mpMaskBmp )
501cdf0e10cSrcweir             aRet = BitmapEx( *mpBmp, *mpMaskBmp );
502cdf0e10cSrcweir         else
503cdf0e10cSrcweir             aRet = *mpBmp;
504cdf0e10cSrcweir 
505cdf0e10cSrcweir         if ( mbpHYs && maPhysSize.Width() && maPhysSize.Height() )
506cdf0e10cSrcweir         {
507cdf0e10cSrcweir             aRet.SetPrefMapMode( MAP_100TH_MM );
508cdf0e10cSrcweir             aRet.SetPrefSize( maPhysSize );
509cdf0e10cSrcweir         }
510cdf0e10cSrcweir 
511cdf0e10cSrcweir #if 0
512cdf0e10cSrcweir         // TODO: make sure nobody depends on the stream being after the IEND chunks
513cdf0e10cSrcweir         // => let them do ReadChunks before
514cdf0e10cSrcweir         ReadRemainingChunks();
515cdf0e10cSrcweir #endif
516cdf0e10cSrcweir     }
517cdf0e10cSrcweir 
518cdf0e10cSrcweir     return aRet;
519cdf0e10cSrcweir }
520cdf0e10cSrcweir 
521cdf0e10cSrcweir // ------------------------------------------------------------------------
522cdf0e10cSrcweir 
523cdf0e10cSrcweir sal_Bool PNGReaderImpl::ImplReadHeader( const Size& rPreviewSizeHint )
524cdf0e10cSrcweir {
525cdf0e10cSrcweir     if( mnChunkLen < 13 )
526cdf0e10cSrcweir         return sal_False;
527cdf0e10cSrcweir 
528cdf0e10cSrcweir     maOrigSize.Width()  = ImplReadsal_uInt32();
529cdf0e10cSrcweir     maOrigSize.Height() = ImplReadsal_uInt32();
530cdf0e10cSrcweir 
531cdf0e10cSrcweir     if ( !maOrigSize.Width() || !maOrigSize.Height() )
532cdf0e10cSrcweir         return sal_False;
533cdf0e10cSrcweir 
534cdf0e10cSrcweir     mnPngDepth = *(maDataIter++);
535cdf0e10cSrcweir     mnColorType = *(maDataIter++);
536cdf0e10cSrcweir 
537cdf0e10cSrcweir     mnCompressionType = *(maDataIter++);
538cdf0e10cSrcweir     if( mnCompressionType != 0 )    // unknown compression type
539cdf0e10cSrcweir         return sal_False;
540cdf0e10cSrcweir 
541cdf0e10cSrcweir     mnFilterType = *(maDataIter++);
542cdf0e10cSrcweir     if( mnFilterType != 0 )         // unknown filter type
543cdf0e10cSrcweir         return sal_False;
544cdf0e10cSrcweir 
545cdf0e10cSrcweir     mnInterlaceType = *(maDataIter++);
546cdf0e10cSrcweir     switch ( mnInterlaceType ) // filter type valid ?
547cdf0e10cSrcweir     {
548cdf0e10cSrcweir         case 0 :  // progressive image
549cdf0e10cSrcweir             mnPass = 7;
550cdf0e10cSrcweir             break;
551cdf0e10cSrcweir         case 1 :  // Adam7-interlaced image
552cdf0e10cSrcweir             mnPass = 0;
553cdf0e10cSrcweir             break;
554cdf0e10cSrcweir         default:
555cdf0e10cSrcweir             return sal_False;
556cdf0e10cSrcweir     }
557cdf0e10cSrcweir 
558cdf0e10cSrcweir     mbPalette = sal_True;
559cdf0e10cSrcweir     mbIDAT = mbAlphaChannel = mbTransparent = sal_False;
560cdf0e10cSrcweir     mbGrayScale = mbRGBTriple = sal_False;
561cdf0e10cSrcweir     mnTargetDepth = mnPngDepth;
562cdf0e10cSrcweir     sal_uInt64 nScansize64 = ( ( static_cast< sal_uInt64 >( maOrigSize.Width() ) * mnPngDepth ) + 7 ) >> 3;
563cdf0e10cSrcweir 
564cdf0e10cSrcweir     // valid color types are 0,2,3,4 & 6
565cdf0e10cSrcweir     switch ( mnColorType )
566cdf0e10cSrcweir     {
567cdf0e10cSrcweir         case 0 :    // each pixel is a grayscale
568cdf0e10cSrcweir         {
569cdf0e10cSrcweir             switch ( mnPngDepth )
570cdf0e10cSrcweir             {
571cdf0e10cSrcweir                 case 2 : // 2bit target not available -> use four bits
572cdf0e10cSrcweir                     mnTargetDepth = 4;  // we have to expand the bitmap
573cdf0e10cSrcweir                     mbGrayScale = sal_True;
574cdf0e10cSrcweir                     break;
575cdf0e10cSrcweir                 case 16 :
576cdf0e10cSrcweir                     mnTargetDepth = 8;  // we have to reduce the bitmap
577cdf0e10cSrcweir                     // fall through
578cdf0e10cSrcweir                 case 1 :
579cdf0e10cSrcweir                 case 4 :
580cdf0e10cSrcweir                 case 8 :
581cdf0e10cSrcweir                     mbGrayScale = sal_True;
582cdf0e10cSrcweir                     break;
583cdf0e10cSrcweir                 default :
584cdf0e10cSrcweir                     return sal_False;
585cdf0e10cSrcweir             }
586cdf0e10cSrcweir         }
587cdf0e10cSrcweir         break;
588cdf0e10cSrcweir 
589cdf0e10cSrcweir         case 2 :    // each pixel is an RGB triple
590cdf0e10cSrcweir         {
591cdf0e10cSrcweir             mbRGBTriple = sal_True;
592cdf0e10cSrcweir             nScansize64 *= 3;
593cdf0e10cSrcweir             switch ( mnPngDepth )
594cdf0e10cSrcweir             {
595cdf0e10cSrcweir                 case 16 :           // we have to reduce the bitmap
596cdf0e10cSrcweir                 case 8 :
597cdf0e10cSrcweir                     mnTargetDepth = 24;
598cdf0e10cSrcweir                     break;
599cdf0e10cSrcweir                 default :
600cdf0e10cSrcweir                     return sal_False;
601cdf0e10cSrcweir             }
602cdf0e10cSrcweir         }
603cdf0e10cSrcweir         break;
604cdf0e10cSrcweir 
605cdf0e10cSrcweir         case 3 :    // each pixel is a palette index
606cdf0e10cSrcweir         {
607cdf0e10cSrcweir             switch ( mnPngDepth )
608cdf0e10cSrcweir             {
609cdf0e10cSrcweir                 case 2 :
610cdf0e10cSrcweir                     mnTargetDepth = 4;  // we have to expand the bitmap
611cdf0e10cSrcweir                     // fall through
612cdf0e10cSrcweir                 case 1 :
613cdf0e10cSrcweir                 case 4 :
614cdf0e10cSrcweir                 case 8 :
615cdf0e10cSrcweir                     mbPalette = sal_False;
616cdf0e10cSrcweir                     break;
617cdf0e10cSrcweir                 default :
618cdf0e10cSrcweir                     return sal_False;
619cdf0e10cSrcweir             }
620cdf0e10cSrcweir         }
621cdf0e10cSrcweir         break;
622cdf0e10cSrcweir 
623cdf0e10cSrcweir         case 4 :    // each pixel is a grayscale sample followed by an alpha sample
624cdf0e10cSrcweir         {
625cdf0e10cSrcweir             nScansize64 *= 2;
626cdf0e10cSrcweir             mbAlphaChannel = sal_True;
627cdf0e10cSrcweir             switch ( mnPngDepth )
628cdf0e10cSrcweir             {
629cdf0e10cSrcweir                 case 16 :
630cdf0e10cSrcweir                     mnTargetDepth = 8;  // we have to reduce the bitmap
631cdf0e10cSrcweir                 case 8 :
632cdf0e10cSrcweir                     mbGrayScale = sal_True;
633cdf0e10cSrcweir                     break;
634cdf0e10cSrcweir                 default :
635cdf0e10cSrcweir                     return sal_False;
636cdf0e10cSrcweir             }
637cdf0e10cSrcweir         }
638cdf0e10cSrcweir         break;
639cdf0e10cSrcweir 
640cdf0e10cSrcweir         case 6 :    // each pixel is an RGB triple followed by an alpha sample
641cdf0e10cSrcweir         {
642cdf0e10cSrcweir             mbRGBTriple = sal_True;
643cdf0e10cSrcweir             nScansize64 *= 4;
644cdf0e10cSrcweir             mbAlphaChannel = sal_True;
645cdf0e10cSrcweir             switch (mnPngDepth )
646cdf0e10cSrcweir             {
647cdf0e10cSrcweir                 case 16 :           // we have to reduce the bitmap
648cdf0e10cSrcweir                 case 8 :
649cdf0e10cSrcweir                     mnTargetDepth = 24;
650cdf0e10cSrcweir                     break;
651cdf0e10cSrcweir                 default :
652cdf0e10cSrcweir                     return sal_False;
653cdf0e10cSrcweir             }
654cdf0e10cSrcweir         }
655cdf0e10cSrcweir         break;
656cdf0e10cSrcweir 
657cdf0e10cSrcweir         default :
658cdf0e10cSrcweir             return sal_False;
659cdf0e10cSrcweir     }
660cdf0e10cSrcweir 
661cdf0e10cSrcweir     mnBPP = static_cast< sal_uInt32 >( nScansize64 / maOrigSize.Width() );
662cdf0e10cSrcweir     if ( !mnBPP )
663cdf0e10cSrcweir         mnBPP = 1;
664cdf0e10cSrcweir 
665cdf0e10cSrcweir     nScansize64++;       // each scanline includes one filterbyte
666cdf0e10cSrcweir 
667cdf0e10cSrcweir     if ( nScansize64 > SAL_MAX_UINT32 )
668cdf0e10cSrcweir         return sal_False;
669cdf0e10cSrcweir 
670cdf0e10cSrcweir     mnScansize = static_cast< sal_uInt32 >( nScansize64 );
671cdf0e10cSrcweir 
672cdf0e10cSrcweir     // TODO: switch between both scanlines instead of copying
673cdf0e10cSrcweir     mpInflateInBuf = new (std::nothrow) sal_uInt8[ mnScansize ];
674cdf0e10cSrcweir     mpScanCurrent = mpInflateInBuf;
675cdf0e10cSrcweir     mpScanPrior = new (std::nothrow) sal_uInt8[ mnScansize ];
676cdf0e10cSrcweir 
677cdf0e10cSrcweir     if ( !mpInflateInBuf || !mpScanPrior )
678cdf0e10cSrcweir         return sal_False;
679cdf0e10cSrcweir 
680cdf0e10cSrcweir     // calculate target size from original size and the preview hint
681cdf0e10cSrcweir     if( rPreviewSizeHint.Width() || rPreviewSizeHint.Height() )
682cdf0e10cSrcweir     {
683cdf0e10cSrcweir         Size aPreviewSize( rPreviewSizeHint.Width(), rPreviewSizeHint.Height() );
684cdf0e10cSrcweir         maTargetSize = maOrigSize;
685cdf0e10cSrcweir 
686cdf0e10cSrcweir         if( aPreviewSize.Width() == 0 ) {
687cdf0e10cSrcweir             aPreviewSize.setWidth( ( maOrigSize.Width()*aPreviewSize.Height() )/maOrigSize.Height() );
688cdf0e10cSrcweir             if( aPreviewSize.Width() <= 0 )
689cdf0e10cSrcweir                 aPreviewSize.setWidth( 1 );
690cdf0e10cSrcweir         } else if( aPreviewSize.Height() == 0 ) {
691cdf0e10cSrcweir             aPreviewSize.setHeight( ( maOrigSize.Height()*aPreviewSize.Width() )/maOrigSize.Width() );
692cdf0e10cSrcweir             if( aPreviewSize.Height() <= 0 )
693cdf0e10cSrcweir                 aPreviewSize.setHeight( 1 );
694cdf0e10cSrcweir         }
695cdf0e10cSrcweir 
696cdf0e10cSrcweir         if( aPreviewSize.Width() < maOrigSize.Width() && aPreviewSize.Height() < maOrigSize.Height() ) {
697cdf0e10cSrcweir             OSL_TRACE("preview size %dx%d", aPreviewSize.Width(), aPreviewSize.Height() );
698cdf0e10cSrcweir 
699cdf0e10cSrcweir             for( int i = 1; i < 5; ++i )
700cdf0e10cSrcweir                 {
701cdf0e10cSrcweir                     if( (maTargetSize.Width() >> i) < aPreviewSize.Width() )
702cdf0e10cSrcweir                         break;
703cdf0e10cSrcweir                     if( (maTargetSize.Height() >> i) < aPreviewSize.Height() )
704cdf0e10cSrcweir                         break;
705cdf0e10cSrcweir                     mnPreviewShift = i;
706cdf0e10cSrcweir                 }
707cdf0e10cSrcweir             mnPreviewMask = (1 << mnPreviewShift) - 1;
708cdf0e10cSrcweir         }
709cdf0e10cSrcweir     }
710cdf0e10cSrcweir 
711cdf0e10cSrcweir     maTargetSize.Width()  = (maOrigSize.Width() + mnPreviewMask) >> mnPreviewShift;
712cdf0e10cSrcweir     maTargetSize.Height() = (maOrigSize.Height() + mnPreviewMask) >> mnPreviewShift;
713cdf0e10cSrcweir 
714cdf0e10cSrcweir     mpBmp = new Bitmap( maTargetSize, mnTargetDepth );
715cdf0e10cSrcweir     mpAcc = mpBmp->AcquireWriteAccess();
716cdf0e10cSrcweir     if( !mpAcc )
717cdf0e10cSrcweir         return sal_False;
718cdf0e10cSrcweir 
719cdf0e10cSrcweir     mpBmp->SetSourceSizePixel( maOrigSize );
720cdf0e10cSrcweir 
721cdf0e10cSrcweir     if ( mbAlphaChannel )
722cdf0e10cSrcweir     {
723cdf0e10cSrcweir         mpAlphaMask = new AlphaMask( maTargetSize );
724cdf0e10cSrcweir         mpAlphaMask->Erase( 128 );
725cdf0e10cSrcweir         mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
726cdf0e10cSrcweir         if( !mpMaskAcc )
727cdf0e10cSrcweir             return sal_False;
728cdf0e10cSrcweir     }
729cdf0e10cSrcweir 
730cdf0e10cSrcweir     if ( mbGrayScale )
731cdf0e10cSrcweir         ImplGetGrayPalette( mnPngDepth );
732cdf0e10cSrcweir 
733cdf0e10cSrcweir     ImplPreparePass();
734cdf0e10cSrcweir 
735cdf0e10cSrcweir     return sal_True;
736cdf0e10cSrcweir }
737cdf0e10cSrcweir 
738cdf0e10cSrcweir // ------------------------------------------------------------------------
739cdf0e10cSrcweir 
740cdf0e10cSrcweir void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
741cdf0e10cSrcweir {
742cdf0e10cSrcweir     if( nBitDepth > 8 )
743cdf0e10cSrcweir         nBitDepth = 8;
744cdf0e10cSrcweir 
745cdf0e10cSrcweir     sal_uInt16  nPaletteEntryCount = 1 << nBitDepth;
746cdf0e10cSrcweir     sal_uInt32  nAdd = nBitDepth ? 256 / (nPaletteEntryCount - 1) : 0;
747cdf0e10cSrcweir 
748cdf0e10cSrcweir     // no bitdepth==2 available
749cdf0e10cSrcweir     // but bitdepth==4 with two unused bits is close enough
750cdf0e10cSrcweir     if( nBitDepth == 2 )
751cdf0e10cSrcweir         nPaletteEntryCount = 16;
752cdf0e10cSrcweir 
753cdf0e10cSrcweir     mpAcc->SetPaletteEntryCount( nPaletteEntryCount );
754cdf0e10cSrcweir     for ( sal_uInt32 i = 0, nStart = 0; nStart < 256; i++, nStart += nAdd )
755cdf0e10cSrcweir         mpAcc->SetPaletteColor( (sal_uInt16)i, BitmapColor( mpColorTable[ nStart ],
756cdf0e10cSrcweir             mpColorTable[ nStart ], mpColorTable[ nStart ] ) );
757cdf0e10cSrcweir }
758cdf0e10cSrcweir 
759cdf0e10cSrcweir // ------------------------------------------------------------------------
760cdf0e10cSrcweir 
761cdf0e10cSrcweir sal_Bool PNGReaderImpl::ImplReadPalette()
762cdf0e10cSrcweir {
763cdf0e10cSrcweir     sal_uInt16 nCount = static_cast<sal_uInt16>( mnChunkLen / 3 );
764cdf0e10cSrcweir 
765cdf0e10cSrcweir     if ( ( ( mnChunkLen % 3 ) == 0 ) && ( ( 0 < nCount ) && ( nCount <= 256 ) ) && mpAcc )
766cdf0e10cSrcweir     {
767cdf0e10cSrcweir         mbPalette = sal_True;
768cdf0e10cSrcweir         mpAcc->SetPaletteEntryCount( (sal_uInt16) nCount );
769cdf0e10cSrcweir 
770cdf0e10cSrcweir         for ( sal_uInt16 i = 0; i < nCount; i++ )
771cdf0e10cSrcweir         {
772cdf0e10cSrcweir             sal_uInt8 nRed =   mpColorTable[ *maDataIter++ ];
773cdf0e10cSrcweir             sal_uInt8 nGreen = mpColorTable[ *maDataIter++ ];
774cdf0e10cSrcweir             sal_uInt8 nBlue =  mpColorTable[ *maDataIter++ ];
775cdf0e10cSrcweir             mpAcc->SetPaletteColor( i, Color( nRed, nGreen, nBlue ) );
776cdf0e10cSrcweir         }
777cdf0e10cSrcweir     }
778cdf0e10cSrcweir     else
779cdf0e10cSrcweir         mbStatus = sal_False;
780cdf0e10cSrcweir 
781cdf0e10cSrcweir     return mbStatus;
782cdf0e10cSrcweir }
783cdf0e10cSrcweir 
784cdf0e10cSrcweir // ------------------------------------------------------------------------
785cdf0e10cSrcweir 
786cdf0e10cSrcweir sal_Bool PNGReaderImpl::ImplReadTransparent()
787cdf0e10cSrcweir {
788cdf0e10cSrcweir     bool bNeedAlpha = false;
789cdf0e10cSrcweir 
790cdf0e10cSrcweir     if ( mpTransTab == NULL )
791cdf0e10cSrcweir     {
792cdf0e10cSrcweir         switch ( mnColorType )
793cdf0e10cSrcweir         {
794cdf0e10cSrcweir             case 0 :
795cdf0e10cSrcweir             {
796cdf0e10cSrcweir                 if ( mnChunkLen == 2 )
797cdf0e10cSrcweir                 {
798cdf0e10cSrcweir                     mpTransTab = new sal_uInt8[ 256 ];
799cdf0e10cSrcweir                     rtl_fillMemory( mpTransTab, 256, 0xff );
800cdf0e10cSrcweir                     // color type 0 and 4 is always greyscale,
801cdf0e10cSrcweir                     // so the return value can be used as index
802cdf0e10cSrcweir                     sal_uInt8 nIndex = ImplScaleColor();
803cdf0e10cSrcweir                     mpTransTab[ nIndex ] = 0;
804cdf0e10cSrcweir                     mbTransparent = true;
805cdf0e10cSrcweir                 }
806cdf0e10cSrcweir             }
807cdf0e10cSrcweir             break;
808cdf0e10cSrcweir 
809cdf0e10cSrcweir             case 2 :
810cdf0e10cSrcweir             {
811cdf0e10cSrcweir                 if ( mnChunkLen == 6 )
812cdf0e10cSrcweir                 {
813cdf0e10cSrcweir                     mnTransRed = ImplScaleColor();
814cdf0e10cSrcweir                     mnTransGreen = ImplScaleColor();
815cdf0e10cSrcweir                     mnTransBlue = ImplScaleColor();
816cdf0e10cSrcweir                     mbTransparent = true;
817cdf0e10cSrcweir                 }
818cdf0e10cSrcweir             }
819cdf0e10cSrcweir             break;
820cdf0e10cSrcweir 
821cdf0e10cSrcweir             case 3 :
822cdf0e10cSrcweir             {
823cdf0e10cSrcweir                 if ( mnChunkLen <= 256 )
824cdf0e10cSrcweir                 {
825cdf0e10cSrcweir                     mpTransTab = new sal_uInt8 [ 256 ];
826cdf0e10cSrcweir                     rtl_fillMemory( mpTransTab, 256, 0xff );
827cdf0e10cSrcweir                     rtl_copyMemory( mpTransTab, &(*maDataIter), mnChunkLen );
828cdf0e10cSrcweir                     maDataIter += mnChunkLen;
829cdf0e10cSrcweir                     mbTransparent = true;
830cdf0e10cSrcweir                     // need alpha transparency if not on/off masking
831cdf0e10cSrcweir                     for( int i = 0; i < mnChunkLen; ++i )
832cdf0e10cSrcweir                        bNeedAlpha |= (mpTransTab[i]!=0x00) && (mpTransTab[i]!=0xFF);
833cdf0e10cSrcweir                 }
834cdf0e10cSrcweir             }
835cdf0e10cSrcweir             break;
836cdf0e10cSrcweir         }
837cdf0e10cSrcweir     }
838cdf0e10cSrcweir 
839cdf0e10cSrcweir     if( mbTransparent && !mbAlphaChannel && !mpMaskBmp )
840cdf0e10cSrcweir     {
841cdf0e10cSrcweir         if( bNeedAlpha)
842cdf0e10cSrcweir         {
843cdf0e10cSrcweir             mpAlphaMask = new AlphaMask( maTargetSize );
844cdf0e10cSrcweir             mpMaskAcc = mpAlphaMask->AcquireWriteAccess();
845cdf0e10cSrcweir         }
846cdf0e10cSrcweir         else
847cdf0e10cSrcweir         {
848cdf0e10cSrcweir             mpMaskBmp = new Bitmap( maTargetSize, 1 );
849cdf0e10cSrcweir             mpMaskAcc = mpMaskBmp->AcquireWriteAccess();
850cdf0e10cSrcweir         }
851cdf0e10cSrcweir         mbTransparent = (mpMaskAcc != NULL);
852cdf0e10cSrcweir         if( !mbTransparent )
853cdf0e10cSrcweir             return sal_False;
854cdf0e10cSrcweir         mcOpaqueColor = BitmapColor( 0x00 );
855cdf0e10cSrcweir         mcTranspColor = BitmapColor( 0xFF );
856cdf0e10cSrcweir         mpMaskAcc->Erase( 0x00 );
857cdf0e10cSrcweir     }
858cdf0e10cSrcweir 
859cdf0e10cSrcweir     return sal_True;
860cdf0e10cSrcweir }
861cdf0e10cSrcweir 
862cdf0e10cSrcweir // ------------------------------------------------------------------------
863cdf0e10cSrcweir 
864cdf0e10cSrcweir void PNGReaderImpl::ImplGetGamma()
865cdf0e10cSrcweir {
866cdf0e10cSrcweir     if( mnChunkLen < 4 )
867cdf0e10cSrcweir         return;
868cdf0e10cSrcweir 
869cdf0e10cSrcweir     sal_uInt32  nGammaValue = ImplReadsal_uInt32();
870cdf0e10cSrcweir     double      fGamma = ( ( VIEWING_GAMMA / DISPLAY_GAMMA ) * ( (double)nGammaValue / 100000 ) );
871cdf0e10cSrcweir     double      fInvGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
872cdf0e10cSrcweir 
873cdf0e10cSrcweir     if ( fInvGamma != 1.0 )
874cdf0e10cSrcweir     {
875cdf0e10cSrcweir         mbGamma = sal_True;
876cdf0e10cSrcweir 
877cdf0e10cSrcweir         if ( mpColorTable == mpDefaultColorTable )
878cdf0e10cSrcweir             mpColorTable = new sal_uInt8[ 256 ];
879cdf0e10cSrcweir 
880cdf0e10cSrcweir         for ( sal_Int32 i = 0; i < 256; i++ )
881cdf0e10cSrcweir             mpColorTable[ i ] = (sal_uInt8)(pow((double)i/255.0, fInvGamma) * 255.0 + 0.5);
882cdf0e10cSrcweir 
883cdf0e10cSrcweir         if ( mbGrayScale )
884cdf0e10cSrcweir             ImplGetGrayPalette( mnPngDepth );
885cdf0e10cSrcweir     }
886cdf0e10cSrcweir }
887cdf0e10cSrcweir 
888cdf0e10cSrcweir // ------------------------------------------------------------------------
889cdf0e10cSrcweir 
890cdf0e10cSrcweir void PNGReaderImpl::ImplGetBackground()
891cdf0e10cSrcweir {
892cdf0e10cSrcweir     switch ( mnColorType )
893cdf0e10cSrcweir     {
894cdf0e10cSrcweir         case 3 :
895cdf0e10cSrcweir         {
896cdf0e10cSrcweir             if ( mnChunkLen == 1 )
897cdf0e10cSrcweir             {
898cdf0e10cSrcweir                 sal_uInt16 nCol = *maDataIter++;
899cdf0e10cSrcweir                 if ( nCol < mpAcc->GetPaletteEntryCount() )
900cdf0e10cSrcweir                 {
901cdf0e10cSrcweir                     mpAcc->Erase( mpAcc->GetPaletteColor( (sal_uInt8)nCol ) );
902cdf0e10cSrcweir                     break;
903cdf0e10cSrcweir                 }
904cdf0e10cSrcweir             }
905cdf0e10cSrcweir         }
906cdf0e10cSrcweir         break;
907cdf0e10cSrcweir 
908cdf0e10cSrcweir         case 0 :
909cdf0e10cSrcweir         case 4 :
910cdf0e10cSrcweir         {
911cdf0e10cSrcweir             if ( mnChunkLen == 2 )
912cdf0e10cSrcweir             {
913cdf0e10cSrcweir                 // the color type 0 and 4 is always greyscale,
914cdf0e10cSrcweir                 // so the return value can be used as index
915cdf0e10cSrcweir                 sal_uInt8 nIndex = ImplScaleColor();
916cdf0e10cSrcweir                 mpAcc->Erase( mpAcc->GetPaletteColor( nIndex ) );
917cdf0e10cSrcweir             }
918cdf0e10cSrcweir         }
919cdf0e10cSrcweir         break;
920cdf0e10cSrcweir 
921cdf0e10cSrcweir         case 2 :
922cdf0e10cSrcweir         case 6 :
923cdf0e10cSrcweir         {
924cdf0e10cSrcweir             if ( mnChunkLen == 6 )
925cdf0e10cSrcweir             {
926cdf0e10cSrcweir                 sal_uInt8 nRed = ImplScaleColor();
927cdf0e10cSrcweir                 sal_uInt8 nGreen = ImplScaleColor();
928cdf0e10cSrcweir                 sal_uInt8 nBlue = ImplScaleColor();
929cdf0e10cSrcweir                 mpAcc->Erase( Color( nRed, nGreen, nBlue ) );
930cdf0e10cSrcweir             }
931cdf0e10cSrcweir         }
932cdf0e10cSrcweir         break;
933cdf0e10cSrcweir     }
934cdf0e10cSrcweir }
935cdf0e10cSrcweir 
936cdf0e10cSrcweir // ------------------------------------------------------------------------
937cdf0e10cSrcweir 
938cdf0e10cSrcweir // for color type 0 and 4 (greyscale) the return value is always index to the color
939cdf0e10cSrcweir //                2 and 6 (RGB)       the return value is always the 8 bit color component
940cdf0e10cSrcweir sal_uInt8 PNGReaderImpl::ImplScaleColor()
941cdf0e10cSrcweir {
942cdf0e10cSrcweir     sal_uInt32 nMask = ( ( 1 << mnPngDepth ) - 1 );
943cdf0e10cSrcweir     sal_uInt16 nCol = ( *maDataIter++ << 8 );
944cdf0e10cSrcweir 
945cdf0e10cSrcweir     nCol += *maDataIter++ & (sal_uInt16)nMask;
946cdf0e10cSrcweir 
947cdf0e10cSrcweir     if ( mnPngDepth > 8 )   // convert 16bit graphics to 8
948cdf0e10cSrcweir         nCol >>= 8;
949cdf0e10cSrcweir 
950cdf0e10cSrcweir     return (sal_uInt8) nCol;
951cdf0e10cSrcweir }
952cdf0e10cSrcweir 
953cdf0e10cSrcweir // ------------------------------------------------------------------------
954cdf0e10cSrcweir // ImplReadIDAT reads as much image data as needed
955cdf0e10cSrcweir 
956cdf0e10cSrcweir void PNGReaderImpl::ImplReadIDAT()
957cdf0e10cSrcweir {
958cdf0e10cSrcweir     if( mnChunkLen > 0 )
959cdf0e10cSrcweir     {
960cdf0e10cSrcweir         if ( mbzCodecInUse == sal_False )
961cdf0e10cSrcweir         {
962cdf0e10cSrcweir             mbzCodecInUse = sal_True;
963cdf0e10cSrcweir             mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT );
964cdf0e10cSrcweir         }
965cdf0e10cSrcweir         mpZCodec->SetBreak( mnChunkLen );
966cdf0e10cSrcweir         SvMemoryStream aIStrm( &(*maDataIter), mnChunkLen, STREAM_READ );
967cdf0e10cSrcweir 
968cdf0e10cSrcweir         while ( ( mpZCodec->GetBreak() ) )
969cdf0e10cSrcweir         {
970cdf0e10cSrcweir             // get bytes needed to fill the current scanline
971cdf0e10cSrcweir             sal_Int32 nToRead = mnScansize - (mpScanCurrent - mpInflateInBuf);
972cdf0e10cSrcweir             sal_Int32 nRead = mpZCodec->ReadAsynchron( aIStrm, mpScanCurrent, nToRead );
973cdf0e10cSrcweir             if ( nRead < 0 )
974cdf0e10cSrcweir             {
975cdf0e10cSrcweir                 mbStatus = sal_False;
976cdf0e10cSrcweir                 break;
977cdf0e10cSrcweir             }
978cdf0e10cSrcweir             if ( nRead < nToRead )
979cdf0e10cSrcweir             {
980cdf0e10cSrcweir                 mpScanCurrent += nRead; // more ZStream data in the next IDAT chunk
981cdf0e10cSrcweir                 break;
982cdf0e10cSrcweir             }
983cdf0e10cSrcweir             else  // this scanline is Finished
984cdf0e10cSrcweir             {
985cdf0e10cSrcweir                 mpScanCurrent = mpInflateInBuf;
986cdf0e10cSrcweir                 ImplApplyFilter();
987cdf0e10cSrcweir 
988cdf0e10cSrcweir                 ImplDrawScanline( mnXStart, mnXAdd );
989cdf0e10cSrcweir                 mnYpos += mnYAdd;
990cdf0e10cSrcweir             }
991cdf0e10cSrcweir 
992cdf0e10cSrcweir             if ( mnYpos >= (sal_uInt32)maOrigSize.Height() )
993cdf0e10cSrcweir             {
994cdf0e10cSrcweir                 if( (mnPass < 7) && mnInterlaceType )
995cdf0e10cSrcweir                     if( ImplPreparePass() )
996cdf0e10cSrcweir                         continue;
997cdf0e10cSrcweir                 mbIDAT = true;
998cdf0e10cSrcweir                 break;
999cdf0e10cSrcweir             }
1000cdf0e10cSrcweir         }
1001cdf0e10cSrcweir     }
1002cdf0e10cSrcweir 
1003cdf0e10cSrcweir     if( mbIDAT )
1004cdf0e10cSrcweir     {
1005cdf0e10cSrcweir         mpZCodec->EndCompression();
1006cdf0e10cSrcweir         mbzCodecInUse = sal_False;
1007cdf0e10cSrcweir     }
1008cdf0e10cSrcweir }
1009cdf0e10cSrcweir 
1010cdf0e10cSrcweir // ---------------------------------------------------------------------------------------------------
1011cdf0e10cSrcweir 
1012cdf0e10cSrcweir bool PNGReaderImpl::ImplPreparePass()
1013cdf0e10cSrcweir {
1014cdf0e10cSrcweir     struct InterlaceParams{ int mnXStart, mnYStart, mnXAdd, mnYAdd; };
1015cdf0e10cSrcweir     static const InterlaceParams aInterlaceParams[8] =
1016cdf0e10cSrcweir     {
1017cdf0e10cSrcweir         // non-interlaced
1018cdf0e10cSrcweir         { 0, 0, 1, 1 },
1019cdf0e10cSrcweir         // Adam7-interlaced
1020cdf0e10cSrcweir         { 0, 0, 8, 8 },    // pass 1
1021cdf0e10cSrcweir         { 4, 0, 8, 8 },    // pass 2
1022cdf0e10cSrcweir         { 0, 4, 4, 8 },    // pass 3
1023cdf0e10cSrcweir         { 2, 0, 4, 4 },    // pass 4
1024cdf0e10cSrcweir         { 0, 2, 2, 4 },    // pass 5
1025cdf0e10cSrcweir         { 1, 0, 2, 2 },    // pass 6
1026cdf0e10cSrcweir         { 0, 1, 1, 2 }     // pass 7
1027cdf0e10cSrcweir     };
1028cdf0e10cSrcweir 
1029cdf0e10cSrcweir     const InterlaceParams* pParam = &aInterlaceParams[ 0 ];
1030cdf0e10cSrcweir     if( mnInterlaceType )
1031cdf0e10cSrcweir     {
1032cdf0e10cSrcweir         while( ++mnPass <= 7 )
1033cdf0e10cSrcweir         {
1034cdf0e10cSrcweir             pParam = &aInterlaceParams[ mnPass ];
1035cdf0e10cSrcweir 
1036cdf0e10cSrcweir             // skip this pass if the original image is too small for it
1037cdf0e10cSrcweir             if( (pParam->mnXStart < maOrigSize.Width())
1038cdf0e10cSrcweir             &&  (pParam->mnYStart < maOrigSize.Height()) )
1039cdf0e10cSrcweir                 break;
1040cdf0e10cSrcweir         }
1041cdf0e10cSrcweir         if( mnPass > 7 )
1042cdf0e10cSrcweir             return false;
1043cdf0e10cSrcweir 
1044cdf0e10cSrcweir         // skip the last passes if possible (for scaled down target images)
1045cdf0e10cSrcweir         if( mnPreviewMask & (pParam->mnXStart | pParam->mnYStart) )
1046cdf0e10cSrcweir             return false;
1047cdf0e10cSrcweir     }
1048cdf0e10cSrcweir 
1049cdf0e10cSrcweir     mnYpos      = pParam->mnYStart;
1050cdf0e10cSrcweir     mnXStart    = pParam->mnXStart;
1051cdf0e10cSrcweir     mnXAdd      = pParam->mnXAdd;
1052cdf0e10cSrcweir     mnYAdd      = pParam->mnYAdd;
1053cdf0e10cSrcweir 
1054cdf0e10cSrcweir     // in Interlace mode the size of scanline is not constant
1055cdf0e10cSrcweir     // so first we calculate the number of entrys
1056cdf0e10cSrcweir     long nScanWidth = (maOrigSize.Width() - mnXStart + mnXAdd - 1) / mnXAdd;
1057cdf0e10cSrcweir     mnScansize = nScanWidth;
1058cdf0e10cSrcweir 
1059cdf0e10cSrcweir     if( mbRGBTriple )
1060cdf0e10cSrcweir         mnScansize = 3 * nScanWidth;
1061cdf0e10cSrcweir 
1062cdf0e10cSrcweir     if( mbAlphaChannel )
1063cdf0e10cSrcweir         mnScansize += nScanWidth;
1064cdf0e10cSrcweir 
1065cdf0e10cSrcweir     // convert to width in bytes
1066cdf0e10cSrcweir     mnScansize = ( mnScansize*mnPngDepth + 7 ) >> 3;
1067cdf0e10cSrcweir 
1068cdf0e10cSrcweir     ++mnScansize; // scan size also needs room for the filtertype byte
1069cdf0e10cSrcweir     rtl_zeroMemory( mpScanPrior, mnScansize );
1070cdf0e10cSrcweir 
1071cdf0e10cSrcweir     return true;
1072cdf0e10cSrcweir }
1073cdf0e10cSrcweir 
1074cdf0e10cSrcweir // ----------------------------------------------------------------------------
1075cdf0e10cSrcweir // ImplApplyFilter writes the complete Scanline (nY)
1076cdf0e10cSrcweir // in interlace mode the parameter nXStart and nXAdd are non-zero
1077cdf0e10cSrcweir 
1078cdf0e10cSrcweir void PNGReaderImpl::ImplApplyFilter()
1079cdf0e10cSrcweir {
1080cdf0e10cSrcweir     OSL_ASSERT( mnScansize >= mnBPP + 1 );
1081cdf0e10cSrcweir     const sal_uInt8* const pScanEnd = mpInflateInBuf + mnScansize;
1082cdf0e10cSrcweir 
1083cdf0e10cSrcweir     sal_uInt8 nFilterType = *mpInflateInBuf; // the filter type may change each scanline
1084cdf0e10cSrcweir     switch ( nFilterType )
1085cdf0e10cSrcweir     {
1086cdf0e10cSrcweir         default: // unknown Scanline Filter Type
1087cdf0e10cSrcweir         case 0: // Filter Type "None"
1088cdf0e10cSrcweir             // we let the pixels pass and display the data unfiltered
1089cdf0e10cSrcweir             break;
1090cdf0e10cSrcweir 
1091cdf0e10cSrcweir         case 1: // Scanline Filter Type "Sub"
1092cdf0e10cSrcweir         {
1093cdf0e10cSrcweir             sal_uInt8* p1 = mpInflateInBuf + 1;
1094cdf0e10cSrcweir             const sal_uInt8* p2 = p1;
1095cdf0e10cSrcweir             p1 += mnBPP;
1096cdf0e10cSrcweir 
1097cdf0e10cSrcweir             // use left pixels
1098cdf0e10cSrcweir             do
1099cdf0e10cSrcweir                 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1100cdf0e10cSrcweir             while( ++p1 < pScanEnd );
1101cdf0e10cSrcweir         }
1102cdf0e10cSrcweir         break;
1103cdf0e10cSrcweir 
1104cdf0e10cSrcweir         case 2: // Scanline Filter Type "Up"
1105cdf0e10cSrcweir         {
1106cdf0e10cSrcweir             sal_uInt8* p1 = mpInflateInBuf + 1;
1107cdf0e10cSrcweir             const sal_uInt8* p2 = mpScanPrior + 1;
1108cdf0e10cSrcweir 
1109cdf0e10cSrcweir             // use pixels from prior line
1110cdf0e10cSrcweir             while( p1 < pScanEnd )
1111cdf0e10cSrcweir             {
1112cdf0e10cSrcweir                 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1113cdf0e10cSrcweir                 ++p1;
1114cdf0e10cSrcweir             }
1115cdf0e10cSrcweir         }
1116cdf0e10cSrcweir         break;
1117cdf0e10cSrcweir 
1118cdf0e10cSrcweir         case 3: // Scanline Filter Type "Average"
1119cdf0e10cSrcweir         {
1120cdf0e10cSrcweir             sal_uInt8* p1 = mpInflateInBuf + 1;
1121cdf0e10cSrcweir             const sal_uInt8* p2 = mpScanPrior + 1;
1122cdf0e10cSrcweir             const sal_uInt8* p3 = p1;
1123cdf0e10cSrcweir 
1124cdf0e10cSrcweir             // use one pixel from prior line
1125cdf0e10cSrcweir             for( int n = mnBPP; --n >= 0; ++p1, ++p2)
1126cdf0e10cSrcweir                 *p1 = static_cast<sal_uInt8>( *p1 + (*p2 >> 1) );
1127cdf0e10cSrcweir 
1128cdf0e10cSrcweir             // predict by averaging the left and prior line pixels
1129cdf0e10cSrcweir             while( p1 < pScanEnd )
1130cdf0e10cSrcweir             {
1131cdf0e10cSrcweir                 *p1 = static_cast<sal_uInt8>( *p1 + ((*(p2++) + *(p3++)) >> 1) );
1132cdf0e10cSrcweir                 ++p1;
1133cdf0e10cSrcweir             }
1134cdf0e10cSrcweir         }
1135cdf0e10cSrcweir         break;
1136cdf0e10cSrcweir 
1137cdf0e10cSrcweir         case 4: // Scanline Filter Type "PaethPredictor"
1138cdf0e10cSrcweir         {
1139cdf0e10cSrcweir             sal_uInt8* p1 = mpInflateInBuf + 1;
1140cdf0e10cSrcweir             const sal_uInt8* p2 = mpScanPrior + 1;
1141cdf0e10cSrcweir             const sal_uInt8* p3 = p1;
1142cdf0e10cSrcweir             const sal_uInt8* p4 = p2;
1143cdf0e10cSrcweir 
1144cdf0e10cSrcweir             // use one pixel from prior line
1145cdf0e10cSrcweir             for( int n = mnBPP; --n >= 0; ++p1)
1146cdf0e10cSrcweir                 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1147cdf0e10cSrcweir 
1148cdf0e10cSrcweir             // predict by using the left and the prior line pixels
1149cdf0e10cSrcweir             while( p1 < pScanEnd )
1150cdf0e10cSrcweir             {
1151cdf0e10cSrcweir                 int na = *(p2++);
1152cdf0e10cSrcweir                 int nb = *(p3++);
1153cdf0e10cSrcweir                 int nc = *(p4++);
1154cdf0e10cSrcweir 
1155cdf0e10cSrcweir                 int npa = nb - (int)nc;
1156cdf0e10cSrcweir                 int npb = na - (int)nc;
1157cdf0e10cSrcweir                 int npc = npa + npb;
1158cdf0e10cSrcweir 
1159cdf0e10cSrcweir                 if( npa < 0 )
1160cdf0e10cSrcweir                     npa =-npa;
1161cdf0e10cSrcweir                 if( npb < 0 )
1162cdf0e10cSrcweir                     npb =-npb;
1163cdf0e10cSrcweir                 if( npc < 0 )
1164cdf0e10cSrcweir                     npc =-npc;
1165cdf0e10cSrcweir 
1166cdf0e10cSrcweir                 if( npa > npb )
1167cdf0e10cSrcweir                     na = nb, npa = npb;
1168cdf0e10cSrcweir                 if( npa > npc )
1169cdf0e10cSrcweir                     na = nc;
1170cdf0e10cSrcweir 
1171cdf0e10cSrcweir                 *p1 = static_cast<sal_uInt8>( *p1 + na );
1172cdf0e10cSrcweir                 ++p1;
1173cdf0e10cSrcweir             }
1174cdf0e10cSrcweir         }
1175cdf0e10cSrcweir         break;
1176cdf0e10cSrcweir     }
1177cdf0e10cSrcweir 
1178cdf0e10cSrcweir     rtl_copyMemory( mpScanPrior, mpInflateInBuf, mnScansize );
1179cdf0e10cSrcweir }
1180cdf0e10cSrcweir 
1181cdf0e10cSrcweir // ---------------------------------------------------------------------------------------------------
1182cdf0e10cSrcweir // ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
1183cdf0e10cSrcweir // In interlace mode the parameter nXStart and nXAdd append to the currently used pass
1184cdf0e10cSrcweir 
1185cdf0e10cSrcweir void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd )
1186cdf0e10cSrcweir {
1187cdf0e10cSrcweir     // optimization for downscaling
1188cdf0e10cSrcweir     if( mnYpos & mnPreviewMask )
1189cdf0e10cSrcweir         return;
1190cdf0e10cSrcweir     if( nXStart & mnPreviewMask )
1191cdf0e10cSrcweir         return;
1192cdf0e10cSrcweir 
1193cdf0e10cSrcweir     // convert nY to pixel units in the target image
1194cdf0e10cSrcweir     // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
1195cdf0e10cSrcweir     const sal_uInt32 nY = mnYpos >> mnPreviewShift;
1196cdf0e10cSrcweir 
1197cdf0e10cSrcweir     const sal_uInt8* pTmp = mpInflateInBuf + 1;
1198cdf0e10cSrcweir     if ( mpAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
1199cdf0e10cSrcweir     {
1200cdf0e10cSrcweir         switch ( mpAcc->GetBitCount() )
1201cdf0e10cSrcweir         {
1202cdf0e10cSrcweir             case 1 :
1203cdf0e10cSrcweir             {
1204cdf0e10cSrcweir                 if ( mbTransparent )
1205cdf0e10cSrcweir                 {
1206cdf0e10cSrcweir                     for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1207cdf0e10cSrcweir                     {
1208cdf0e10cSrcweir                         sal_uInt8 nCol;
1209cdf0e10cSrcweir                         nShift = (nShift - 1) & 7;
1210cdf0e10cSrcweir                         if ( nShift == 0 )
1211cdf0e10cSrcweir                             nCol = *(pTmp++);
1212cdf0e10cSrcweir                         else
1213cdf0e10cSrcweir                             nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1214cdf0e10cSrcweir                         nCol &= 1;
1215cdf0e10cSrcweir 
1216cdf0e10cSrcweir                         ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1217cdf0e10cSrcweir                     }
1218cdf0e10cSrcweir                 }
1219cdf0e10cSrcweir                 else
1220cdf0e10cSrcweir                 {   // BMP_FORMAT_1BIT_MSB_PAL
1221cdf0e10cSrcweir                     for ( sal_Int32 nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1222cdf0e10cSrcweir                     {
1223cdf0e10cSrcweir                         nShift = (nShift - 1) & 7;
1224cdf0e10cSrcweir 
1225cdf0e10cSrcweir                         sal_uInt8 nCol;
1226cdf0e10cSrcweir                         if ( nShift == 0 )
1227cdf0e10cSrcweir                             nCol = *(pTmp++);
1228cdf0e10cSrcweir                         else
1229cdf0e10cSrcweir                             nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1230cdf0e10cSrcweir                         nCol &= 1;
1231cdf0e10cSrcweir 
1232cdf0e10cSrcweir                         ImplSetPixel( nY, nX, nCol );
1233cdf0e10cSrcweir                     }
1234cdf0e10cSrcweir                 }
1235cdf0e10cSrcweir             }
1236cdf0e10cSrcweir             break;
1237cdf0e10cSrcweir 
1238cdf0e10cSrcweir             case 4 :
1239cdf0e10cSrcweir             {
1240cdf0e10cSrcweir                 if ( mbTransparent )
1241cdf0e10cSrcweir                 {
1242cdf0e10cSrcweir                     if ( mnPngDepth == 4 )  // check if source has a two bit pixel format
1243cdf0e10cSrcweir                     {
1244cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, ++nXIndex )
1245cdf0e10cSrcweir                         {
1246cdf0e10cSrcweir                             if( nXIndex & 1 )
1247cdf0e10cSrcweir                             {
1248cdf0e10cSrcweir                                 ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
1249cdf0e10cSrcweir                                 pTmp++;
1250cdf0e10cSrcweir                             }
1251cdf0e10cSrcweir                             else
1252cdf0e10cSrcweir                             {
1253cdf0e10cSrcweir                                 ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
1254cdf0e10cSrcweir                             }
1255cdf0e10cSrcweir                         }
1256cdf0e10cSrcweir                     }
1257cdf0e10cSrcweir                     else // if ( mnPngDepth == 2 )
1258cdf0e10cSrcweir                     {
1259cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1260cdf0e10cSrcweir                         {
1261cdf0e10cSrcweir                             sal_uInt8 nCol;
1262cdf0e10cSrcweir                             switch( nXIndex & 3 )
1263cdf0e10cSrcweir                             {
1264cdf0e10cSrcweir                                 case 0 :
1265cdf0e10cSrcweir                                     nCol = *pTmp >> 6;
1266cdf0e10cSrcweir                                 break;
1267cdf0e10cSrcweir 
1268cdf0e10cSrcweir                                 case 1 :
1269cdf0e10cSrcweir                                     nCol = ( *pTmp >> 4 ) & 0x03 ;
1270cdf0e10cSrcweir                                 break;
1271cdf0e10cSrcweir 
1272cdf0e10cSrcweir                                 case 2 :
1273cdf0e10cSrcweir                                     nCol = ( *pTmp >> 2 ) & 0x03;
1274cdf0e10cSrcweir                                 break;
1275cdf0e10cSrcweir 
1276cdf0e10cSrcweir                                 case 3 :
1277cdf0e10cSrcweir                                     nCol = ( *pTmp++ ) & 0x03;
1278cdf0e10cSrcweir                                 break;
1279cdf0e10cSrcweir 
1280cdf0e10cSrcweir                                 default:    // get rid of nCol uninitialized warning
1281cdf0e10cSrcweir                                     nCol = 0;
1282cdf0e10cSrcweir                                     break;
1283cdf0e10cSrcweir                             }
1284cdf0e10cSrcweir 
1285cdf0e10cSrcweir                             ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1286cdf0e10cSrcweir                         }
1287cdf0e10cSrcweir                     }
1288cdf0e10cSrcweir                 }
1289cdf0e10cSrcweir                 else
1290cdf0e10cSrcweir                 {
1291cdf0e10cSrcweir                     if ( mnPngDepth == 4 )  // maybe the source is a two bitmap graphic
1292cdf0e10cSrcweir                     {   // BMP_FORMAT_4BIT_LSN_PAL
1293cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1294cdf0e10cSrcweir                         {
1295cdf0e10cSrcweir                             if( nXIndex & 1 )
1296cdf0e10cSrcweir                                 ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
1297cdf0e10cSrcweir                             else
1298cdf0e10cSrcweir                                 ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
1299cdf0e10cSrcweir                         }
1300cdf0e10cSrcweir                     }
1301cdf0e10cSrcweir                     else // if ( mnPngDepth == 2 )
1302cdf0e10cSrcweir                     {
1303cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1304cdf0e10cSrcweir                         {
1305cdf0e10cSrcweir                             switch( nXIndex & 3 )
1306cdf0e10cSrcweir                             {
1307cdf0e10cSrcweir                                 case 0 :
1308cdf0e10cSrcweir                                     ImplSetPixel( nY, nX, *pTmp >> 6 );
1309cdf0e10cSrcweir                                 break;
1310cdf0e10cSrcweir 
1311cdf0e10cSrcweir                                 case 1 :
1312cdf0e10cSrcweir                                     ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
1313cdf0e10cSrcweir                                 break;
1314cdf0e10cSrcweir 
1315cdf0e10cSrcweir                                 case 2 :
1316cdf0e10cSrcweir                                     ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
1317cdf0e10cSrcweir                                 break;
1318cdf0e10cSrcweir 
1319cdf0e10cSrcweir                                 case 3 :
1320cdf0e10cSrcweir                                     ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
1321cdf0e10cSrcweir                                 break;
1322cdf0e10cSrcweir                             }
1323cdf0e10cSrcweir                         }
1324cdf0e10cSrcweir                     }
1325cdf0e10cSrcweir                 }
1326cdf0e10cSrcweir             }
1327cdf0e10cSrcweir             break;
1328cdf0e10cSrcweir 
1329cdf0e10cSrcweir             case 8 :
1330cdf0e10cSrcweir             {
1331cdf0e10cSrcweir                 if ( mbAlphaChannel )
1332cdf0e10cSrcweir                 {
1333cdf0e10cSrcweir                     if ( mnPngDepth == 8 )  // maybe the source is a 16 bit grayscale
1334cdf0e10cSrcweir                     {
1335cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1336cdf0e10cSrcweir                             ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
1337cdf0e10cSrcweir                     }
1338cdf0e10cSrcweir                     else
1339cdf0e10cSrcweir                     {
1340cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1341cdf0e10cSrcweir                             ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
1342cdf0e10cSrcweir                     }
1343cdf0e10cSrcweir                 }
1344cdf0e10cSrcweir                 else if ( mbTransparent )
1345cdf0e10cSrcweir                 {
1346cdf0e10cSrcweir                     if ( mnPngDepth == 8 )  // maybe the source is a 16 bit grayscale
1347cdf0e10cSrcweir                     {
1348cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp++ )
1349cdf0e10cSrcweir                             ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1350cdf0e10cSrcweir                     }
1351cdf0e10cSrcweir                     else
1352cdf0e10cSrcweir                     {
1353cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1354cdf0e10cSrcweir                             ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1355cdf0e10cSrcweir                     }
1356cdf0e10cSrcweir                 }
1357cdf0e10cSrcweir                 else // neither alpha nor transparency
1358cdf0e10cSrcweir                 {
1359cdf0e10cSrcweir                     if ( mnPngDepth == 8 )  // maybe the source is a 16 bit grayscale
1360cdf0e10cSrcweir                     {
1361cdf0e10cSrcweir                         if( nXAdd == 1 && mnPreviewShift == 0 )  // copy raw line data if possible
1362cdf0e10cSrcweir                         {
1363cdf0e10cSrcweir                             int nLineBytes = maOrigSize.Width();
1364cdf0e10cSrcweir                             mpAcc->CopyScanline( nY, pTmp, BMP_FORMAT_8BIT_PAL, nLineBytes );
1365cdf0e10cSrcweir                             pTmp += nLineBytes;
1366cdf0e10cSrcweir                         }
1367cdf0e10cSrcweir                         else
1368cdf0e10cSrcweir                         {
1369cdf0e10cSrcweir                             for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd )
1370cdf0e10cSrcweir                                 ImplSetPixel( nY, nX, *pTmp++ );
1371cdf0e10cSrcweir                         }
1372cdf0e10cSrcweir                     }
1373cdf0e10cSrcweir                     else
1374cdf0e10cSrcweir                     {
1375cdf0e10cSrcweir                         for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1376cdf0e10cSrcweir                             ImplSetPixel( nY, nX, *pTmp );
1377cdf0e10cSrcweir                     }
1378cdf0e10cSrcweir                 }
1379cdf0e10cSrcweir             }
1380cdf0e10cSrcweir             break;
1381cdf0e10cSrcweir 
1382cdf0e10cSrcweir             default :
1383cdf0e10cSrcweir                 mbStatus = sal_False;
1384cdf0e10cSrcweir             break;
1385cdf0e10cSrcweir         }
1386cdf0e10cSrcweir     }
1387cdf0e10cSrcweir     else // no palette => truecolor
1388cdf0e10cSrcweir     {
138988b53a7cSArmin Le Grand         // #122985# Added fast-lane implementations using CopyScanline with direct supported mem formats
139088b53a7cSArmin Le Grand         static bool bCkeckDirectScanline(true);
139188b53a7cSArmin Le Grand 
139288b53a7cSArmin Le Grand         if( mbAlphaChannel )
139388b53a7cSArmin Le Grand         {
139488b53a7cSArmin Le Grand             // has RGB + alpha
1395cdf0e10cSrcweir             if ( mnPngDepth == 8 )  // maybe the source has 16 bit per sample
1396cdf0e10cSrcweir             {
139788b53a7cSArmin Le Grand                 // BMP_FORMAT_32BIT_TC_RGBA
139888b53a7cSArmin Le Grand                 // only use DirectScanline when we have no preview shifting stuff and accesses to content and alpha
139988b53a7cSArmin Le Grand                 const bool bDoDirectScanline(
140088b53a7cSArmin Le Grand                     bCkeckDirectScanline && !nXStart && 1 == nXAdd && !mnPreviewShift && mpAcc && mpMaskAcc);
140188b53a7cSArmin Le Grand                 const bool bCustomColorTable(mpColorTable != mpDefaultColorTable);
140288b53a7cSArmin Le Grand 
140388b53a7cSArmin Le Grand                 if(bDoDirectScanline)
140488b53a7cSArmin Le Grand                 {
140588b53a7cSArmin Le Grand                     // allocate scanlines on demand, reused for next line
140688b53a7cSArmin Le Grand                     if(!mpScanline)
140788b53a7cSArmin Le Grand                     {
140888b53a7cSArmin Le Grand #ifdef DBG_UTIL
140988b53a7cSArmin Le Grand                         mnAllocSizeScanline = maOrigSize.Width() * 3;
141088b53a7cSArmin Le Grand #endif
141188b53a7cSArmin Le Grand                         mpScanline = new sal_uInt8[maOrigSize.Width() * 3];
141288b53a7cSArmin Le Grand                     }
141388b53a7cSArmin Le Grand 
141488b53a7cSArmin Le Grand                     if(!mpScanlineAlpha)
141588b53a7cSArmin Le Grand                     {
141688b53a7cSArmin Le Grand #ifdef DBG_UTIL
141788b53a7cSArmin Le Grand                         mnAllocSizeScanlineAlpha = maOrigSize.Width();
141888b53a7cSArmin Le Grand #endif
141988b53a7cSArmin Le Grand                         mpScanlineAlpha = new sal_uInt8[maOrigSize.Width()];
142088b53a7cSArmin Le Grand                     }
142188b53a7cSArmin Le Grand                 }
142288b53a7cSArmin Le Grand 
142388b53a7cSArmin Le Grand                 if(bDoDirectScanline)
142488b53a7cSArmin Le Grand                 {
142588b53a7cSArmin Le Grand                     OSL_ENSURE(mpScanline, "No Scanline allocated (!)");
142688b53a7cSArmin Le Grand                     OSL_ENSURE(mpScanlineAlpha, "No ScanlineAlpha allocated (!)");
142759c7f95bSHerbert Dürr #ifdef DBG_UTIL
142888b53a7cSArmin Le Grand                     OSL_ENSURE(mnAllocSizeScanline >= maOrigSize.Width() * 3, "Allocated Scanline too small (!)");
142988b53a7cSArmin Le Grand                     OSL_ENSURE(mnAllocSizeScanlineAlpha >= maOrigSize.Width(), "Allocated ScanlineAlpha too small (!)");
143059c7f95bSHerbert Dürr #endif
143188b53a7cSArmin Le Grand                     sal_uInt8* pScanline(mpScanline);
143288b53a7cSArmin Le Grand                     sal_uInt8* pScanlineAlpha(mpScanlineAlpha);
143388b53a7cSArmin Le Grand 
1434f037e03fSPavel Janík                     for(sal_Int32 nX(0); nX < maOrigSize.Width(); nX++, pTmp += 4)
143588b53a7cSArmin Le Grand                     {
143688b53a7cSArmin Le Grand                         // prepare content line as BGR by reordering when copying
143788b53a7cSArmin Le Grand                         // do not forget to invert alpha (source is alpha, target is opacity)
143888b53a7cSArmin Le Grand                         if(bCustomColorTable)
143988b53a7cSArmin Le Grand                         {
144088b53a7cSArmin Le Grand                             *pScanline++ = mpColorTable[pTmp[2]];
144188b53a7cSArmin Le Grand                             *pScanline++ = mpColorTable[pTmp[1]];
144288b53a7cSArmin Le Grand                             *pScanline++ = mpColorTable[pTmp[0]];
144388b53a7cSArmin Le Grand                             *pScanlineAlpha++ = ~pTmp[3];
144488b53a7cSArmin Le Grand                         }
144588b53a7cSArmin Le Grand                         else
144688b53a7cSArmin Le Grand                         {
144788b53a7cSArmin Le Grand                             *pScanline++ = pTmp[2];
144888b53a7cSArmin Le Grand                             *pScanline++ = pTmp[1];
144988b53a7cSArmin Le Grand                             *pScanline++ = pTmp[0];
145088b53a7cSArmin Le Grand                             *pScanlineAlpha++ = ~pTmp[3];
145188b53a7cSArmin Le Grand                         }
145288b53a7cSArmin Le Grand                     }
145388b53a7cSArmin Le Grand 
145488b53a7cSArmin Le Grand                     // copy scanlines directly to bitmaps for content and alpha; use the formats which
145588b53a7cSArmin Le Grand                     // are able to copy directly to BitmapBuffer
145688b53a7cSArmin Le Grand                     mpAcc->CopyScanline(nY, mpScanline, BMP_FORMAT_24BIT_TC_BGR, maOrigSize.Width() * 3);
145788b53a7cSArmin Le Grand                     mpMaskAcc->CopyScanline(nY, mpScanlineAlpha, BMP_FORMAT_8BIT_PAL, maOrigSize.Width());
145888b53a7cSArmin Le Grand                 }
145988b53a7cSArmin Le Grand                 else
1460cdf0e10cSrcweir                 {
1461cdf0e10cSrcweir                     for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
146288b53a7cSArmin Le Grand                     {
146388b53a7cSArmin Le Grand                         if(bCustomColorTable)
146488b53a7cSArmin Le Grand                         {
146588b53a7cSArmin Le Grand                             ImplSetAlphaPixel(
146688b53a7cSArmin Le Grand                                 nY,
146788b53a7cSArmin Le Grand                                 nX,
146888b53a7cSArmin Le Grand                                 BitmapColor(
146988b53a7cSArmin Le Grand                                     mpColorTable[ pTmp[ 0 ] ],
1470cdf0e10cSrcweir                                     mpColorTable[ pTmp[ 1 ] ],
147188b53a7cSArmin Le Grand                                     mpColorTable[ pTmp[ 2 ] ]),
147288b53a7cSArmin Le Grand                                 pTmp[ 3 ]);
1473cdf0e10cSrcweir                         }
1474cdf0e10cSrcweir                         else
1475cdf0e10cSrcweir                         {
147688b53a7cSArmin Le Grand                             ImplSetAlphaPixel(
147788b53a7cSArmin Le Grand                                 nY,
147888b53a7cSArmin Le Grand                                 nX,
147988b53a7cSArmin Le Grand                                 BitmapColor(
148088b53a7cSArmin Le Grand                                     pTmp[0],
148188b53a7cSArmin Le Grand                                     pTmp[1],
148288b53a7cSArmin Le Grand                                     pTmp[2]),
148388b53a7cSArmin Le Grand                                 pTmp[3]);
148488b53a7cSArmin Le Grand                         }
1485cdf0e10cSrcweir                     }
1486cdf0e10cSrcweir                 }
1487cdf0e10cSrcweir             }
1488cdf0e10cSrcweir             else
148988b53a7cSArmin Le Grand             {
149088b53a7cSArmin Le Grand                 // BMP_FORMAT_64BIT_TC_RGBA
1491cdf0e10cSrcweir                 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 8 )
149288b53a7cSArmin Le Grand                 {
149388b53a7cSArmin Le Grand                     ImplSetAlphaPixel(
149488b53a7cSArmin Le Grand                         nY,
149588b53a7cSArmin Le Grand                         nX,
149688b53a7cSArmin Le Grand                         BitmapColor(
149788b53a7cSArmin Le Grand                             mpColorTable[ pTmp[ 0 ] ],
1498cdf0e10cSrcweir                             mpColorTable[ pTmp[ 2 ] ],
149988b53a7cSArmin Le Grand                             mpColorTable[ pTmp[ 4 ] ]),
150088b53a7cSArmin Le Grand                         pTmp[6]);
150188b53a7cSArmin Le Grand                 }
1502cdf0e10cSrcweir             }
1503cdf0e10cSrcweir         }
1504cdf0e10cSrcweir         else if( mbTransparent ) // has RGB + transparency
150588b53a7cSArmin Le Grand         {
150688b53a7cSArmin Le Grand             // BMP_FORMAT_24BIT_TC_RGB
150788b53a7cSArmin Le Grand             // no support currently for DirectScanline, found no real usages in current PNGs, may be added on demand
1508cdf0e10cSrcweir             if ( mnPngDepth == 8 )  // maybe the source has 16 bit per sample
1509cdf0e10cSrcweir             {
1510cdf0e10cSrcweir                 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1511cdf0e10cSrcweir                 {
1512cdf0e10cSrcweir                     sal_uInt8 nRed = pTmp[ 0 ];
1513cdf0e10cSrcweir                     sal_uInt8 nGreen = pTmp[ 1 ];
1514cdf0e10cSrcweir                     sal_uInt8 nBlue = pTmp[ 2 ];
1515cdf0e10cSrcweir                     sal_Bool bTransparent = ( ( nRed == mnTransRed )
1516cdf0e10cSrcweir                                         && ( nGreen == mnTransGreen )
1517cdf0e10cSrcweir                                         && ( nBlue == mnTransBlue ) );
1518cdf0e10cSrcweir 
1519cdf0e10cSrcweir                     ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1520cdf0e10cSrcweir                                                         mpColorTable[ nGreen ],
1521cdf0e10cSrcweir                                                         mpColorTable[ nBlue ] ), bTransparent );
1522cdf0e10cSrcweir                 }
1523cdf0e10cSrcweir             }
1524cdf0e10cSrcweir             else
152588b53a7cSArmin Le Grand             {
152688b53a7cSArmin Le Grand                 // BMP_FORMAT_48BIT_TC_RGB
1527cdf0e10cSrcweir                 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
1528cdf0e10cSrcweir                 {
1529cdf0e10cSrcweir                     sal_uInt8 nRed = pTmp[ 0 ];
1530cdf0e10cSrcweir                     sal_uInt8 nGreen = pTmp[ 2 ];
1531cdf0e10cSrcweir                     sal_uInt8 nBlue = pTmp[ 4 ];
1532cdf0e10cSrcweir                     sal_Bool bTransparent = ( ( nRed == mnTransRed )
1533cdf0e10cSrcweir                                         && ( nGreen == mnTransGreen )
1534cdf0e10cSrcweir                                         && ( nBlue == mnTransBlue ) );
1535cdf0e10cSrcweir 
1536cdf0e10cSrcweir                     ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1537cdf0e10cSrcweir                                                         mpColorTable[ nGreen ],
1538cdf0e10cSrcweir                                                         mpColorTable[ nBlue ] ), bTransparent );
1539cdf0e10cSrcweir                 }
1540cdf0e10cSrcweir             }
1541cdf0e10cSrcweir         }
1542cdf0e10cSrcweir         else  // has RGB but neither alpha nor transparency
154388b53a7cSArmin Le Grand         {
154488b53a7cSArmin Le Grand             // BMP_FORMAT_24BIT_TC_RGB
154588b53a7cSArmin Le Grand             // only use DirectScanline when we have no preview shifting stuff and access to content
154688b53a7cSArmin Le Grand             const bool bDoDirectScanline(
154788b53a7cSArmin Le Grand                 bCkeckDirectScanline && !nXStart && 1 == nXAdd && !mnPreviewShift && mpAcc);
154888b53a7cSArmin Le Grand             const bool bCustomColorTable(mpColorTable != mpDefaultColorTable);
154988b53a7cSArmin Le Grand 
155088b53a7cSArmin Le Grand             if(bDoDirectScanline && !mpScanline)
155188b53a7cSArmin Le Grand             {
155288b53a7cSArmin Le Grand                 // allocate scanlines on demand, reused for next line
155388b53a7cSArmin Le Grand #ifdef DBG_UTIL
155488b53a7cSArmin Le Grand                 mnAllocSizeScanline = maOrigSize.Width() * 3;
155588b53a7cSArmin Le Grand #endif
155688b53a7cSArmin Le Grand                 mpScanline = new sal_uInt8[maOrigSize.Width() * 3];
155788b53a7cSArmin Le Grand             }
155888b53a7cSArmin Le Grand 
1559cdf0e10cSrcweir             if ( mnPngDepth == 8 )   // maybe the source has 16 bit per sample
1560cdf0e10cSrcweir             {
156188b53a7cSArmin Le Grand                 if(bDoDirectScanline)
156288b53a7cSArmin Le Grand                 {
156388b53a7cSArmin Le Grand                     OSL_ENSURE(mpScanline, "No Scanline allocated (!)");
156459c7f95bSHerbert Dürr #ifdef DBG_UTIL
156588b53a7cSArmin Le Grand                     OSL_ENSURE(mnAllocSizeScanline >= maOrigSize.Width() * 3, "Allocated Scanline too small (!)");
156659c7f95bSHerbert Dürr #endif
156788b53a7cSArmin Le Grand                     sal_uInt8* pScanline(mpScanline);
156888b53a7cSArmin Le Grand 
1569f037e03fSPavel Janík                     for(sal_Int32 nX(0); nX < maOrigSize.Width(); nX++, pTmp += 3)
157088b53a7cSArmin Le Grand                     {
157188b53a7cSArmin Le Grand                         // prepare content line as BGR by reordering when copying
157288b53a7cSArmin Le Grand                         if(bCustomColorTable)
157388b53a7cSArmin Le Grand                         {
157488b53a7cSArmin Le Grand                             *pScanline++ = mpColorTable[pTmp[2]];
157588b53a7cSArmin Le Grand                             *pScanline++ = mpColorTable[pTmp[1]];
157688b53a7cSArmin Le Grand                             *pScanline++ = mpColorTable[pTmp[0]];
157788b53a7cSArmin Le Grand                         }
157888b53a7cSArmin Le Grand                         else
157988b53a7cSArmin Le Grand                         {
158088b53a7cSArmin Le Grand                             *pScanline++ = pTmp[2];
158188b53a7cSArmin Le Grand                             *pScanline++ = pTmp[1];
158288b53a7cSArmin Le Grand                             *pScanline++ = pTmp[0];
158388b53a7cSArmin Le Grand                         }
158488b53a7cSArmin Le Grand                     }
158588b53a7cSArmin Le Grand 
158688b53a7cSArmin Le Grand                     // copy scanline directly to bitmap for content; use the format which is able to
158788b53a7cSArmin Le Grand                     // copy directly to BitmapBuffer
158888b53a7cSArmin Le Grand                     mpAcc->CopyScanline(nY, mpScanline, BMP_FORMAT_24BIT_TC_BGR, maOrigSize.Width() * 3);
158988b53a7cSArmin Le Grand                 }
159088b53a7cSArmin Le Grand                 else
1591cdf0e10cSrcweir                 {
1592cdf0e10cSrcweir                     for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
159388b53a7cSArmin Le Grand                     {
159488b53a7cSArmin Le Grand                         if(bCustomColorTable)
159588b53a7cSArmin Le Grand                         {
159688b53a7cSArmin Le Grand                             ImplSetPixel(
159788b53a7cSArmin Le Grand                                 nY,
159888b53a7cSArmin Le Grand                                 nX,
159988b53a7cSArmin Le Grand                                 BitmapColor(
160088b53a7cSArmin Le Grand                                     mpColorTable[ pTmp[ 0 ] ],
1601cdf0e10cSrcweir                                     mpColorTable[ pTmp[ 1 ] ],
1602cdf0e10cSrcweir                                     mpColorTable[ pTmp[ 2 ] ]));
1603cdf0e10cSrcweir                         }
1604cdf0e10cSrcweir                         else
1605cdf0e10cSrcweir                         {
160688b53a7cSArmin Le Grand                             ImplSetPixel(
160788b53a7cSArmin Le Grand                                 nY,
160888b53a7cSArmin Le Grand                                 nX,
160988b53a7cSArmin Le Grand                                 BitmapColor(
161088b53a7cSArmin Le Grand                                     pTmp[0],
161188b53a7cSArmin Le Grand                                     pTmp[1],
161288b53a7cSArmin Le Grand                                     pTmp[2]));
1613cdf0e10cSrcweir                         }
1614cdf0e10cSrcweir                     }
1615cdf0e10cSrcweir                 }
1616cdf0e10cSrcweir             }
1617cdf0e10cSrcweir             else
161888b53a7cSArmin Le Grand             {
161988b53a7cSArmin Le Grand                 // BMP_FORMAT_48BIT_TC_RGB
162088b53a7cSArmin Le Grand                 // no support currently for DirectScanline, found no real usages in current PNGs, may be added on demand
1621cdf0e10cSrcweir                 for ( sal_Int32 nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
162288b53a7cSArmin Le Grand                 {
162388b53a7cSArmin Le Grand                     ImplSetPixel(
162488b53a7cSArmin Le Grand                         nY,
162588b53a7cSArmin Le Grand                         nX,
162688b53a7cSArmin Le Grand                         BitmapColor(
162788b53a7cSArmin Le Grand                             mpColorTable[ pTmp[ 0 ] ],
1628cdf0e10cSrcweir                             mpColorTable[ pTmp[ 2 ] ],
1629cdf0e10cSrcweir                             mpColorTable[ pTmp[ 4 ] ]));
1630cdf0e10cSrcweir                 }
1631cdf0e10cSrcweir             }
1632cdf0e10cSrcweir         }
1633cdf0e10cSrcweir     }
163488b53a7cSArmin Le Grand }
1635cdf0e10cSrcweir 
1636cdf0e10cSrcweir // ------------------------------------------------------------------------
1637cdf0e10cSrcweir 
1638cdf0e10cSrcweir void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
1639cdf0e10cSrcweir {
1640cdf0e10cSrcweir     // TODO: get preview mode checks out of inner loop
1641cdf0e10cSrcweir     if( nX & mnPreviewMask )
1642cdf0e10cSrcweir         return;
1643cdf0e10cSrcweir     nX >>= mnPreviewShift;
1644cdf0e10cSrcweir 
1645cdf0e10cSrcweir     mpAcc->SetPixel( nY, nX, rBitmapColor );
1646cdf0e10cSrcweir }
1647cdf0e10cSrcweir 
1648cdf0e10cSrcweir // ------------------------------------------------------------------------
1649cdf0e10cSrcweir 
1650cdf0e10cSrcweir void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, sal_uInt8 nPalIndex )
1651cdf0e10cSrcweir {
1652cdf0e10cSrcweir     // TODO: get preview mode checks out of inner loop
1653cdf0e10cSrcweir     if( nX & mnPreviewMask )
1654cdf0e10cSrcweir         return;
1655cdf0e10cSrcweir     nX >>= mnPreviewShift;
1656cdf0e10cSrcweir 
1657cbfee35eSDamjan Jovanovic     if (nPalIndex >= mpAcc->GetPaletteEntryCount())
1658cbfee35eSDamjan Jovanovic         throw ::com::sun::star::lang::IndexOutOfBoundsException();
165987bc88d3SHerbert Dürr     mpAcc->SetPixelIndex( nY, nX, nPalIndex );
1660cdf0e10cSrcweir }
1661cdf0e10cSrcweir 
1662cdf0e10cSrcweir // ------------------------------------------------------------------------
1663cdf0e10cSrcweir 
1664cdf0e10cSrcweir void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, sal_Bool bTrans )
1665cdf0e10cSrcweir {
1666cdf0e10cSrcweir     // TODO: get preview mode checks out of inner loop
1667cdf0e10cSrcweir     if( nX & mnPreviewMask )
1668cdf0e10cSrcweir         return;
1669cdf0e10cSrcweir     nX >>= mnPreviewShift;
1670cdf0e10cSrcweir 
1671cdf0e10cSrcweir     mpAcc->SetPixel( nY, nX, rBitmapColor );
1672cdf0e10cSrcweir 
1673cdf0e10cSrcweir     if ( bTrans )
1674cdf0e10cSrcweir         mpMaskAcc->SetPixel( nY, nX, mcTranspColor );
1675cdf0e10cSrcweir     else
1676cdf0e10cSrcweir         mpMaskAcc->SetPixel( nY, nX, mcOpaqueColor );
1677cdf0e10cSrcweir }
1678cdf0e10cSrcweir 
1679cdf0e10cSrcweir // ------------------------------------------------------------------------
1680cdf0e10cSrcweir 
1681cdf0e10cSrcweir void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1682cdf0e10cSrcweir     sal_uInt8 nPalIndex, sal_uInt8 nAlpha )
1683cdf0e10cSrcweir {
1684cdf0e10cSrcweir     // TODO: get preview mode checks out of inner loop
1685cdf0e10cSrcweir     if( nX & mnPreviewMask )
1686cdf0e10cSrcweir         return;
1687cdf0e10cSrcweir     nX >>= mnPreviewShift;
1688cdf0e10cSrcweir 
1689cbfee35eSDamjan Jovanovic     if (nPalIndex >= mpAcc->GetPaletteEntryCount())
1690cbfee35eSDamjan Jovanovic         throw ::com::sun::star::lang::IndexOutOfBoundsException();
169187bc88d3SHerbert Dürr     mpAcc->SetPixelIndex( nY, nX, nPalIndex );
169287bc88d3SHerbert Dürr     mpMaskAcc->SetPixelIndex( nY, nX, ~nAlpha );
1693cdf0e10cSrcweir }
1694cdf0e10cSrcweir 
1695cdf0e10cSrcweir // ------------------------------------------------------------------------
1696cdf0e10cSrcweir 
1697cdf0e10cSrcweir void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1698cdf0e10cSrcweir     const BitmapColor& rBitmapColor, sal_uInt8 nAlpha )
1699cdf0e10cSrcweir {
1700cdf0e10cSrcweir     // TODO: get preview mode checks out of inner loop
1701cdf0e10cSrcweir     if( nX & mnPreviewMask )
1702cdf0e10cSrcweir         return;
1703cdf0e10cSrcweir     nX >>= mnPreviewShift;
1704cdf0e10cSrcweir 
1705cdf0e10cSrcweir     mpAcc->SetPixel( nY, nX, rBitmapColor );
170687bc88d3SHerbert Dürr     mpMaskAcc->SetPixelIndex( nY, nX, ~nAlpha );
1707cdf0e10cSrcweir }
1708cdf0e10cSrcweir 
1709cdf0e10cSrcweir // ------------------------------------------------------------------------
1710cdf0e10cSrcweir 
1711cdf0e10cSrcweir sal_uInt32 PNGReaderImpl::ImplReadsal_uInt32()
1712cdf0e10cSrcweir {
1713cdf0e10cSrcweir     sal_uInt32 nRet;
1714cdf0e10cSrcweir     nRet = *maDataIter++;
1715cdf0e10cSrcweir     nRet <<= 8;
1716cdf0e10cSrcweir     nRet |= *maDataIter++;
1717cdf0e10cSrcweir     nRet <<= 8;
1718cdf0e10cSrcweir     nRet |= *maDataIter++;
1719cdf0e10cSrcweir     nRet <<= 8;
1720cdf0e10cSrcweir     nRet |= *maDataIter++;
1721cdf0e10cSrcweir     return nRet;
1722cdf0e10cSrcweir }
1723cdf0e10cSrcweir 
1724cdf0e10cSrcweir // ------------------------------------------------------------------------
1725cdf0e10cSrcweir 
1726cdf0e10cSrcweir // -------------
1727cdf0e10cSrcweir // - PNGReader -
1728cdf0e10cSrcweir // -------------
1729cdf0e10cSrcweir 
1730cdf0e10cSrcweir PNGReader::PNGReader( SvStream& rIStm ) :
1731cdf0e10cSrcweir     mpImpl( new ::vcl::PNGReaderImpl( rIStm ) )
1732cdf0e10cSrcweir {
1733cdf0e10cSrcweir }
1734cdf0e10cSrcweir 
1735cdf0e10cSrcweir // ------------------------------------------------------------------------
1736cdf0e10cSrcweir 
1737cdf0e10cSrcweir PNGReader::~PNGReader()
1738cdf0e10cSrcweir {
1739cdf0e10cSrcweir     delete mpImpl;
1740cdf0e10cSrcweir }
1741cdf0e10cSrcweir 
1742cdf0e10cSrcweir // ------------------------------------------------------------------------
1743cdf0e10cSrcweir 
1744cdf0e10cSrcweir BitmapEx PNGReader::Read( const Size& i_rPreviewSizeHint )
1745cdf0e10cSrcweir {
1746cdf0e10cSrcweir     return mpImpl->GetBitmapEx( i_rPreviewSizeHint );
1747cdf0e10cSrcweir }
1748cdf0e10cSrcweir 
1749cdf0e10cSrcweir // ------------------------------------------------------------------------
1750cdf0e10cSrcweir 
1751cdf0e10cSrcweir const std::vector< vcl::PNGReader::ChunkData >& PNGReader::GetChunks() const
1752cdf0e10cSrcweir {
1753cdf0e10cSrcweir     return mpImpl->GetAllChunks();
1754cdf0e10cSrcweir }
1755cdf0e10cSrcweir 
1756cdf0e10cSrcweir // ------------------------------------------------------------------------
1757cdf0e10cSrcweir 
1758cdf0e10cSrcweir void PNGReader::SetIgnoreGammaChunk( sal_Bool b )
1759cdf0e10cSrcweir {
1760cdf0e10cSrcweir     mpImpl->SetIgnoreGammaChunk( b );
1761cdf0e10cSrcweir }
1762cdf0e10cSrcweir 
1763cdf0e10cSrcweir 
1764cdf0e10cSrcweir } // namespace vcl
1765