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
130  || !(colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA))
131  {
132  png_destroy_read_struct(&pPng, &pInfo, nullptr);
133  return false;
134  }
135 
136  {
137  if (colorType == PNG_COLOR_TYPE_RGB)
138  {
139  size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
140 
141  Bitmap aBitmap(Size(width, height), 24);
142  {
143  BitmapScopedWriteAccess pWriteAccess(aBitmap);
144  ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
145  if (eFormat == ScanlineFormat::N24BitTcBgr)
146  png_set_bgr(pPng);
147 
148  std::vector<std::vector<png_byte>> aRows(height);
149  for (auto& rRow : aRows)
150  rRow.resize(aRowSizeBytes, 0);
151 
152  for (int pass = 0; pass < nNumberOfPasses; pass++)
153  {
154  for (png_uint_32 y = 0; y < height; y++)
155  {
156  Scanline pScanline = pWriteAccess->GetScanline(y);
157  png_bytep pRow = aRows[y].data();
158  png_read_row(pPng, pRow, nullptr);
159  size_t iColor = 0;
160  for (size_t i = 0; i < aRowSizeBytes; i += 3)
161  {
162  pScanline[iColor++] = pRow[i + 0];
163  pScanline[iColor++] = pRow[i + 1];
164  pScanline[iColor++] = pRow[i + 2];
165  }
166  }
167  }
168  }
169  rBitmapEx = BitmapEx(aBitmap);
170  }
171  else if (colorType == PNG_COLOR_TYPE_RGB_ALPHA)
172  {
173  size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
174 
175  if (bUseBitmap32)
176  {
177  Bitmap aBitmap(Size(width, height), 32);
178  {
179  BitmapScopedWriteAccess pWriteAccess(aBitmap);
180  ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
181  if (eFormat == ScanlineFormat::N32BitTcAbgr
182  || eFormat == ScanlineFormat::N32BitTcBgra)
183  {
184  png_set_bgr(pPng);
185  }
186 
187  std::vector<std::vector<png_byte>> aRows(height);
188  for (auto& rRow : aRows)
189  rRow.resize(aRowSizeBytes, 0);
190 
191  for (int pass = 0; pass < nNumberOfPasses; pass++)
192  {
193  for (png_uint_32 y = 0; y < height; y++)
194  {
195  Scanline pScanline = pWriteAccess->GetScanline(y);
196  png_bytep pRow = aRows[y].data();
197  png_read_row(pPng, pRow, nullptr);
198  size_t iColor = 0;
199  for (size_t i = 0; i < aRowSizeBytes; i += 4)
200  {
201  sal_Int8 alpha = pRow[i + 3];
202  pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 0], alpha);
203  pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 1], alpha);
204  pScanline[iColor++] = vcl::bitmap::premultiply(pRow[i + 2], alpha);
205  pScanline[iColor++] = alpha;
206  }
207  }
208  }
209  }
210  rBitmapEx = BitmapEx(aBitmap);
211  }
212  else
213  {
214  Bitmap aBitmap(Size(width, height), 24);
215  AlphaMask aBitmapAlpha(Size(width, height), nullptr);
216  {
217  BitmapScopedWriteAccess pWriteAccess(aBitmap);
218  ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat();
219  if (eFormat == ScanlineFormat::N24BitTcBgr)
220  png_set_bgr(pPng);
221 
222  AlphaScopedWriteAccess pWriteAccessAlpha(aBitmapAlpha);
223 
224  std::vector<std::vector<png_byte>> aRows(height);
225  for (auto& rRow : aRows)
226  rRow.resize(aRowSizeBytes, 0);
227 
228  for (int pass = 0; pass < nNumberOfPasses; pass++)
229  {
230  for (png_uint_32 y = 0; y < height; y++)
231  {
232  Scanline pScanline = pWriteAccess->GetScanline(y);
233  Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y);
234  png_bytep pRow = aRows[y].data();
235  png_read_row(pPng, pRow, nullptr);
236  size_t iAlpha = 0;
237  size_t iColor = 0;
238  for (size_t i = 0; i < aRowSizeBytes; i += 4)
239  {
240  pScanline[iColor++] = pRow[i + 0];
241  pScanline[iColor++] = pRow[i + 1];
242  pScanline[iColor++] = pRow[i + 2];
243  pScanAlpha[iAlpha++] = 0xFF - pRow[i + 3];
244  }
245  }
246  }
247  }
248  rBitmapEx = BitmapEx(aBitmap, aBitmapAlpha);
249  }
250  }
251  }
252 
253  png_read_end(pPng, pInfo);
254 
255  png_destroy_read_struct(&pPng, &pInfo, nullptr);
256 
257  return true;
258 }
259 
260 } // anonymous namespace
261 
262 namespace vcl
263 {
265  : mrStream(rStream)
266 {
267 }
268 
270 {
271  auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities();
272  bool bSupportsBitmap32 = pBackendCapabilities->mbSupportsBitmap32;
273 
274  return reader(mrStream, rBitmapEx, bSupportsBitmap32);
275 }
276 
277 } // namespace vcl
278 
279 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
signed char sal_Int8
bool read(BitmapEx &rBitmap)
This template handles BitmapAccess the RAII way.
ScanlineFormat
Definition: Scanline.hxx:28
sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
float y
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:66
sal_uInt8 * Scanline
Definition: Scanline.hxx:25
virtual std::shared_ptr< vcl::BackendCapabilities > GetBackendCapabilities()
Definition: salinst.hxx:135
int i
pass
std::size_t ReadBytes(void *pData, std::size_t nSize)
unsigned char sal_uInt8
PngImageReader(SvStream &rStream)
SalInstance * mpDefInst
Definition: svdata.hxx:341