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

Generated by: LCOV version 1.11