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