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/pngwrite.hxx> 32 33 #include <cmath> 34 #include <limits> 35 #include <rtl/crc.h> 36 #include <rtl/memory.h> 37 #include <rtl/alloc.h> 38 #include <tools/zcodec.hxx> 39 #include <tools/stream.hxx> 40 #include <vcl/bmpacc.hxx> 41 #include <vcl/svapp.hxx> 42 #include <vcl/alpha.hxx> 43 #include <osl/endian.h> 44 45 // ----------- 46 // - Defines - 47 // ----------- 48 49 #define PNG_DEF_COMPRESSION 6 50 51 #define PNGCHUNK_IHDR 0x49484452 52 #define PNGCHUNK_PLTE 0x504c5445 53 #define PNGCHUNK_IDAT 0x49444154 54 #define PNGCHUNK_IEND 0x49454e44 55 #define PNGCHUNK_bKGD 0x624b4744 56 #define PNGCHUNK_cHRM 0x6348524d 57 #define PNGCHUNK_gAMA 0x67414d41 58 #define PNGCHUNK_hIST 0x68495354 59 #define PNGCHUNK_pHYs 0x70485973 60 #define PNGCHUNK_sBIT 0x73425420 61 #define PNGCHUNK_tIME 0x74494d45 62 #define PNGCHUNK_tEXt 0x74455874 63 #define PNGCHUNK_tRNS 0x74524e53 64 #define PNGCHUNK_zTXt 0x7a545874 65 66 namespace vcl 67 { 68 // ----------------- 69 // - PNGWriterImplImpl - 70 // ----------------- 71 72 class PNGWriterImpl 73 { 74 public: 75 76 PNGWriterImpl( const BitmapEx& BmpEx, 77 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL ); 78 ~PNGWriterImpl(); 79 80 sal_Bool Write( SvStream& rOStm ); 81 82 std::vector< vcl::PNGWriter::ChunkData >& GetChunks(); 83 84 private: 85 86 std::vector< vcl::PNGWriter::ChunkData > maChunkSeq; 87 88 sal_Int32 mnCompLevel; 89 sal_Int32 mnInterlaced; 90 sal_uInt32 mnMaxChunkSize; 91 sal_Bool mbStatus; 92 93 BitmapReadAccess* mpAccess; 94 BitmapReadAccess* mpMaskAccess; 95 ZCodec* mpZCodec; 96 97 sal_uInt8* mpDeflateInBuf; // as big as the size of a scanline + alphachannel + 1 98 sal_uInt8* mpPreviousScan; // as big as mpDeflateInBuf 99 sal_uInt8* mpCurrentScan; 100 sal_uLong mnDeflateInSize; 101 102 sal_uLong mnWidth, mnHeight; 103 sal_uInt8 mnBitsPerPixel; 104 sal_uInt8 mnFilterType; // 0 oder 4; 105 sal_uLong mnBBP; // bytes per pixel ( needed for filtering ) 106 sal_Bool mbTrueAlpha; 107 sal_uLong mnCRC; 108 long mnChunkDatSize; 109 sal_uLong mnLastPercent; 110 111 void ImplWritepHYs( const BitmapEx& rBitmapEx ); 112 void ImplWriteIDAT(); 113 sal_uLong ImplGetFilter( sal_uLong nY, sal_uLong nXStart=0, sal_uLong nXAdd=1 ); 114 void ImplClearFirstScanline(); 115 void ImplWriteTransparent(); 116 sal_Bool ImplWriteHeader(); 117 void ImplWritePalette(); 118 void ImplOpenChunk( sal_uLong nChunkType ); 119 void ImplWriteChunk( sal_uInt8 nNumb ); 120 void ImplWriteChunk( sal_uInt32 nNumb ); 121 void ImplWriteChunk( unsigned char* pSource, sal_uInt32 nDatSize ); 122 void ImplCloseChunk( void ); 123 }; 124 125 // ------------------------------------------------------------------------ 126 127 PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx, 128 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) : 129 mnCompLevel ( PNG_DEF_COMPRESSION ), 130 mbStatus ( sal_True ), 131 mpAccess ( NULL ), 132 mpMaskAccess ( NULL ), 133 mpZCodec ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ), 134 mnCRC(0UL), 135 mnLastPercent ( 0UL ) 136 { 137 if ( !rBmpEx.IsEmpty() ) 138 { 139 Bitmap aBmp( rBmpEx.GetBitmap() ); 140 141 mnInterlaced = 0; // ( aBmp.GetSizePixel().Width() > 128 ) || ( aBmp.GetSizePixel().Height() > 128 ) ? 1 : 0; #i67236# 142 143 // #i67234# defaulting max chunk size to 256kb when using interlace mode 144 mnMaxChunkSize = mnInterlaced == 0 ? std::numeric_limits< sal_uInt32 >::max() : 0x40000; 145 146 if ( pFilterData ) 147 { 148 sal_Int32 i = 0; 149 for ( i = 0; i < pFilterData->getLength(); i++ ) 150 { 151 if ( (*pFilterData)[ i ].Name.equalsAscii( "Compression" ) ) 152 (*pFilterData)[ i ].Value >>= mnCompLevel; 153 else if ( (*pFilterData)[ i ].Name.equalsAscii( "Interlaced" ) ) 154 (*pFilterData)[ i ].Value >>= mnInterlaced; 155 else if ( (*pFilterData)[ i ].Name.equalsAscii( "MaxChunkSize" ) ) 156 { 157 sal_Int32 nVal = 0; 158 if ( (*pFilterData)[ i ].Value >>= nVal ) 159 mnMaxChunkSize = (sal_uInt32)nVal; 160 } 161 } 162 } 163 mnBitsPerPixel = (sal_uInt8)aBmp.GetBitCount(); 164 165 if( rBmpEx.IsTransparent() ) 166 { 167 if ( mnBitsPerPixel <= 8 && rBmpEx.IsAlpha() ) 168 { 169 aBmp.Convert( BMP_CONVERSION_24BIT ); 170 mnBitsPerPixel = 24; 171 } 172 173 if ( mnBitsPerPixel <= 8 ) // transparent palette 174 { 175 aBmp.Convert( BMP_CONVERSION_8BIT_TRANS ); 176 aBmp.Replace( rBmpEx.GetMask(), BMP_COL_TRANS ); 177 mnBitsPerPixel = 8; 178 mpAccess = aBmp.AcquireReadAccess(); 179 if ( mpAccess ) 180 { 181 if ( ImplWriteHeader() ) 182 { 183 ImplWritepHYs( rBmpEx ); 184 ImplWritePalette(); 185 ImplWriteTransparent(); 186 ImplWriteIDAT(); 187 } 188 aBmp.ReleaseAccess( mpAccess ); 189 } 190 else 191 mbStatus = sal_False; 192 } 193 else 194 { 195 mpAccess = aBmp.AcquireReadAccess(); // sal_True RGB with alphachannel 196 if( mpAccess ) 197 { 198 if ( ( mbTrueAlpha = rBmpEx.IsAlpha() ) != sal_False ) 199 { 200 AlphaMask aMask( rBmpEx.GetAlpha() ); 201 mpMaskAccess = aMask.AcquireReadAccess(); 202 if ( mpMaskAccess ) 203 { 204 if ( ImplWriteHeader() ) 205 { 206 ImplWritepHYs( rBmpEx ); 207 ImplWriteIDAT(); 208 } 209 aMask.ReleaseAccess( mpMaskAccess ); 210 } 211 else 212 mbStatus = sal_False; 213 } 214 else 215 { 216 Bitmap aMask( rBmpEx.GetMask() ); 217 mpMaskAccess = aMask.AcquireReadAccess(); 218 if( mpMaskAccess ) 219 { 220 if ( ImplWriteHeader() ) 221 { 222 ImplWritepHYs( rBmpEx ); 223 ImplWriteIDAT(); 224 } 225 aMask.ReleaseAccess( mpMaskAccess ); 226 } 227 else 228 mbStatus = sal_False; 229 } 230 aBmp.ReleaseAccess( mpAccess ); 231 } 232 else 233 mbStatus = sal_False; 234 } 235 } 236 else 237 { 238 mpAccess = aBmp.AcquireReadAccess(); // palette + RGB without alphachannel 239 if( mpAccess ) 240 { 241 if ( ImplWriteHeader() ) 242 { 243 ImplWritepHYs( rBmpEx ); 244 if( mpAccess->HasPalette() ) 245 ImplWritePalette(); 246 247 ImplWriteIDAT(); 248 } 249 aBmp.ReleaseAccess( mpAccess ); 250 } 251 else 252 mbStatus = sal_False; 253 } 254 if ( mbStatus ) 255 { 256 ImplOpenChunk( PNGCHUNK_IEND ); // create an IEND chunk 257 ImplCloseChunk(); 258 } 259 } 260 } 261 262 // ------------------------------------------------------------------------ 263 264 PNGWriterImpl::~PNGWriterImpl() 265 { 266 delete mpZCodec; 267 } 268 269 // ------------------------------------------------------------------------ 270 271 sal_Bool PNGWriterImpl::Write( SvStream& rOStm ) 272 { 273 /* png signature is always an array of 8 bytes */ 274 sal_uInt16 nOldMode = rOStm.GetNumberFormatInt(); 275 rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); 276 rOStm << static_cast<sal_uInt32>(0x89504e47); 277 rOStm << static_cast<sal_uInt32>(0x0d0a1a0a); 278 279 std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg( maChunkSeq.begin() ); 280 std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd( maChunkSeq.end() ); 281 while( aBeg != aEnd ) 282 { 283 sal_uInt32 nType = aBeg->nType; 284 #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN) 285 nType = SWAPLONG( nType ); 286 #endif 287 sal_uInt32 nCRC = rtl_crc32( 0, &nType, 4 ); 288 sal_uInt32 nDataSize = aBeg->aData.size(); 289 if ( nDataSize ) 290 nCRC = rtl_crc32( nCRC, &aBeg->aData[ 0 ], nDataSize ); 291 rOStm << nDataSize 292 << aBeg->nType; 293 if ( nDataSize ) 294 rOStm.Write( &aBeg->aData[ 0 ], nDataSize ); 295 rOStm << nCRC; 296 aBeg++; 297 } 298 rOStm.SetNumberFormatInt( nOldMode ); 299 return mbStatus; 300 } 301 302 // ------------------------------------------------------------------------ 303 304 std::vector< vcl::PNGWriter::ChunkData >& PNGWriterImpl::GetChunks() 305 { 306 return maChunkSeq; 307 } 308 309 // ------------------------------------------------------------------------ 310 311 sal_Bool PNGWriterImpl::ImplWriteHeader() 312 { 313 ImplOpenChunk(PNGCHUNK_IHDR); 314 ImplWriteChunk( sal_uInt32( mnWidth = mpAccess->Width() ) ); 315 ImplWriteChunk( sal_uInt32( mnHeight = mpAccess->Height() ) ); 316 317 if ( mnWidth && mnHeight && mnBitsPerPixel && mbStatus ) 318 { 319 sal_uInt8 nBitDepth = mnBitsPerPixel; 320 if ( mnBitsPerPixel <= 8 ) 321 mnFilterType = 0; 322 else 323 mnFilterType = 4; 324 325 sal_uInt8 nColorType = 2; // colortype: 326 // bit 0 -> palette is used 327 if ( mpAccess->HasPalette() ) // bit 1 -> color is used 328 nColorType |= 1; // bit 2 -> alpha channel is used 329 else 330 nBitDepth /= 3; 331 332 if ( mpMaskAccess ) 333 nColorType |= 4; 334 335 ImplWriteChunk( nBitDepth ); 336 ImplWriteChunk( nColorType ); // colortype 337 ImplWriteChunk((sal_uInt8) 0 ); // compression type 338 ImplWriteChunk((sal_uInt8) 0 ); // filter type - is not supported in this version 339 ImplWriteChunk((sal_uInt8) mnInterlaced ); // interlace type 340 ImplCloseChunk(); 341 } 342 else 343 mbStatus = sal_False; 344 return mbStatus; 345 } 346 347 // ------------------------------------------------------------------------ 348 349 void PNGWriterImpl::ImplWritePalette() 350 { 351 const sal_uLong nCount = mpAccess->GetPaletteEntryCount(); 352 sal_uInt8* pTempBuf = new sal_uInt8[ nCount*3 ]; 353 sal_uInt8* pTmp = pTempBuf; 354 355 ImplOpenChunk( PNGCHUNK_PLTE ); 356 357 for ( sal_uInt16 i = 0; i < nCount; i++ ) 358 { 359 const BitmapColor& rColor = mpAccess->GetPaletteColor( i ); 360 *pTmp++ = rColor.GetRed(); 361 *pTmp++ = rColor.GetGreen(); 362 *pTmp++ = rColor.GetBlue(); 363 } 364 ImplWriteChunk( pTempBuf, nCount*3 ); 365 ImplCloseChunk(); 366 delete[] pTempBuf; 367 } 368 369 // ------------------------------------------------------------------------ 370 371 void PNGWriterImpl::ImplWriteTransparent () 372 { 373 const sal_uLong nTransIndex = mpAccess->GetBestMatchingColor( BMP_COL_TRANS ); 374 375 ImplOpenChunk( PNGCHUNK_tRNS ); 376 377 for ( sal_uLong n = 0UL; n <= nTransIndex; n++ ) 378 ImplWriteChunk( ( nTransIndex == n ) ? (sal_uInt8) 0x0 : (sal_uInt8) 0xff ); 379 380 ImplCloseChunk(); 381 } 382 383 // ------------------------------------------------------------------------ 384 385 void PNGWriterImpl::ImplWritepHYs( const BitmapEx& rBmpEx ) 386 { 387 if ( rBmpEx.GetPrefMapMode() == MAP_100TH_MM ) 388 { 389 Size aPrefSize( rBmpEx.GetPrefSize() ); 390 if ( aPrefSize.Width() && aPrefSize.Height() ) 391 { 392 ImplOpenChunk( PNGCHUNK_pHYs ); 393 sal_uInt8 nMapUnit = 1; 394 sal_uInt32 nPrefSizeX = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Width() / mnWidth ) + 0.5 ); 395 sal_uInt32 nPrefSizeY = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Height() / mnHeight ) + 0.5 ); 396 ImplWriteChunk( nPrefSizeX ); 397 ImplWriteChunk( nPrefSizeY ); 398 ImplWriteChunk( nMapUnit ); 399 ImplCloseChunk(); 400 } 401 } 402 } 403 404 // ------------------------------------------------------------------------ 405 406 void PNGWriterImpl::ImplWriteIDAT () 407 { 408 mnDeflateInSize = mnBitsPerPixel; 409 410 if( mpMaskAccess ) 411 mnDeflateInSize += 8; 412 413 mnBBP = ( mnDeflateInSize + 7 ) >> 3; 414 415 mnDeflateInSize = mnBBP * mnWidth + 1; 416 417 mpDeflateInBuf = new sal_uInt8[ mnDeflateInSize ]; 418 419 if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times 420 { 421 mpPreviousScan = new sal_uInt8[ mnDeflateInSize ]; 422 mpCurrentScan = new sal_uInt8[ mnDeflateInSize ]; 423 ImplClearFirstScanline(); 424 } 425 mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT + mnCompLevel ); 426 mpZCodec->SetCRC( mnCRC ); 427 SvMemoryStream aOStm; 428 if ( mnInterlaced == 0 ) 429 { 430 for ( sal_uLong nY = 0; nY < mnHeight; nY++ ) 431 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter( nY ) ); 432 } 433 else 434 { 435 // interlace mode 436 sal_uLong nY; 437 for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 1 438 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 8 ) ); 439 ImplClearFirstScanline(); 440 441 for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 2 442 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 4, 8 ) ); 443 ImplClearFirstScanline(); 444 445 if ( mnHeight >= 5 ) // pass 3 446 { 447 for ( nY = 4; nY < mnHeight; nY+=8 ) 448 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 4 ) ); 449 ImplClearFirstScanline(); 450 } 451 452 for ( nY = 0; nY < mnHeight; nY+=4 ) // pass 4 453 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 2, 4 ) ); 454 ImplClearFirstScanline(); 455 456 if ( mnHeight >= 3 ) // pass 5 457 { 458 for ( nY = 2; nY < mnHeight; nY+=4 ) 459 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 2 ) ); 460 ImplClearFirstScanline(); 461 } 462 463 for ( nY = 0; nY < mnHeight; nY+=2 ) // pass 6 464 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 1, 2 ) ); 465 ImplClearFirstScanline(); 466 467 if ( mnHeight >= 2 ) // pass 7 468 { 469 for ( nY = 1; nY < mnHeight; nY+=2 ) 470 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 1 ) ); 471 } 472 } 473 mpZCodec->EndCompression(); 474 mnCRC = mpZCodec->GetCRC(); 475 476 if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times 477 { 478 delete[] mpCurrentScan; 479 delete[] mpPreviousScan; 480 } 481 delete[] mpDeflateInBuf; 482 483 sal_uInt32 nIDATSize = aOStm.Tell(); 484 sal_uInt32 nBytes, nBytesToWrite = nIDATSize; 485 while( nBytesToWrite ) 486 { 487 nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize; 488 ImplOpenChunk( PNGCHUNK_IDAT ); 489 ImplWriteChunk( (unsigned char*)aOStm.GetData() + ( nIDATSize - nBytesToWrite ), nBytes ); 490 ImplCloseChunk(); 491 nBytesToWrite -= nBytes; 492 } 493 } 494 495 // --------------------------------------------------------------------------------------------------- 496 // ImplGetFilter writes the complete Scanline (nY) - in interlace mode the parameter nXStart and nXAdd 497 // appends to the currently used pass 498 // the complete size of scanline will be returned - in interlace mode zero is possible! 499 500 sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uLong nXAdd ) 501 { 502 sal_uInt8* pDest; 503 504 if ( mnFilterType ) 505 pDest = mpCurrentScan; 506 else 507 pDest = mpDeflateInBuf; 508 509 if ( nXStart < mnWidth ) 510 { 511 *pDest++ = mnFilterType; // in this version the filter type is either 0 or 4 512 513 if ( mpAccess->HasPalette() ) // alphachannel is not allowed by pictures including palette entries 514 { 515 switch ( mnBitsPerPixel ) 516 { 517 case( 1 ): 518 { 519 sal_uLong nX, nXIndex; 520 for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+=nXAdd, nXIndex++ ) 521 { 522 sal_uLong nShift = ( nXIndex & 7 ) ^ 7; 523 if ( nShift == 7) 524 *pDest = (sal_uInt8)(mpAccess->GetPixel( nY, nX ) << nShift); 525 else if ( nShift == 0 ) 526 *pDest++ |= (sal_uInt8) mpAccess->GetPixel( nY, nX ) << nShift; 527 else 528 *pDest |= (sal_uInt8) mpAccess->GetPixel( nY, nX ) << nShift; 529 } 530 if ( ( nXIndex & 7 ) != 0 ) pDest++; // byte is not completely used, so the 531 } // bufferpointer is to correct 532 break; 533 534 case( 4 ): 535 { 536 sal_uLong nX, nXIndex; 537 for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+= nXAdd, nXIndex++ ) 538 { 539 if( nXIndex & 1 ) 540 *pDest++ |= (sal_uInt8) mpAccess->GetPixel( nY, nX ); 541 else 542 *pDest = (sal_uInt8) mpAccess->GetPixel( nY, nX ) << 4; 543 } 544 if ( nXIndex & 1 ) pDest++; 545 } 546 break; 547 548 case( 8 ): 549 { 550 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd ) 551 *pDest++ = mpAccess->GetPixel( nY, nX ); 552 } 553 break; 554 555 default : 556 mbStatus = sal_False; 557 break; 558 } 559 } 560 else 561 { 562 if ( mpMaskAccess ) // mpMaskAccess != NULL -> alphachannel is to create 563 { 564 if ( mbTrueAlpha ) 565 { 566 for ( sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd ) 567 { 568 const BitmapColor& rColor = mpAccess->GetPixel( nY, nX ); 569 *pDest++ = rColor.GetRed(); 570 *pDest++ = rColor.GetGreen(); 571 *pDest++ = rColor.GetBlue(); 572 *pDest++ = 255 - mpMaskAccess->GetPixel( nY, nX ); 573 } 574 } 575 else 576 { 577 const BitmapColor aTrans( mpMaskAccess->GetBestMatchingColor( Color( COL_WHITE ) ) ); 578 579 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd ) 580 { 581 const BitmapColor& rColor = mpAccess->GetPixel( nY, nX ); 582 *pDest++ = rColor.GetRed(); 583 *pDest++ = rColor.GetGreen(); 584 *pDest++ = rColor.GetBlue(); 585 586 if( mpMaskAccess->GetPixel( nY, nX ) == aTrans ) 587 *pDest++ = 0; 588 else 589 *pDest++ = 0xff; 590 } 591 } 592 } 593 else 594 { 595 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd ) 596 { 597 const BitmapColor& rColor = mpAccess->GetPixel( nY, nX ); 598 *pDest++ = rColor.GetRed(); 599 *pDest++ = rColor.GetGreen(); 600 *pDest++ = rColor.GetBlue(); 601 } 602 } 603 } 604 } 605 // filter type4 ( PAETH ) will be used only for 24bit graphics 606 if ( mnFilterType ) 607 { 608 mnDeflateInSize = pDest - mpCurrentScan; 609 pDest = mpDeflateInBuf; 610 *pDest++ = 4; // filter type 611 612 sal_uLong na, nb, nc; 613 long np, npa, npb, npc; 614 615 sal_uInt8* p1 = mpCurrentScan + 1; // Current Pixel 616 sal_uInt8* p2 = p1 - mnBBP; // left pixel 617 sal_uInt8* p3 = mpPreviousScan; // upper pixel 618 sal_uInt8* p4 = p3 - mnBBP; // upperleft Pixel; 619 620 while ( pDest < mpDeflateInBuf + mnDeflateInSize ) 621 { 622 nb = *p3++; 623 if ( p2 >= mpCurrentScan + 1 ) 624 { 625 na = *p2; 626 nc = *p4; 627 } 628 else 629 na = nc = 0; 630 631 np = na + nb; 632 np -= nc; 633 npa = np - na; 634 npb = np - nb; 635 npc = np - nc; 636 if ( npa < 0 ) 637 npa =-npa; 638 if ( npb < 0 ) 639 npb =-npb; 640 if ( npc < 0 ) 641 npc =-npc; 642 if ( ( npa <= npb ) && ( npa <= npc ) ) *pDest++ = *p1++ - (sal_uInt8)na; 643 else if ( npb <= npc ) *pDest++ = *p1++ - (sal_uInt8)nb; 644 else *pDest++ = *p1++ - (sal_uInt8)nc; 645 p4++; 646 p2++; 647 } 648 for ( long i = 0; i < (long)( mnDeflateInSize - 1 ); i++ ) 649 mpPreviousScan[ i ] = mpCurrentScan[ i + 1 ]; 650 } 651 else 652 mnDeflateInSize = pDest - mpDeflateInBuf; 653 return ( mnDeflateInSize ); 654 } 655 656 // ------------------------------------------------------------------------ 657 658 void PNGWriterImpl::ImplClearFirstScanline() 659 { 660 if ( mnFilterType ) 661 rtl_zeroMemory( mpPreviousScan, mnDeflateInSize ); 662 } 663 664 // ------------------------------------------------------------------------ 665 666 void PNGWriterImpl::ImplOpenChunk ( sal_uLong nChunkType ) 667 { 668 maChunkSeq.resize( maChunkSeq.size() + 1 ); 669 maChunkSeq.back().nType = nChunkType; 670 } 671 672 // ------------------------------------------------------------------------ 673 674 void PNGWriterImpl::ImplWriteChunk ( sal_uInt8 nSource ) 675 { 676 maChunkSeq.back().aData.push_back( nSource ); 677 } 678 679 void PNGWriterImpl::ImplWriteChunk ( sal_uInt32 nSource ) 680 { 681 vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back(); 682 rChunkData.aData.push_back( (sal_uInt8)( nSource >> 24 ) ); 683 rChunkData.aData.push_back( (sal_uInt8)( nSource >> 16 ) ); 684 rChunkData.aData.push_back( (sal_uInt8)( nSource >> 8 ) ); 685 rChunkData.aData.push_back( (sal_uInt8)( nSource ) ); 686 } 687 688 void PNGWriterImpl::ImplWriteChunk ( unsigned char* pSource, sal_uInt32 nDatSize ) 689 { 690 if ( nDatSize ) 691 { 692 vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back(); 693 sal_uInt32 nSize = rChunkData.aData.size(); 694 rChunkData.aData.resize( nSize + nDatSize ); 695 rtl_copyMemory( &rChunkData.aData[ nSize ], pSource, nDatSize ); 696 } 697 } 698 699 // ------------------------------------------------------------------------ 700 // nothing to do 701 void PNGWriterImpl::ImplCloseChunk ( void ) 702 { 703 } 704 705 // ------------- 706 // - PNGWriter - 707 // ------------- 708 709 PNGWriter::PNGWriter( const BitmapEx& rBmpEx, 710 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) : 711 mpImpl( new ::vcl::PNGWriterImpl( rBmpEx, pFilterData ) ) 712 { 713 } 714 715 // ------------------------------------------------------------------------ 716 717 PNGWriter::~PNGWriter() 718 { 719 delete mpImpl; 720 } 721 722 // ------------------------------------------------------------------------ 723 724 sal_Bool PNGWriter::Write( SvStream& rIStm ) 725 { 726 return mpImpl->Write( rIStm ); 727 } 728 729 // ------------------------------------------------------------------------ 730 731 std::vector< vcl::PNGWriter::ChunkData >& PNGWriter::GetChunks() 732 { 733 return mpImpl->GetChunks(); 734 } 735 736 } // namespace vcl 737 738