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