26 void lclReadStream(png_structp pPng, png_bytep pOutBytes, png_size_t nBytesToRead)
28 png_voidp pIO = png_get_io_ptr(pPng);
35 sal_Size nBytesRead = pStream->
ReadBytes(pOutBytes, nBytesToRead);
37 if (nBytesRead != nBytesToRead)
40 png_error(pPng,
"Error reading");
44 memset(pOutBytes + nBytesRead, 0, nBytesToRead - nBytesRead);
45 png_warning(pPng,
"Short read");
50 constexpr
int PNG_SIGNATURE_SIZE = 8;
56 rStream.
ReadBytes(aHeader, PNG_SIGNATURE_SIZE);
58 return png_sig_cmp(aHeader, 0, PNG_SIGNATURE_SIZE) == 0;
66 png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
70 png_infop pInfo = png_create_info_struct(pPng);
73 png_destroy_read_struct(&pPng,
nullptr,
nullptr);
85 std::vector<std::vector<png_byte>> aRows;
87 if (setjmp(png_jmpbuf(pPng)))
89 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
93 pWriteAccessAlpha.
reset();
95 rBitmapEx =
BitmapEx(aBitmap, aBitmapAlpha);
106 png_set_option(pPng, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
108 png_set_read_fn(pPng, &rStream, lclReadStream);
111 png_set_crc_action(pPng, PNG_CRC_ERROR_QUIT, PNG_CRC_WARN_DISCARD);
113 png_set_crc_action(pPng, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
115 png_set_sig_bytes(pPng, PNG_SIGNATURE_SIZE);
117 png_read_info(pPng, pInfo);
119 png_uint_32 width = 0;
120 png_uint_32 height = 0;
125 png_uint_32 returnValue = png_get_IHDR(pPng, pInfo, &width, &height, &bitDepth, &colorType,
126 &interlace,
nullptr,
nullptr);
128 if (returnValue != 1)
130 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
134 if (colorType == PNG_COLOR_TYPE_PALETTE)
135 png_set_palette_to_rgb(pPng);
137 if (colorType == PNG_COLOR_TYPE_GRAY)
138 png_set_expand_gray_1_2_4_to_8(pPng);
140 if (png_get_valid(pPng, pInfo, PNG_INFO_tRNS))
141 png_set_tRNS_to_alpha(pPng);
144 png_set_scale_16(pPng);
147 png_set_packing(pPng);
150 if (colorType == PNG_COLOR_TYPE_GRAY_ALPHA
151 || (colorType == PNG_COLOR_TYPE_GRAY && png_get_valid(pPng, pInfo, PNG_INFO_tRNS)))
153 png_set_gray_to_rgb(pPng);
159 int nNumberOfPasses = png_set_interlace_handling(pPng);
161 png_read_update_info(pPng, pInfo);
162 returnValue = png_get_IHDR(pPng, pInfo, &width, &height, &bitDepth, &colorType,
nullptr,
165 if (returnValue != 1)
167 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
172 || (colorType != PNG_COLOR_TYPE_RGB && colorType != PNG_COLOR_TYPE_RGB_ALPHA
173 && colorType != PNG_COLOR_TYPE_GRAY))
175 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
179 png_uint_32 res_x = 0;
180 png_uint_32 res_y = 0;
182 if (png_get_pHYs(pPng, pInfo, &res_x, &res_y, &unit_type) != 0
183 && unit_type == PNG_RESOLUTION_METER && res_x && res_y)
186 prefSize =
Size(static_cast<sal_Int32>((100000.0 * width) / res_x),
187 static_cast<sal_Int32>((100000.0 * height) / res_y));
191 if (colorType == PNG_COLOR_TYPE_RGB)
198 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
205 for (
int pass = 0;
pass < nNumberOfPasses;
pass++)
207 for (png_uint_32 y = 0;
y < height;
y++)
209 Scanline pScanline = pWriteAccess->GetScanline(y);
210 png_read_row(pPng, pScanline,
nullptr);
213 pWriteAccess.
reset();
217 else if (colorType == PNG_COLOR_TYPE_RGB_ALPHA)
219 size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo);
228 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
238 aRows = std::vector<std::vector<png_byte>>(height);
239 for (
auto& rRow : aRows)
240 rRow.resize(aRowSizeBytes, 0);
244 for (
int pass = 0;
pass < nNumberOfPasses;
pass++)
246 for (png_uint_32 y = 0;
y < height;
y++)
248 Scanline pScanline = pWriteAccess->GetScanline(y);
249 png_bytep pRow = aRows[
y].data();
250 png_read_row(pPng, pRow,
nullptr);
252 for (
size_t i = 0;
i < aRowSizeBytes;
i += 4)
257 pScanline[iColor++] = alpha;
264 pScanline[iColor++] = alpha;
269 pWriteAccess.
reset();
281 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
290 aRows = std::vector<std::vector<png_byte>>(height);
291 for (
auto& rRow : aRows)
292 rRow.resize(aRowSizeBytes, 0);
294 for (
int pass = 0;
pass < nNumberOfPasses;
pass++)
296 for (png_uint_32 y = 0;
y < height;
y++)
298 Scanline pScanline = pWriteAccess->GetScanline(y);
299 Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y);
300 png_bytep pRow = aRows[
y].data();
301 png_read_row(pPng, pRow,
nullptr);
304 for (
size_t i = 0;
i < aRowSizeBytes;
i += 4)
306 pScanline[iColor++] = pRow[
i + 0];
307 pScanline[iColor++] = pRow[
i + 1];
308 pScanline[iColor++] = pRow[
i + 2];
309 pScanAlpha[iAlpha++] = 0xFF - pRow[
i + 3];
313 pWriteAccess.
reset();
314 pWriteAccessAlpha.
reset();
316 rBitmapEx =
BitmapEx(aBitmap, aBitmapAlpha);
319 else if (colorType == PNG_COLOR_TYPE_GRAY)
323 aBitmap.
Erase(COL_WHITE);
328 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
332 for (
int pass = 0;
pass < nNumberOfPasses;
pass++)
334 for (png_uint_32 y = 0;
y < height;
y++)
336 Scanline pScanline = pWriteAccess->GetScanline(y);
337 png_read_row(pPng, pScanline,
nullptr);
340 pWriteAccess.
reset();
346 png_read_end(pPng, pInfo);
348 png_destroy_read_struct(&pPng, &pInfo,
nullptr);
359 std::unique_ptr<sal_uInt8[]> getMsGifChunk(
SvStream& rStream, sal_Int32* chunkSize)
377 constexpr sal_uInt32 PNGCHUNK_msOG = 0x6d734f47;
378 constexpr sal_uInt64 MSGifHeaderSize = 11;
379 if (type == PNGCHUNK_msOG && length > MSGifHeaderSize)
382 sal_uInt32 typeForCrc = type;
383 #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
384 typeForCrc = OSL_SWAPDWORD(typeForCrc);
386 sal_uInt32 computedCrc = rtl_crc32(0, &typeForCrc, 4);
387 const sal_uInt64
pos = rStream.
Tell();
388 if (pos + length >= rStream.
TellEnd())
391 char msHeader[MSGifHeaderSize];
392 if (rStream.
ReadBytes(msHeader, MSGifHeaderSize) != MSGifHeaderSize)
394 computedCrc = rtl_crc32(computedCrc, msHeader, MSGifHeaderSize);
395 length -= MSGifHeaderSize;
397 std::unique_ptr<sal_uInt8[]> chunk(
new sal_uInt8[length]);
398 if (rStream.
ReadBytes(chunk.get(), length) != length)
400 computedCrc = rtl_crc32(computedCrc, chunk.get(), length);
402 if (!ignoreCrc && crc != computedCrc)
413 if (type == PNGCHUNK_IEND)
430 bool bSupportsBitmap32 = pBackendCapabilities->mbSupportsBitmap32;
432 return reader(
mrStream, rBitmapEx, bSupportsBitmap32);
443 sal_Int32* chunkSize)
445 sal_uInt64 originalPosition = rStream.
Tell();
448 std::unique_ptr<sal_uInt8[]> chunk = getMsGifChunk(rStream, chunkSize);
450 rStream.
Seek(originalPosition);
sal_uInt8 premultiply(sal_uInt8 c, sal_uInt8 a)
virtual sal_uInt64 TellEnd()
void SetPrefMapMode(const MapMode &rPrefMapMode)
sal_uInt64 Seek(sal_uInt64 nPos)
This template handles BitmapAccess the RAII way.
vcl::ScopedBitmapAccess< BitmapWriteAccess, Bitmap,&Bitmap::AcquireWriteAccess > BitmapScopedWriteAccess
sal_uInt64 SeekRel(sal_Int64 nPos)
sal_uInt64 remainingSize()
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
ImplSVData * ImplGetSVData()
static std::unique_ptr< sal_uInt8[]> getMicrosoftGifChunk(SvStream &rStream, sal_Int32 *chunkSize=nullptr)
virtual std::shared_ptr< vcl::BackendCapabilities > GetBackendCapabilities()
std::size_t ReadBytes(void *pData, std::size_t nSize)
SvStreamEndian GetEndian() const
vcl::ScopedBitmapAccess< BitmapWriteAccess, AlphaMask,&AlphaMask::AcquireAlphaWriteAccess > AlphaScopedWriteAccess
void SetEndian(SvStreamEndian SvStreamEndian)
void SetPrefSize(const Size &rPrefSize)
bool Erase(const Color &rFillColor)
Fill the entire bitmap with the given color.
PngImageReader(SvStream &rStream)
static const BitmapPalette & GetGreyPalette(int nEntries)