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