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