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