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