LibreOffice Module vcl (master)  1
PngImageReader.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  */
10 
12 #include <png.h>
13 #include <tools/stream.hxx>
14 #include <bitmapwriteaccess.hxx>
15 #include <vcl/bitmap.hxx>
16 #include <vcl/alpha.hxx>
17 #include <vcl/BitmapTools.hxx>
18 #include <svdata.hxx>
19 #include <salinst.hxx>
20 
21 namespace
22 {
23 void lclReadStream(png_structp pPng, png_bytep pOutBytes, png_size_t nBytesToRead)
24 {
25  png_voidp pIO = png_get_io_ptr(pPng);
26 
27  if (pIO == nullptr)
28  return;
29 
30  SvStream* pStream = static_cast<SvStream*>(pIO);
31 
32  sal_Size nBytesRead = pStream->ReadBytes(pOutBytes, nBytesToRead);
33 
34  if (nBytesRead != nBytesToRead)
35  png_error(pPng, "Error reading");
36 }
37 
38 bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
39 {
40  enum
41  {
42  PNG_SIGNATURE_SIZE = 8
43  };
44 
45  // Check signature bytes
46  sal_uInt8 aHeader[PNG_SIGNATURE_SIZE];
47  rStream.ReadBytes(aHeader, PNG_SIGNATURE_SIZE);
48 
49  if (png_sig_cmp(aHeader, 0, PNG_SIGNATURE_SIZE))
50  return false;
51 
52  png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
53  if (!pPng)
54  return false;
55 
56  png_infop pInfo = png_create_info_struct(pPng);
57  if (!pInfo)
58  {
59  png_destroy_read_struct(&pPng, nullptr, nullptr);
60  return false;
61  }
62 
63  if (setjmp(png_jmpbuf(pPng)))
64  {
65  png_destroy_read_struct(&pPng, &pInfo, nullptr);
66  return false;
67  }
68 
69  png_set_option(pPng, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
70 
71  png_set_read_fn(pPng, &rStream, lclReadStream);
72 
73  png_set_crc_action(pPng, PNG_CRC_ERROR_QUIT, PNG_CRC_WARN_DISCARD);
74 
75  png_set_sig_bytes(pPng, PNG_SIGNATURE_SIZE);
76 
77  png_read_info(pPng, pInfo);
78 
79  png_uint_32 width = 0;
80  png_uint_32 height = 0;
81  int bitDepth = 0;
82  int colorType = -1;
83  int interlace = -1;
84 
85  png_uint_32 returnValue = png_get_IHDR(pPng, pInfo, &width, &height, &bitDepth, &colorType,
86  &interlace, nullptr, nullptr);
87 
88  if (returnValue != 1)
89  {
90  png_destroy_read_struct(&pPng, &pInfo, nullptr);
91  return false;
92  }
93 
94  if (colorType == PNG_COLOR_TYPE_PALETTE)
95  png_set_palette_to_rgb(pPng);
96 
97  if (colorType == PNG_COLOR_TYPE_GRAY)
98  png_set_expand_gray_1_2_4_to_8(pPng);
99 
100  if (png_get_valid(pPng, pInfo, PNG_INFO_tRNS))
101  png_set_tRNS_to_alpha(pPng);
102 
103  if (bitDepth == 16)
104  png_set_scale_16(pPng);
105 
106  if (bitDepth < 8)
107  png_set_packing(pPng);
108 
109  if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
110  {
111  png_set_gray_to_rgb(pPng);
112  }
113 
114  // Sets the filler byte - if RGB it converts to RGBA
115  // png_set_filler(pPng, 0xFF, PNG_FILLER_AFTER);
116 
117  int nNumberOfPasses = png_set_interlace_handling(pPng);
118 
119  png_read_update_info(pPng, pInfo);
120  returnValue = png_get_IHDR(pPng, pInfo, &width, &height, &bitDepth, &colorType, nullptr,
121  nullptr, nullptr);
122 
123  if (returnValue != 1)
124  {
125  png_destroy_read_struct(&pPng, &pInfo, nullptr);
126  return false;
127  }
128 
129  if (bitDepth != 8 || (colorType != PNG_COLOR_TYPE_RGB && colorType != PNG_COLOR_TYPE_RGB_ALPHA))
130  {
131  png_destroy_read_struct(&pPng, &pInfo, nullptr);
132  return false;
133  }
134 
135  {
136  if (colorType == PNG_COLOR_TYPE_RGB)
137  {
138  size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
139 
140  Bitmap aBitmap(Size(width, height), 24);
141  {
142  BitmapScopedWriteAccess pWriteAccess(aBitmap);
143  ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
144  if (eFormat == ScanlineFormat::N24BitTcBgr)
145  png_set_bgr(pPng);
146 
147  std::vector<std::vector<png_byte>> aRows(height);
148  for (auto& rRow : aRows)
149  rRow.resize(aRowSizeBytes, 0);
150 
151  for (int pass = 0; pass < nNumberOfPasses; pass++)
152  {
153  for (png_uint_32 y = 0; y < height; y++)
154  {
155  Scanline pScanline = pWriteAccess->GetScanline(y);
156  png_bytep pRow = aRows[y].data();
157  png_read_row(pPng, pRow, nullptr);
158  size_t iColor = 0;
159  for (size_t i = 0; i < aRowSizeBytes; i += 3)
160  {
161  pScanline[iColor++] = pRow[i + 0];
162  pScanline[iColor++] = pRow[i + 1];
163  pScanline[iColor++] = pRow[i + 2];
164  }
165  }
166  }
167  }
168  rBitmapEx = BitmapEx(aBitmap);
169  }
170  else if (colorType == PNG_COLOR_TYPE_RGB_ALPHA)
171  {
172  size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
173 
174  if (bUseBitmap32)
175  {
176  Bitmap aBitmap(Size(width, height), 32);
177  {
178  BitmapScopedWriteAccess pWriteAccess(aBitmap);
179  ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
180  if (eFormat == ScanlineFormat::N32BitTcAbgr
181  || eFormat == ScanlineFormat::N32BitTcBgra)
182  {
183  png_set_bgr(pPng);
184  }
185 
186  std::vector<std::vector<png_byte>> aRows(height);
187  for (auto& rRow : aRows)
188  rRow.resize(aRowSizeBytes, 0);
189 
190  auto const alphaFirst = (eFormat == ScanlineFormat::N32BitTcAbgr
191  || eFormat == ScanlineFormat::N32BitTcArgb);
192  for (int pass = 0; pass < nNumberOfPasses; pass++)
193  {
194  for (png_uint_32 y = 0; y < height; y++)
195  {
196  Scanline pScanline = pWriteAccess->GetScanline(y);
197  png_bytep pRow = aRows[y].data();
198  png_read_row(pPng, pRow, nullptr);
199  size_t iColor = 0;
200  for (size_t i = 0; i < aRowSizeBytes; i += 4)
201  {
202  sal_Int8 alpha = pRow[i + 3];
203  if (alphaFirst)
204  {
205  pScanline[iColor++] = alpha;
206  }
207  pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 0], alpha);
208  pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 1], alpha);
209  pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 2], alpha);
210  if (!alphaFirst)
211  {
212  pScanline[iColor++] = alpha;
213  }
214  }
215  }
216  }
217  }
218  rBitmapEx = BitmapEx(aBitmap);
219  }
220  else
221  {
222  Bitmap aBitmap(Size(width, height), 24);
223  AlphaMask aBitmapAlpha(Size(width, height), nullptr);
224  {
225  BitmapScopedWriteAccess pWriteAccess(aBitmap);
226  ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
227  if (eFormat == ScanlineFormat::N24BitTcBgr)
228  png_set_bgr(pPng);
229 
230  AlphaScopedWriteAccess pWriteAccessAlpha(aBitmapAlpha);
231 
232  std::vector<std::vector<png_byte>> aRows(height);
233  for (auto& rRow : aRows)
234  rRow.resize(aRowSizeBytes, 0);
235 
236  for (int pass = 0; pass < nNumberOfPasses; pass++)
237  {
238  for (png_uint_32 y = 0; y < height; y++)
239  {
240  Scanline pScanline = pWriteAccess->GetScanline(y);
241  Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y);
242  png_bytep pRow = aRows[y].data();
243  png_read_row(pPng, pRow, nullptr);
244  size_t iAlpha = 0;
245  size_t iColor = 0;
246  for (size_t i = 0; i < aRowSizeBytes; i += 4)
247  {
248  pScanline[iColor++] = pRow[i + 0];
249  pScanline[iColor++] = pRow[i + 1];
250  pScanline[iColor++] = pRow[i + 2];
251  pScanAlpha[iAlpha++] = 0xFF - pRow[i + 3];
252  }
253  }
254  }
255  }
256  rBitmapEx = BitmapEx(aBitmap, aBitmapAlpha);
257  }
258  }
259  }
260 
261  png_read_end(pPng, pInfo);
262 
263  png_destroy_read_struct(&pPng, &pInfo, nullptr);
264 
265  return true;
266 }
267 
268 } // anonymous namespace
269 
270 namespace vcl
271 {
273  : mrStream(rStream)
274 {
275 }
276 
278 {
279  auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities();
280  bool bSupportsBitmap32 = pBackendCapabilities->mbSupportsBitmap32;
281 
282  return reader(mrStream, rBitmapEx, bSupportsBitmap32);
283 }
284 
285 } // namespace vcl
286 
287 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
signed char sal_Int8
bool read(BitmapEx &rBitmap)
ScanlineFormat
Definition: Scanline.hxx:28
float y
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
int i
virtual std::shared_ptr< vcl::BackendCapabilities > GetBackendCapabilities()
Definition: salinst.hxx:132
pass
std::size_t ReadBytes(void *pData, std::size_t nSize)
unsigned char sal_uInt8
PngImageReader(SvStream &rStream)
SalInstance * mpDefInst
Definition: svdata.hxx:381