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