LCOV - code coverage report
Current view: top level - vcl/source/gdi - pngread.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 597 696 85.8 %
Date: 2014-04-11 Functions: 28 29 96.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10