xref: /AOO41X/main/vcl/source/gdi/pngwrite.cxx (revision 87bc88d3ed834c36654f277ed18005c290f77bdd)
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 
PNGWriterImpl(const BitmapEx & rBmpEx,const::com::sun::star::uno::Sequence<::com::sun::star::beans::PropertyValue> * pFilterData)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 
~PNGWriterImpl()260 PNGWriterImpl::~PNGWriterImpl()
261 {
262     delete mpZCodec;
263 }
264 
265 // ------------------------------------------------------------------------
266 
Write(SvStream & rOStm)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 
GetChunks()300 std::vector< vcl::PNGWriter::ChunkData >& PNGWriterImpl::GetChunks()
301 {
302     return maChunkSeq;
303 }
304 
305 // ------------------------------------------------------------------------
306 
ImplWriteHeader()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 
ImplWritePalette()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 
ImplWriteTransparent()367 void PNGWriterImpl::ImplWriteTransparent ()
368 {
369     const sal_uLong nTransIndex = mpAccess->GetBestPaletteIndex( 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 
ImplWritepHYs(const BitmapEx & rBmpEx)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 
ImplWriteIDAT()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 
ImplGetFilter(sal_uLong nY,sal_uLong nXStart,sal_uLong nXAdd)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 = mpAccess->GetPixelIndex( nY, nX ) << nShift;
521                         else if  ( nShift == 0 )
522                             *pDest++ |= mpAccess->GetPixelIndex( nY, nX ) << nShift;
523                         else
524                             *pDest |= mpAccess->GetPixelIndex( 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++ |= mpAccess->GetPixelIndex( nY, nX );
537                         else
538                             *pDest = mpAccess->GetPixelIndex( 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->GetPixelIndex( 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->GetPixelIndex( 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 
ImplClearFirstScanline()654 void PNGWriterImpl::ImplClearFirstScanline()
655 {
656     if ( mnFilterType )
657         rtl_zeroMemory( mpPreviousScan, mnDeflateInSize );
658 }
659 
660 // ------------------------------------------------------------------------
661 
ImplOpenChunk(sal_uLong nChunkType)662 void PNGWriterImpl::ImplOpenChunk ( sal_uLong nChunkType )
663 {
664     maChunkSeq.resize( maChunkSeq.size() + 1 );
665     maChunkSeq.back().nType = nChunkType;
666 }
667 
668 // ------------------------------------------------------------------------
669 
ImplWriteChunk(sal_uInt8 nSource)670 void PNGWriterImpl::ImplWriteChunk ( sal_uInt8 nSource )
671 {
672     maChunkSeq.back().aData.push_back( nSource );
673 }
674 
ImplWriteChunk(sal_uInt32 nSource)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 
ImplWriteChunk(unsigned char * pSource,sal_uInt32 nDatSize)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
ImplCloseChunk(void)697 void PNGWriterImpl::ImplCloseChunk ( void )
698 {
699 }
700 
701 // -------------
702 // - PNGWriter -
703 // -------------
704 
PNGWriter(const BitmapEx & rBmpEx,const::com::sun::star::uno::Sequence<::com::sun::star::beans::PropertyValue> * pFilterData)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 
~PNGWriter()713 PNGWriter::~PNGWriter()
714 {
715     delete mpImpl;
716 }
717 
718 // ------------------------------------------------------------------------
719 
Write(SvStream & rIStm)720 sal_Bool PNGWriter::Write( SvStream& rIStm )
721 {
722     return mpImpl->Write( rIStm );
723 }
724 
725 // ------------------------------------------------------------------------
726 
GetChunks()727 std::vector< vcl::PNGWriter::ChunkData >& PNGWriter::GetChunks()
728 {
729     return mpImpl->GetChunks();
730 }
731 
732 } // namespace vcl
733 
734