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