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