update credits
[LibreOffice.git] / vcl / source / gdi / pngwrite.cxx
blobf7c60860c67f17accba15249e313a5511dc1eb56
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <vcl/pngwrite.hxx>
23 #include <cmath>
24 #include <limits>
25 #include <rtl/crc.h>
26 #include <rtl/alloc.h>
27 #include <tools/zcodec.hxx>
28 #include <tools/stream.hxx>
29 #include <vcl/bmpacc.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/alpha.hxx>
32 #include <osl/endian.h>
34 #define PNG_DEF_COMPRESSION 6
36 #define PNGCHUNK_IHDR 0x49484452
37 #define PNGCHUNK_PLTE 0x504c5445
38 #define PNGCHUNK_IDAT 0x49444154
39 #define PNGCHUNK_IEND 0x49454e44
40 #define PNGCHUNK_pHYs 0x70485973
41 #define PNGCHUNK_tRNS 0x74524e53
43 namespace vcl
46 class PNGWriterImpl
48 public:
50 PNGWriterImpl( const BitmapEx& BmpEx,
51 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData = NULL );
52 ~PNGWriterImpl();
54 sal_Bool Write( SvStream& rOStm );
56 std::vector< vcl::PNGWriter::ChunkData >& GetChunks();
58 private:
60 std::vector< vcl::PNGWriter::ChunkData > maChunkSeq;
62 sal_Int32 mnCompLevel;
63 sal_Int32 mnInterlaced;
64 sal_uInt32 mnMaxChunkSize;
65 sal_Bool mbStatus;
67 BitmapReadAccess* mpAccess;
68 BitmapReadAccess* mpMaskAccess;
69 ZCodec* mpZCodec;
71 sal_uInt8* mpDeflateInBuf; // as big as the size of a scanline + alphachannel + 1
72 sal_uInt8* mpPreviousScan; // as big as mpDeflateInBuf
73 sal_uInt8* mpCurrentScan;
74 sal_uLong mnDeflateInSize;
76 sal_uLong mnWidth, mnHeight;
77 sal_uInt8 mnBitsPerPixel;
78 sal_uInt8 mnFilterType; // 0 oder 4;
79 sal_uLong mnBBP; // bytes per pixel ( needed for filtering )
80 sal_Bool mbTrueAlpha;
81 sal_uLong mnCRC;
83 void ImplWritepHYs( const BitmapEx& rBitmapEx );
84 void ImplWriteIDAT();
85 sal_uLong ImplGetFilter( sal_uLong nY, sal_uLong nXStart=0, sal_uLong nXAdd=1 );
86 void ImplClearFirstScanline();
87 void ImplWriteTransparent();
88 sal_Bool ImplWriteHeader();
89 void ImplWritePalette();
90 void ImplOpenChunk( sal_uLong nChunkType );
91 void ImplWriteChunk( sal_uInt8 nNumb );
92 void ImplWriteChunk( sal_uInt32 nNumb );
93 void ImplWriteChunk( unsigned char* pSource, sal_uInt32 nDatSize );
94 void ImplCloseChunk( void ) const;
97 PNGWriterImpl::PNGWriterImpl( const BitmapEx& rBmpEx,
98 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
99 mnCompLevel ( PNG_DEF_COMPRESSION ),
100 mbStatus ( sal_True ),
101 mpAccess ( NULL ),
102 mpMaskAccess ( NULL ),
103 mpZCodec ( new ZCodec( DEFAULT_IN_BUFSIZE, DEFAULT_OUT_BUFSIZE, MAX_MEM_USAGE ) ),
104 mnCRC(0UL)
106 if ( !rBmpEx.IsEmpty() )
108 Bitmap aBmp( rBmpEx.GetBitmap() );
110 mnInterlaced = 0; // ( aBmp.GetSizePixel().Width() > 128 ) || ( aBmp.GetSizePixel().Height() > 128 ) ? 1 : 0; #i67236#
112 // #i67234# defaulting max chunk size to 256kb when using interlace mode
113 mnMaxChunkSize = mnInterlaced == 0 ? std::numeric_limits< sal_uInt32 >::max() : 0x40000;
115 if ( pFilterData )
117 sal_Int32 i = 0;
118 for ( i = 0; i < pFilterData->getLength(); i++ )
120 if ( (*pFilterData)[ i ].Name == "Compression" )
121 (*pFilterData)[ i ].Value >>= mnCompLevel;
122 else if ( (*pFilterData)[ i ].Name == "Interlaced" )
123 (*pFilterData)[ i ].Value >>= mnInterlaced;
124 else if ( (*pFilterData)[ i ].Name == "MaxChunkSize" )
126 sal_Int32 nVal = 0;
127 if ( (*pFilterData)[ i ].Value >>= nVal )
128 mnMaxChunkSize = (sal_uInt32)nVal;
132 mnBitsPerPixel = (sal_uInt8)aBmp.GetBitCount();
134 if( rBmpEx.IsTransparent() )
136 if ( mnBitsPerPixel <= 8 && rBmpEx.IsAlpha() )
138 aBmp.Convert( BMP_CONVERSION_24BIT );
139 mnBitsPerPixel = 24;
142 if ( mnBitsPerPixel <= 8 ) // transparent palette
144 aBmp.Convert( BMP_CONVERSION_8BIT_TRANS );
145 aBmp.Replace( rBmpEx.GetMask(), BMP_COL_TRANS );
146 mnBitsPerPixel = 8;
147 mpAccess = aBmp.AcquireReadAccess();
148 if ( mpAccess )
150 if ( ImplWriteHeader() )
152 ImplWritepHYs( rBmpEx );
153 ImplWritePalette();
154 ImplWriteTransparent();
155 ImplWriteIDAT();
157 aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
159 else
160 mbStatus = sal_False;
162 else
164 mpAccess = aBmp.AcquireReadAccess(); // sal_True RGB with alphachannel
165 if( mpAccess )
167 if ( ( mbTrueAlpha = rBmpEx.IsAlpha() ) != sal_False )
169 AlphaMask aMask( rBmpEx.GetAlpha() );
170 mpMaskAccess = aMask.AcquireReadAccess();
171 if ( mpMaskAccess )
173 if ( ImplWriteHeader() )
175 ImplWritepHYs( rBmpEx );
176 ImplWriteIDAT();
178 aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
180 else
181 mbStatus = sal_False;
183 else
185 Bitmap aMask( rBmpEx.GetMask() );
186 mpMaskAccess = aMask.AcquireReadAccess();
187 if( mpMaskAccess )
189 if ( ImplWriteHeader() )
191 ImplWritepHYs( rBmpEx );
192 ImplWriteIDAT();
194 aMask.ReleaseAccess( mpMaskAccess ), mpMaskAccess = 0;
196 else
197 mbStatus = sal_False;
199 aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
201 else
202 mbStatus = sal_False;
205 else
207 mpAccess = aBmp.AcquireReadAccess(); // palette + RGB without alphachannel
208 if( mpAccess )
210 if ( ImplWriteHeader() )
212 ImplWritepHYs( rBmpEx );
213 if( mpAccess->HasPalette() )
214 ImplWritePalette();
216 ImplWriteIDAT();
218 aBmp.ReleaseAccess( mpAccess ), mpAccess = 0;
220 else
221 mbStatus = sal_False;
223 if ( mbStatus )
225 ImplOpenChunk( PNGCHUNK_IEND ); // create an IEND chunk
226 ImplCloseChunk();
231 PNGWriterImpl::~PNGWriterImpl()
233 delete mpZCodec;
236 sal_Bool PNGWriterImpl::Write( SvStream& rOStm )
238 /* png signature is always an array of 8 bytes */
239 sal_uInt16 nOldMode = rOStm.GetNumberFormatInt();
240 rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
241 rOStm << static_cast<sal_uInt32>(0x89504e47);
242 rOStm << static_cast<sal_uInt32>(0x0d0a1a0a);
244 std::vector< vcl::PNGWriter::ChunkData >::iterator aBeg( maChunkSeq.begin() );
245 std::vector< vcl::PNGWriter::ChunkData >::iterator aEnd( maChunkSeq.end() );
246 while( aBeg != aEnd )
248 sal_uInt32 nType = aBeg->nType;
249 #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
250 nType = OSL_SWAPDWORD( nType );
251 #endif
252 sal_uInt32 nCRC = rtl_crc32( 0, &nType, 4 );
253 sal_uInt32 nDataSize = aBeg->aData.size();
254 if ( nDataSize )
255 nCRC = rtl_crc32( nCRC, &aBeg->aData[ 0 ], nDataSize );
256 rOStm << nDataSize
257 << aBeg->nType;
258 if ( nDataSize )
259 rOStm.Write( &aBeg->aData[ 0 ], nDataSize );
260 rOStm << nCRC;
261 ++aBeg;
263 rOStm.SetNumberFormatInt( nOldMode );
264 return mbStatus;
267 std::vector< vcl::PNGWriter::ChunkData >& PNGWriterImpl::GetChunks()
269 return maChunkSeq;
272 sal_Bool PNGWriterImpl::ImplWriteHeader()
274 ImplOpenChunk(PNGCHUNK_IHDR);
275 ImplWriteChunk( sal_uInt32( mnWidth = mpAccess->Width() ) );
276 ImplWriteChunk( sal_uInt32( mnHeight = mpAccess->Height() ) );
278 if ( mnWidth && mnHeight && mnBitsPerPixel && mbStatus )
280 sal_uInt8 nBitDepth = mnBitsPerPixel;
281 if ( mnBitsPerPixel <= 8 )
282 mnFilterType = 0;
283 else
284 mnFilterType = 4;
286 sal_uInt8 nColorType = 2; // colortype:
287 // bit 0 -> palette is used
288 if ( mpAccess->HasPalette() ) // bit 1 -> color is used
289 nColorType |= 1; // bit 2 -> alpha channel is used
290 else
291 nBitDepth /= 3;
293 if ( mpMaskAccess )
294 nColorType |= 4;
296 ImplWriteChunk( nBitDepth );
297 ImplWriteChunk( nColorType ); // colortype
298 ImplWriteChunk((sal_uInt8) 0 ); // compression type
299 ImplWriteChunk((sal_uInt8) 0 ); // filter type - is not supported in this version
300 ImplWriteChunk((sal_uInt8) mnInterlaced ); // interlace type
301 ImplCloseChunk();
303 else
304 mbStatus = sal_False;
305 return mbStatus;
308 void PNGWriterImpl::ImplWritePalette()
310 const sal_uLong nCount = mpAccess->GetPaletteEntryCount();
311 sal_uInt8* pTempBuf = new sal_uInt8[ nCount*3 ];
312 sal_uInt8* pTmp = pTempBuf;
314 ImplOpenChunk( PNGCHUNK_PLTE );
316 for ( sal_uInt16 i = 0; i < nCount; i++ )
318 const BitmapColor& rColor = mpAccess->GetPaletteColor( i );
319 *pTmp++ = rColor.GetRed();
320 *pTmp++ = rColor.GetGreen();
321 *pTmp++ = rColor.GetBlue();
323 ImplWriteChunk( pTempBuf, nCount*3 );
324 ImplCloseChunk();
325 delete[] pTempBuf;
328 void PNGWriterImpl::ImplWriteTransparent ()
330 const sal_uLong nTransIndex = mpAccess->GetBestPaletteIndex( BMP_COL_TRANS );
332 ImplOpenChunk( PNGCHUNK_tRNS );
334 for ( sal_uLong n = 0UL; n <= nTransIndex; n++ )
335 ImplWriteChunk( ( nTransIndex == n ) ? (sal_uInt8) 0x0 : (sal_uInt8) 0xff );
337 ImplCloseChunk();
340 void PNGWriterImpl::ImplWritepHYs( const BitmapEx& rBmpEx )
342 if ( rBmpEx.GetPrefMapMode() == MAP_100TH_MM )
344 Size aPrefSize( rBmpEx.GetPrefSize() );
345 if ( aPrefSize.Width() && aPrefSize.Height() )
347 ImplOpenChunk( PNGCHUNK_pHYs );
348 sal_uInt8 nMapUnit = 1;
349 sal_uInt32 nPrefSizeX = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Width() / mnWidth ) + 0.5 );
350 sal_uInt32 nPrefSizeY = (sal_uInt32)( (double)100000.0 / ( (double)aPrefSize.Height() / mnHeight ) + 0.5 );
351 ImplWriteChunk( nPrefSizeX );
352 ImplWriteChunk( nPrefSizeY );
353 ImplWriteChunk( nMapUnit );
354 ImplCloseChunk();
359 void PNGWriterImpl::ImplWriteIDAT ()
361 mnDeflateInSize = mnBitsPerPixel;
363 if( mpMaskAccess )
364 mnDeflateInSize += 8;
366 mnBBP = ( mnDeflateInSize + 7 ) >> 3;
368 mnDeflateInSize = mnBBP * mnWidth + 1;
370 mpDeflateInBuf = new sal_uInt8[ mnDeflateInSize ];
372 if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times
374 mpPreviousScan = new sal_uInt8[ mnDeflateInSize ];
375 mpCurrentScan = new sal_uInt8[ mnDeflateInSize ];
376 ImplClearFirstScanline();
378 mpZCodec->BeginCompression( ZCODEC_PNG_DEFAULT + mnCompLevel );
379 mpZCodec->SetCRC( mnCRC );
380 SvMemoryStream aOStm;
381 if ( mnInterlaced == 0 )
383 for ( sal_uLong nY = 0; nY < mnHeight; nY++ )
384 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter( nY ) );
386 else
388 // interlace mode
389 sal_uLong nY;
390 for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 1
391 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 8 ) );
392 ImplClearFirstScanline();
394 for ( nY = 0; nY < mnHeight; nY+=8 ) // pass 2
395 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 4, 8 ) );
396 ImplClearFirstScanline();
398 if ( mnHeight >= 5 ) // pass 3
400 for ( nY = 4; nY < mnHeight; nY+=8 )
401 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 4 ) );
402 ImplClearFirstScanline();
405 for ( nY = 0; nY < mnHeight; nY+=4 ) // pass 4
406 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 2, 4 ) );
407 ImplClearFirstScanline();
409 if ( mnHeight >= 3 ) // pass 5
411 for ( nY = 2; nY < mnHeight; nY+=4 )
412 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 2 ) );
413 ImplClearFirstScanline();
416 for ( nY = 0; nY < mnHeight; nY+=2 ) // pass 6
417 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 1, 2 ) );
418 ImplClearFirstScanline();
420 if ( mnHeight >= 2 ) // pass 7
422 for ( nY = 1; nY < mnHeight; nY+=2 )
423 mpZCodec->Write( aOStm, mpDeflateInBuf, ImplGetFilter ( nY, 0, 1 ) );
426 mpZCodec->EndCompression();
427 mnCRC = mpZCodec->GetCRC();
429 if ( mnFilterType ) // using filter type 4 we need memory for the scanline 3 times
431 delete[] mpCurrentScan;
432 delete[] mpPreviousScan;
434 delete[] mpDeflateInBuf;
436 sal_uInt32 nIDATSize = aOStm.Tell();
437 sal_uInt32 nBytes, nBytesToWrite = nIDATSize;
438 while( nBytesToWrite )
440 nBytes = nBytesToWrite <= mnMaxChunkSize ? nBytesToWrite : mnMaxChunkSize;
441 ImplOpenChunk( PNGCHUNK_IDAT );
442 ImplWriteChunk( (unsigned char*)aOStm.GetData() + ( nIDATSize - nBytesToWrite ), nBytes );
443 ImplCloseChunk();
444 nBytesToWrite -= nBytes;
448 // ImplGetFilter writes the complete Scanline (nY) - in interlace mode the parameter nXStart and nXAdd
449 // appends to the currently used pass
450 // the complete size of scanline will be returned - in interlace mode zero is possible!
452 sal_uLong PNGWriterImpl::ImplGetFilter ( sal_uLong nY, sal_uLong nXStart, sal_uLong nXAdd )
454 sal_uInt8* pDest;
456 if ( mnFilterType )
457 pDest = mpCurrentScan;
458 else
459 pDest = mpDeflateInBuf;
461 if ( nXStart < mnWidth )
463 *pDest++ = mnFilterType; // in this version the filter type is either 0 or 4
465 if ( mpAccess->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
467 switch ( mnBitsPerPixel )
469 case( 1 ):
471 sal_uLong nX, nXIndex;
472 for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+=nXAdd, nXIndex++ )
474 sal_uLong nShift = ( nXIndex & 7 ) ^ 7;
475 if ( nShift == 7)
476 *pDest = mpAccess->GetPixelIndex( nY, nX ) << nShift;
477 else if ( nShift == 0 )
478 *pDest++ |= mpAccess->GetPixelIndex( nY, nX ) << nShift;
479 else
480 *pDest |= mpAccess->GetPixelIndex( nY, nX ) << nShift;
482 if ( ( nXIndex & 7 ) != 0 ) pDest++; // byte is not completely used, so the
483 } // bufferpointer is to correct
484 break;
486 case( 4 ):
488 sal_uLong nX, nXIndex;
489 for ( nX = nXStart, nXIndex = 0; nX < mnWidth; nX+= nXAdd, nXIndex++ )
491 if( nXIndex & 1 )
492 *pDest++ |= mpAccess->GetPixelIndex( nY, nX );
493 else
494 *pDest = mpAccess->GetPixelIndex( nY, nX ) << 4;
496 if ( nXIndex & 1 ) pDest++;
498 break;
500 case( 8 ):
502 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
503 *pDest++ = mpAccess->GetPixelIndex( nY, nX );
505 break;
507 default :
508 mbStatus = sal_False;
509 break;
512 else
514 if ( mpMaskAccess ) // mpMaskAccess != NULL -> alphachannel is to create
516 if ( mbTrueAlpha )
518 for ( sal_uLong nX = nXStart; nX < mnWidth; nX += nXAdd )
520 const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
521 *pDest++ = rColor.GetRed();
522 *pDest++ = rColor.GetGreen();
523 *pDest++ = rColor.GetBlue();
524 *pDest++ = 255 - mpMaskAccess->GetPixelIndex( nY, nX );
527 else
529 const BitmapColor aTrans( mpMaskAccess->GetBestMatchingColor( Color( COL_WHITE ) ) );
531 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
533 const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
534 *pDest++ = rColor.GetRed();
535 *pDest++ = rColor.GetGreen();
536 *pDest++ = rColor.GetBlue();
538 if( mpMaskAccess->GetPixel( nY, nX ) == aTrans )
539 *pDest++ = 0;
540 else
541 *pDest++ = 0xff;
545 else
547 for ( sal_uLong nX = nXStart; nX < mnWidth; nX+=nXAdd )
549 const BitmapColor& rColor = mpAccess->GetPixel( nY, nX );
550 *pDest++ = rColor.GetRed();
551 *pDest++ = rColor.GetGreen();
552 *pDest++ = rColor.GetBlue();
557 // filter type4 ( PAETH ) will be used only for 24bit graphics
558 if ( mnFilterType )
560 mnDeflateInSize = pDest - mpCurrentScan;
561 pDest = mpDeflateInBuf;
562 *pDest++ = 4; // filter type
564 sal_uLong na, nb, nc;
565 long np, npa, npb, npc;
567 sal_uInt8* p1 = mpCurrentScan + 1; // Current Pixel
568 sal_uInt8* p2 = p1 - mnBBP; // left pixel
569 sal_uInt8* p3 = mpPreviousScan; // upper pixel
570 sal_uInt8* p4 = p3 - mnBBP; // upperleft Pixel;
572 while ( pDest < mpDeflateInBuf + mnDeflateInSize )
574 nb = *p3++;
575 if ( p2 >= mpCurrentScan + 1 )
577 na = *p2;
578 nc = *p4;
580 else
581 na = nc = 0;
583 np = na + nb;
584 np -= nc;
585 npa = np - na;
586 npb = np - nb;
587 npc = np - nc;
588 if ( npa < 0 )
589 npa =-npa;
590 if ( npb < 0 )
591 npb =-npb;
592 if ( npc < 0 )
593 npc =-npc;
594 if ( ( npa <= npb ) && ( npa <= npc ) ) *pDest++ = *p1++ - (sal_uInt8)na;
595 else if ( npb <= npc ) *pDest++ = *p1++ - (sal_uInt8)nb;
596 else *pDest++ = *p1++ - (sal_uInt8)nc;
597 p4++;
598 p2++;
600 for ( long i = 0; i < (long)( mnDeflateInSize - 1 ); i++ )
601 mpPreviousScan[ i ] = mpCurrentScan[ i + 1 ];
603 else
604 mnDeflateInSize = pDest - mpDeflateInBuf;
605 return ( mnDeflateInSize );
608 void PNGWriterImpl::ImplClearFirstScanline()
610 if ( mnFilterType )
611 memset( mpPreviousScan, 0, mnDeflateInSize );
614 void PNGWriterImpl::ImplOpenChunk ( sal_uLong nChunkType )
616 maChunkSeq.resize( maChunkSeq.size() + 1 );
617 maChunkSeq.back().nType = nChunkType;
620 void PNGWriterImpl::ImplWriteChunk ( sal_uInt8 nSource )
622 maChunkSeq.back().aData.push_back( nSource );
625 void PNGWriterImpl::ImplWriteChunk ( sal_uInt32 nSource )
627 vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
628 rChunkData.aData.push_back( (sal_uInt8)( nSource >> 24 ) );
629 rChunkData.aData.push_back( (sal_uInt8)( nSource >> 16 ) );
630 rChunkData.aData.push_back( (sal_uInt8)( nSource >> 8 ) );
631 rChunkData.aData.push_back( (sal_uInt8)( nSource ) );
634 void PNGWriterImpl::ImplWriteChunk ( unsigned char* pSource, sal_uInt32 nDatSize )
636 if ( nDatSize )
638 vcl::PNGWriter::ChunkData& rChunkData = maChunkSeq.back();
639 sal_uInt32 nSize = rChunkData.aData.size();
640 rChunkData.aData.resize( nSize + nDatSize );
641 memcpy( &rChunkData.aData[ nSize ], pSource, nDatSize );
645 // nothing to do
646 void PNGWriterImpl::ImplCloseChunk ( void ) const
650 PNGWriter::PNGWriter( const BitmapEx& rBmpEx,
651 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) :
652 mpImpl( new ::vcl::PNGWriterImpl( rBmpEx, pFilterData ) )
656 PNGWriter::~PNGWriter()
658 delete mpImpl;
661 sal_Bool PNGWriter::Write( SvStream& rIStm )
663 return mpImpl->Write( rIStm );
666 std::vector< vcl::PNGWriter::ChunkData >& PNGWriter::GetChunks()
668 return mpImpl->GetChunks();
671 } // namespace vcl
673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */