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