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