1// pngreader.cpp - Public Domain - see unlicense at bottom of file.
2//
3// Notes:
4// This is ancient code from ~1995 ported to C++. It was originally written for a
5// DOS app with very limited memory. It's not as fast as it should be, but it works.
6// The low-level PNG reader class was written assuming the PNG file could not fit
7// entirely into memory, which dictated how it was written/structured.
8// It has been modified to use either zlib or miniz.
9// It supports all PNG color types/bit depths/interlacing, however 16-bit/component
10// images are converted to 8-bit.
11// TRNS chunks are converted to alpha as needed.
12// GAMA chunk is read, but not applied.
13
14#include "../transcoder/basisu.h"
15
16#define MINIZ_HEADER_FILE_ONLY
17#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
18#include "basisu_miniz.h"
19
20#include "pvpngreader.h"
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <math.h>
25#include <string.h>
26#include <vector>
27#include <assert.h>
28
29#define PVPNG_IDAT_CRC_CHECKING (1)
30#define PVPNG_ADLER32_CHECKING (1)
31
32namespace pv_png
33{
34
35const uint32_t MIN_PNG_SIZE = 8 + 13 + 8 + 1 + 4 + 12;
36
37template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; }
38template <typename S> inline S minimum(S a, S b) { return (a < b) ? a : b; }
39
40template <typename T> inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); }
41
42#define MAX_SUPPORTED_RES (32768)
43#define FALSE (0)
44#define TRUE (1)
45#define PNG_MAX_ALLOC_BLOCKS (16)
46
47enum
48{
49 PNG_DECERROR = -3,
50 PNG_ALLDONE = -5,
51 PNG_READPASTEOF = -11,
52 PNG_UNKNOWNTYPE = -16,
53 PNG_FILEREADERROR = -17,
54 PNG_NOTENOUGHMEM = -108,
55 PNG_BAD_CHUNK_CRC32 = -13000,
56 PNG_NO_IHDR = -13001,
57 PNG_BAD_WIDTH = -13002,
58 PNG_BAD_HEIGHT = -13003,
59 PNG_UNS_COMPRESSION = -13004,
60 PNG_UNS_FILTER = -13005,
61 PNG_UNS_ILACE = -13006,
62 PNG_UNS_COLOR_TYPE = -13007,
63 PNG_BAD_BIT_DEPTH = -13008,
64 PNG_BAD_CHUNK_SIZE = -13009,
65 PNG_UNS_CRITICAL_CHUNK = -13010,
66 PNG_BAD_TRNS_CHUNK = -13011,
67 PNG_BAD_PLTE_CHUNK = -13012,
68 PNG_UNS_RESOLUTION = -13013,
69 PNG_INVALID_DATA_STREAM = -13014,
70 PNG_MISSING_PALETTE = -13015,
71 PNG_UNS_PREDICTOR = -13016,
72 PNG_INCOMPLETE_IMAGE = -13017,
73 PNG_TOO_MUCH_DATA = -13018
74};
75
76#define PNG_COLOR_TYPE_PAL_MASK (1)
77#define PNG_COLOR_TYPE_COL_MASK (2)
78#define PNG_COLOR_TYPE_ALP_MASK (4)
79
80#define PNG_INFLATE_SRC_BUF_SIZE (4096)
81
82struct ihdr_struct
83{
84 uint32_t m_width;
85 uint32_t m_height;
86 uint8_t m_bit_depth;
87 uint8_t m_color_type;
88 uint8_t m_comp_type;
89 uint8_t m_filter_type;
90 uint8_t m_ilace_type;
91};
92
93class png_file
94{
95public:
96 png_file() { }
97 virtual ~png_file() { }
98
99 virtual bool resize(uint64_t new_size) = 0;
100 virtual uint64_t get_size() = 0;
101 virtual uint64_t tell() = 0;
102 virtual bool seek(uint64_t ofs) = 0;
103 virtual size_t write(const void* pBuf, size_t len) = 0;
104 virtual size_t read(void* pBuf, size_t len) = 0;
105};
106
107class png_memory_file : public png_file
108{
109public:
110 std::vector<uint8_t> m_buf;
111 uint64_t m_ofs;
112
113 png_memory_file() :
114 png_file(),
115 m_ofs(0)
116 {
117 }
118
119 virtual ~png_memory_file()
120 {
121 }
122
123 std::vector<uint8_t>& get_buf() { return m_buf; }
124 const std::vector<uint8_t>& get_buf() const { return m_buf; }
125
126 void init()
127 {
128 m_ofs = 0;
129 m_buf.resize(0);
130 }
131
132 virtual bool resize(uint64_t new_size)
133 {
134 if ((sizeof(size_t) == sizeof(uint32_t)) && (new_size >= 0x7FFFFFFF))
135 return false;
136
137 m_buf.resize((size_t)new_size);
138 m_ofs = m_buf.size();
139
140 return true;
141 }
142
143 virtual uint64_t get_size()
144 {
145 return m_buf.size();
146 }
147
148 virtual uint64_t tell()
149 {
150 return m_ofs;
151 }
152
153 virtual bool seek(uint64_t ofs)
154 {
155 m_ofs = ofs;
156 return true;
157 }
158
159 virtual size_t write(const void* pBuf, size_t len)
160 {
161 uint64_t new_size = m_ofs + len;
162 if (new_size > m_buf.size())
163 {
164 if ((sizeof(size_t) == sizeof(uint32_t)) && (new_size > 0x7FFFFFFFUL))
165 return 0;
166 m_buf.resize(new_size);
167 }
168
169 memcpy(&m_buf[(size_t)m_ofs], pBuf, len);
170 m_ofs += len;
171
172 return len;
173 }
174
175 virtual size_t read(void* pBuf, size_t len)
176 {
177 if (m_ofs >= m_buf.size())
178 return 0;
179
180 uint64_t max_bytes = minimum<uint64_t>(len, m_buf.size() - m_ofs);
181 memcpy(pBuf, &m_buf[(size_t)m_ofs], max_bytes);
182
183 m_ofs += max_bytes;
184
185 return max_bytes;
186 }
187};
188
189class png_readonly_memory_file : public png_file
190{
191public:
192 const uint8_t* m_pBuf;
193 size_t m_buf_size;
194 uint64_t m_ofs;
195
196 png_readonly_memory_file() :
197 png_file(),
198 m_pBuf(nullptr),
199 m_buf_size(0),
200 m_ofs(0)
201 {
202 }
203
204 virtual ~png_readonly_memory_file()
205 {
206 }
207
208 void init(const void *pBuf, size_t buf_size)
209 {
210 m_pBuf = static_cast<const uint8_t*>(pBuf);
211 m_buf_size = buf_size;
212 m_ofs = 0;
213 }
214
215 virtual bool resize(uint64_t new_size)
216 {
217 (void)new_size;
218 assert(0);
219 return false;
220 }
221
222 virtual uint64_t get_size()
223 {
224 return m_buf_size;
225 }
226
227 virtual uint64_t tell()
228 {
229 return m_ofs;
230 }
231
232 virtual bool seek(uint64_t ofs)
233 {
234 m_ofs = ofs;
235 return true;
236 }
237
238 virtual size_t write(const void* pBuf, size_t len)
239 {
240 (void)pBuf;
241 (void)len;
242 assert(0);
243 return 0;
244 }
245
246 virtual size_t read(void* pBuf, size_t len)
247 {
248 if (m_ofs >= m_buf_size)
249 return 0;
250
251 uint64_t max_bytes = minimum<uint64_t>(len, m_buf_size - m_ofs);
252 memcpy(pBuf, &m_pBuf[(size_t)m_ofs], max_bytes);
253
254 m_ofs += max_bytes;
255
256 return max_bytes;
257 }
258};
259
260#ifdef _MSC_VER
261#define ftell64 _ftelli64
262#define fseek64 _fseeki64
263#else
264#define ftell64 ftello
265#define fseek64 fseeko
266#endif
267
268class png_cfile : public png_file
269{
270public:
271 FILE* m_pFile;
272
273 png_cfile() :
274 png_file(),
275 m_pFile(nullptr)
276 {
277 }
278
279 virtual ~png_cfile()
280 {
281 close();
282 }
283
284 bool init(const char *pFilename, const char *pMode)
285 {
286 close();
287
288 m_pFile = nullptr;
289
290#ifdef _MSC_VER
291 fopen_s(&m_pFile, pFilename, pMode);
292#else
293 m_pFile = fopen(pFilename, pMode);
294#endif
295
296 return m_pFile != nullptr;
297 }
298
299 bool close()
300 {
301 bool status = true;
302 if (m_pFile)
303 {
304 if (fclose(m_pFile) == EOF)
305 status = false;
306 m_pFile = nullptr;
307 }
308 return status;
309 }
310
311 virtual bool resize(uint64_t new_size)
312 {
313 if (new_size)
314 {
315 if (!seek(new_size - 1))
316 return false;
317
318 int v = 0;
319 if (write(&v, 1) != 1)
320 return false;
321 }
322 else
323 {
324 if (!seek(0))
325 return false;
326 }
327
328 return true;
329 }
330
331 virtual uint64_t get_size()
332 {
333 int64_t cur_ofs = ftell64(m_pFile);
334 if (cur_ofs < 0)
335 return 0;
336
337 if (fseek64(m_pFile, 0, SEEK_END) != 0)
338 return 0;
339
340 const int64_t cur_size = ftell64(m_pFile);
341 if (cur_size < 0)
342 return 0;
343
344 if (fseek64(m_pFile, cur_ofs, SEEK_SET) != 0)
345 return 0;
346
347 return cur_size;
348 }
349
350 virtual uint64_t tell()
351 {
352 int64_t cur_ofs = ftell64(m_pFile);
353 if (cur_ofs < 0)
354 return 0;
355
356 return cur_ofs;
357 }
358
359 virtual bool seek(uint64_t ofs)
360 {
361 return fseek64(m_pFile, ofs, SEEK_SET) == 0;
362 }
363
364 virtual size_t write(const void* pBuf, size_t len)
365 {
366 return (size_t)fwrite(pBuf, 1, len, m_pFile);
367 }
368
369 virtual size_t read(void* pBuf, size_t len)
370 {
371 return (size_t)fread(pBuf, 1, len, m_pFile);
372 }
373};
374
375// This low-level helper class handles the actual decoding of PNG files.
376class png_decoder
377{
378public:
379 png_decoder();
380 ~png_decoder();
381
382 // Scans the PNG file, but doesn't decode the IDAT data.
383 // Returns 0 on success, or an error code.
384 // If the returned status is non-zero, or m_img_supported_flag==FALSE the image either the image is corrupted/not PNG or is unsupported in some way.
385 int png_scan(png_file *pFile);
386
387 // Decodes a single scanline of PNG image data.
388 // Returns a pointer to the scanline's pixel data and its size in bytes.
389 // This data is only minimally processed from the internal PNG pixel data.
390 // The caller must use the ihdr, trns_flag and values, and the palette to actually decode the pixel data.
391 //
392 // Possible returned pixel formats is somewhat complex due to the history of this code:
393 // 8-bit RGBA, always 4 bytes/pixel - 24bpp PNG's are converted to 32bpp and TRNS processing is done automatically (8/16bpp RGB or RGBA PNG files)
394 // 1/2/4/8-bit grayscale, 1 byte per pixel - must convert to [0,255] using the palette or some other means, must optionally use the TRNS chunk for alpha (1/2/4/8 Grayscale PNG files - not 16bpp though!)
395 // 1/2/4/8-bit palettized, 1 byte per pixel - must convert to RGB using the 24bpp palette and optionally the TRNS chunk for alpha (1/2/4/8bpp palettized PNG files)
396 // 8-bit grayscale with alpha, 2 bytes per pixel - TRNS processing will be done for you on 16bpp images (there's a special case here for 16bpp Grey files) (8/16bpp Gray-Alpha *or 16bpp Grayscale* PNG files)
397 //
398 // Returns 0 on success, a non-zero error code, or PNG_ALLDONE.
399 int png_decode(void** ppImg_ptr, uint32_t* pImg_len);
400
401 // Starts decoding. Returns 0 on success, otherwise an error code.
402 int png_decode_start();
403
404 // Deinitializes the decoder, freeing all allocations.
405 void png_decode_end();
406
407 png_file* m_pFile;
408
409 // Image's 24bpp palette - 3 bytes per entry
410 uint8_t m_plte_flag;
411 uint8_t m_img_pal[768];
412
413 int m_img_supported_flag;
414
415 ihdr_struct m_ihdr;
416
417 uint8_t m_chunk_flag;
418 uint32_t m_chunk_size;
419 uint32_t m_chunk_left;
420 uint32_t m_chunk_crc32;
421 uint8_t m_chunk_name[4];
422
423 uint8_t m_end_of_idat_chunks;
424
425 void* m_pMalloc_blocks[PNG_MAX_ALLOC_BLOCKS];
426
427 uint32_t m_dec_bytes_per_pixel; // bytes per pixel decoded from the PNG file (minimum 1 for 1/2/4 bpp), factors in the PNG 8/16 bit/component bit depth, may be up to 8 bytes (2*4)
428 uint32_t m_dst_bytes_per_pixel; // bytes per pixel returned to the caller (1-4), always has alpha if the PNG has alpha, 16-bit components always converted to 8-bits/component
429
430 uint32_t m_dec_bytes_per_line; // bytes per line decoded from the PNG file (before 1/2/4 expansion), +1 for the filter byte
431 uint32_t m_src_bytes_per_line; // decoded PNG bytes per line, before 1/2/4 bpp expansion, not counting the filter byte, updated during adam7 deinterlacing
432 uint32_t m_dst_bytes_per_line; // bytes per line returned to the caller (1-4 times width)
433
434 int (*m_pProcess_func)(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi);
435
436 uint8_t* m_pPre_line_buf;
437 uint8_t* m_pCur_line_buf;
438 uint8_t* m_pPro_line_buf;
439
440 uint8_t m_bkgd_flag;
441 uint32_t m_bkgd_value[3];
442
443 uint8_t m_gama_flag;
444 uint32_t m_gama_value;
445
446 uint8_t m_trns_flag;
447 uint32_t m_trns_value[256];
448
449 buminiz::mz_stream m_inflator;
450
451 uint8_t inflate_src_buf[PNG_INFLATE_SRC_BUF_SIZE];
452
453 uint32_t m_inflate_src_buf_ofs;
454 uint32_t m_inflate_src_buf_size;
455 uint32_t m_inflate_dst_buf_ofs;
456
457 int m_inflate_eof_flag;
458
459 uint8_t m_gamma_table[256];
460
461 int m_pass_x_size;
462 int m_pass_y_left;
463
464 int m_adam7_pass_num;
465 int m_adam7_pass_y;
466 int m_adam7_pass_size_x[7];
467 int m_adam7_pass_size_y[7];
468
469 std::vector<uint8_t> m_adam7_image_buf;
470
471 int m_adam7_decoded_flag;
472
473 bool m_scanned_flag;
474
475 int m_terminate_status;
476
477#define TEMP_BUF_SIZE (384)
478 uint8_t m_temp_buf[TEMP_BUF_SIZE * 4];
479
480 void clear();
481 void uninitialize();
482 int terminate(int status);
483 void* png_malloc(uint32_t i);
484 void* png_calloc(uint32_t i);
485 int block_read(void* buf, uint32_t len);
486 int64_t block_read_dword();
487 int fetch_next_chunk_data(uint8_t* buf, int bytes);
488 int fetch_next_chunk_byte();
489 int fetch_next_chunk_word();
490 int64_t fetch_next_chunk_dword();
491 int fetch_next_chunk_init();
492 int unchunk_data(uint8_t* buf, uint32_t bytes, uint32_t* ptr_bytes_read);
493 inline void adam7_write_pixel_8(int x, int y, int c);
494 inline void adam7_write_pixel_16(int x, int y, int r, int g);
495 inline void adam7_write_pixel_24(int x, int y, int r, int g, int b);
496 inline void adam7_write_pixel_32(int x, int y, int r, int g, int b, int a);
497 void unpredict_sub(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);
498 void unpredict_up(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);
499 void unpredict_average(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);
500 inline uint8_t paeth_predictor(int a, int b, int c);
501 void unpredict_paeth(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);
502 int adam7_pass_size(int size, int start, int step);
503 int decompress_line(uint32_t* bytes_decoded);
504 int find_iend_chunk();
505 void calc_gamma_table();
506 void create_grey_palette();
507 int read_signature();
508 int read_ihdr_chunk();
509 int read_bkgd_chunk();
510 int read_gama_chunk();
511 int read_trns_chunk();
512 int read_plte_chunk();
513 int find_idat_chunk();
514};
515
516void png_decoder::uninitialize()
517{
518 m_pFile = nullptr;
519
520 for (int i = 0; i < PNG_MAX_ALLOC_BLOCKS; i++)
521 {
522 free(m_pMalloc_blocks[i]);
523 m_pMalloc_blocks[i] = nullptr;
524 }
525
526 mz_inflateEnd(&m_inflator);
527}
528
529int png_decoder::terminate(int status)
530{
531 if (m_terminate_status == 0)
532 m_terminate_status = status;
533
534 uninitialize();
535 return status;
536}
537
538void* png_decoder::png_malloc(uint32_t len)
539{
540 if (!len)
541 len++;
542
543 void* p = malloc(len);
544
545 if (!p)
546 return nullptr;
547
548 int j;
549 for (j = 0; j < PNG_MAX_ALLOC_BLOCKS; j++)
550 if (!m_pMalloc_blocks[j])
551 break;
552
553 if (j == PNG_MAX_ALLOC_BLOCKS)
554 return nullptr;
555
556 m_pMalloc_blocks[j] = p;
557
558 return p;
559}
560
561void* png_decoder::png_calloc(uint32_t len)
562{
563 void* p = png_malloc(len);
564 if (!p)
565 return nullptr;
566
567 if (p)
568 memset(p, 0, len);
569
570 return p;
571}
572
573int png_decoder::block_read(void* buf, uint32_t len)
574{
575 size_t bytes_read = m_pFile->read(buf, len);
576 if (bytes_read != len)
577 return terminate(PNG_READPASTEOF);
578 return 0;
579}
580
581int64_t png_decoder::block_read_dword()
582{
583 uint8_t buf[4];
584
585 int status = block_read(buf, 4);
586 if (status != 0)
587 return status;
588
589 uint32_t v = buf[3] + ((uint32_t)buf[2] << 8) + ((uint32_t)buf[1] << 16) + ((uint32_t)buf[0] << 24);
590 return (int64_t)v;
591}
592
593int png_decoder::fetch_next_chunk_data(uint8_t* buf, int bytes)
594{
595 if (!m_chunk_flag)
596 return 0;
597
598 bytes = minimum<int>(bytes, m_chunk_left);
599
600 int status = block_read(buf, bytes);
601 if (status != 0)
602 return status;
603
604#if PVPNG_IDAT_CRC_CHECKING
605 bool check_crc32 = true;
606#else
607 const bool is_idat = (m_chunk_name[0] == 'I') && (m_chunk_name[1] == 'D') && (m_chunk_name[2] == 'A') && (m_chunk_name[3] == 'T');
608 bool check_crc32 = !is_idat;
609#endif
610
611 if (check_crc32)
612 m_chunk_crc32 = buminiz::mz_crc32(m_chunk_crc32, buf, bytes);
613
614 if ((m_chunk_left -= bytes) == 0)
615 {
616 int64_t res = block_read_dword();
617 if (res < 0)
618 return (int)res;
619
620 if (check_crc32)
621 {
622 if (m_chunk_crc32 != (uint32_t)res)
623 return terminate(PNG_BAD_CHUNK_CRC32);
624 }
625
626 m_chunk_flag = FALSE;
627 }
628
629 return bytes;
630}
631
632int png_decoder::fetch_next_chunk_byte()
633{
634 uint8_t buf[1];
635
636 int status = fetch_next_chunk_data(buf, 1);
637 if (status < 0)
638 return status;
639
640 if (status != 1)
641 return terminate(PNG_BAD_CHUNK_SIZE);
642
643 return buf[0];
644}
645
646int png_decoder::fetch_next_chunk_word()
647{
648 uint8_t buf[2];
649
650 int status = fetch_next_chunk_data(buf, 2);
651 if (status < 0)
652 return status;
653
654 if (status != 2)
655 return terminate(PNG_BAD_CHUNK_SIZE);
656
657 return buf[1] + ((uint32_t)buf[0] << 8);
658}
659
660int64_t png_decoder::fetch_next_chunk_dword()
661{
662 uint8_t buf[4];
663
664 int status = fetch_next_chunk_data(buf, 4);
665 if (status < 0)
666 return status;
667
668 if (status != 4)
669 terminate(PNG_BAD_CHUNK_SIZE);
670
671 uint32_t v = buf[3] + ((uint32_t)buf[2] << 8) + ((uint32_t)buf[1] << 16) + ((uint32_t)buf[0] << 24);
672 return (int64_t)v;
673}
674
675int png_decoder::fetch_next_chunk_init()
676{
677 while (m_chunk_flag)
678 {
679 int status = fetch_next_chunk_data(m_temp_buf, TEMP_BUF_SIZE * 4);
680 if (status != 0)
681 return status;
682 }
683
684 int64_t n = block_read_dword();
685 if (n < 0)
686 return (int)n;
687
688 m_chunk_size = (uint32_t)n;
689
690 m_chunk_flag = TRUE;
691 m_chunk_left = m_chunk_size + 4;
692 m_chunk_crc32 = 0;
693
694 int status = fetch_next_chunk_data(m_chunk_name, 4);
695 if (status < 0)
696 return status;
697
698 return 0;
699}
700
701int png_decoder::unchunk_data(uint8_t* buf, uint32_t bytes, uint32_t* ptr_bytes_read)
702{
703 uint32_t bytes_read = 0;
704
705 if ((!bytes) || (m_end_of_idat_chunks))
706 {
707 *ptr_bytes_read = 0;
708 return TRUE;
709 }
710
711 while (bytes_read != bytes)
712 {
713 if (!m_chunk_flag)
714 {
715 int res = fetch_next_chunk_init();
716 if (res < 0)
717 return res;
718
719 if ((m_chunk_name[0] != 'I') ||
720 (m_chunk_name[1] != 'D') ||
721 (m_chunk_name[2] != 'A') ||
722 (m_chunk_name[3] != 'T'))
723 {
724 *ptr_bytes_read = bytes_read;
725 m_end_of_idat_chunks = TRUE;
726 return TRUE;
727 }
728 }
729
730 int res = fetch_next_chunk_data(buf + bytes_read, bytes - bytes_read);
731 if (res < 0)
732 return res;
733
734 bytes_read += (uint32_t)res;
735 }
736
737 *ptr_bytes_read = bytes_read;
738
739 return FALSE;
740}
741
742inline void png_decoder::adam7_write_pixel_8(int x, int y, int c)
743{
744 m_adam7_image_buf[x + y * m_dst_bytes_per_line] = (uint8_t)c;
745}
746
747inline void png_decoder::adam7_write_pixel_16(int x, int y, int r, int g)
748{
749 uint32_t ofs = x * 2 + y * m_dst_bytes_per_line;
750 m_adam7_image_buf[ofs + 0] = (uint8_t)r;
751 m_adam7_image_buf[ofs + 1] = (uint8_t)g;
752}
753
754inline void png_decoder::adam7_write_pixel_24(int x, int y, int r, int g, int b)
755{
756 uint32_t ofs = x * 3 + y * m_dst_bytes_per_line;
757 m_adam7_image_buf[ofs + 0] = (uint8_t)r;
758 m_adam7_image_buf[ofs + 1] = (uint8_t)g;
759 m_adam7_image_buf[ofs + 2] = (uint8_t)b;
760}
761
762inline void png_decoder::adam7_write_pixel_32(int x, int y, int r, int g, int b, int a)
763{
764 uint32_t ofs = x * 4 + y * m_dst_bytes_per_line;
765 m_adam7_image_buf[ofs + 0] = (uint8_t)r;
766 m_adam7_image_buf[ofs + 1] = (uint8_t)g;
767 m_adam7_image_buf[ofs + 2] = (uint8_t)b;
768 m_adam7_image_buf[ofs + 3] = (uint8_t)a;
769}
770
771static void PixelDePack2(void* src, void* dst, int numbytes)
772{
773 uint8_t* src8 = (uint8_t*)src;
774 uint8_t* dst8 = (uint8_t*)dst;
775
776 while (numbytes)
777 {
778 uint8_t v = *src8++;
779
780 for (uint32_t i = 0; i < 8; i++)
781 dst8[7 - i] = (v >> i) & 1;
782
783 dst8 += 8;
784 numbytes--;
785 }
786}
787
788static void PixelDePack16(void* src, void* dst, int numbytes)
789{
790 uint8_t* src8 = (uint8_t*)src;
791 uint8_t* dst8 = (uint8_t*)dst;
792
793 while (numbytes)
794 {
795 uint8_t v = *src8++;
796
797 dst8[0] = (uint8_t)v >> 4;
798 dst8[1] = (uint8_t)v & 0xF;
799 dst8 += 2;
800
801 numbytes--;
802 }
803}
804
805static int unpack_grey_1(uint8_t* src, uint8_t* dst, int pixels, png_decoder *pwi)
806{
807 (void)pwi;
808 PixelDePack2(src, dst, pixels >> 3);
809
810 dst += (pixels & 0xFFF8);
811
812 if ((pixels & 7) != 0)
813 {
814 uint8_t c = src[pixels >> 3];
815
816 pixels &= 7;
817
818 while (pixels--)
819 {
820 *dst++ = ((c & 128) >> 7);
821
822 c <<= 1;
823 }
824 }
825
826 return TRUE;
827}
828
829static int unpack_grey_2(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
830{
831 (void)pwi;
832 int i = pixels;
833 uint8_t c;
834
835 while (i >= 4)
836 {
837 c = *src++;
838
839 *dst++ = (c >> 6);
840 *dst++ = (c >> 4) & 3;
841 *dst++ = (c >> 2) & 3;
842 *dst++ = (c) & 3;
843
844 i -= 4;
845 }
846
847 if (i)
848 {
849 c = *src;
850
851 while (i--)
852 {
853 *dst++ = (c >> 6);
854
855 c <<= 2;
856 }
857 }
858
859 return TRUE;
860}
861
862static int unpack_grey_4(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
863{
864 (void)pwi;
865
866 PixelDePack16(src, dst, pixels >> 1);
867
868 if (pixels & 1)
869 dst[pixels & 0xFFFE] = (src[pixels >> 1] >> 4);
870
871 return TRUE;
872}
873
874static int unpack_grey_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
875{
876 (void)src;
877 (void)dst;
878 (void)pixels;
879 (void)pwi;
880 return FALSE;
881}
882
883static int unpack_grey_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
884{
885 (void)pwi;
886 while (pixels--)
887 {
888 *dst++ = *src++;
889
890 src++;
891 }
892
893 return TRUE;
894}
895
896static int unpack_grey_16_2(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
897{
898 if (pwi->m_trns_flag)
899 {
900 while (pixels--)
901 {
902 uint32_t v = (src[0] << 8) + src[1];
903 src += 2;
904
905 *dst++ = (uint8_t)(v >> 8);
906 *dst++ = (v == pwi->m_trns_value[0]) ? 0 : 255;
907 }
908 }
909 else
910 {
911 while (pixels--)
912 {
913 *dst++ = *src++;
914 *dst++ = 0xFF;
915
916 src++;
917 }
918 }
919
920 return TRUE;
921}
922
923static int unpack_true_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
924{
925 if (pwi->m_trns_flag)
926 {
927 const uint32_t tr = pwi->m_trns_value[0];
928 const uint32_t tg = pwi->m_trns_value[1];
929 const uint32_t tb = pwi->m_trns_value[2];
930
931 for (int i = 0; i < pixels; i++)
932 {
933 uint8_t r = src[i * 3 + 0];
934 uint8_t g = src[i * 3 + 1];
935 uint8_t b = src[i * 3 + 2];
936
937 dst[i * 4 + 0] = r;
938 dst[i * 4 + 1] = g;
939 dst[i * 4 + 2] = b;
940 dst[i * 4 + 3] = ((r == tr) && (g == tg) && (b == tb)) ? 0 : 255;
941 }
942 }
943 else
944 {
945 for (int i = 0; i < pixels; i++)
946 {
947 dst[i * 4 + 0] = src[i * 3 + 0];
948 dst[i * 4 + 1] = src[i * 3 + 1];
949 dst[i * 4 + 2] = src[i * 3 + 2];
950 dst[i * 4 + 3] = 255;
951 }
952 }
953
954 return TRUE;
955}
956
957static int unpack_true_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
958{
959 if (pwi->m_trns_flag)
960 {
961 const uint32_t tr = pwi->m_trns_value[0];
962 const uint32_t tg = pwi->m_trns_value[1];
963 const uint32_t tb = pwi->m_trns_value[2];
964
965 for (int i = 0; i < pixels; i++)
966 {
967 uint32_t r = (src[i * 6 + 0] << 8) + src[i * 6 + 1];
968 uint32_t g = (src[i * 6 + 2] << 8) + src[i * 6 + 3];
969 uint32_t b = (src[i * 6 + 4] << 8) + src[i * 6 + 5];
970
971 dst[i * 4 + 0] = (uint8_t)(r >> 8);
972 dst[i * 4 + 1] = (uint8_t)(g >> 8);
973 dst[i * 4 + 2] = (uint8_t)(b >> 8);
974 dst[i * 4 + 3] = ((r == tr) && (g == tg) && (b == tb)) ? 0 : 255;
975 }
976 }
977 else
978 {
979 while (pixels--)
980 {
981 dst[0] = src[0];
982 dst[1] = src[2];
983 dst[2] = src[4];
984 dst[3] = 255;
985
986 dst += 4;
987 src += 6;
988 }
989 }
990
991 return TRUE;
992}
993
994static int unpack_grey_alpha_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
995{
996 (void)pwi;
997 while (pixels--)
998 {
999 dst[0] = src[0];
1000 dst[1] = src[1];
1001 dst += 2;
1002 src += 2;
1003 }
1004
1005 return TRUE;
1006}
1007
1008static int unpack_grey_alpha_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
1009{
1010 (void)pwi;
1011 while (pixels--)
1012 {
1013 dst[0] = src[0];
1014 dst[1] = src[2];
1015 dst += 2;
1016 src += 4;
1017 }
1018
1019 return TRUE;
1020}
1021
1022static int unpack_true_alpha_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
1023{
1024 (void)src;
1025 (void)dst;
1026 (void)pixels;
1027 (void)pwi;
1028 return FALSE;
1029}
1030
1031static int unpack_true_alpha_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)
1032{
1033 (void)pwi;
1034 while (pixels--)
1035 {
1036 dst[0] = src[0];
1037 dst[1] = src[2];
1038 dst[2] = src[4];
1039 dst[3] = src[6];
1040 dst += 4;
1041 src += 8;
1042 }
1043
1044 return TRUE;
1045}
1046
1047void png_decoder::unpredict_sub(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)
1048{
1049 (void)lst;
1050 if (bytes == (uint32_t)bpp)
1051 return;
1052
1053 cur += bpp;
1054 bytes -= bpp;
1055
1056 while (bytes--)
1057 {
1058 *cur += *(cur - bpp);
1059 cur++;
1060 }
1061}
1062
1063void png_decoder::unpredict_up(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)
1064{
1065 (void)bpp;
1066 while (bytes--)
1067 *cur++ += *lst++;
1068}
1069
1070void png_decoder::unpredict_average(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)
1071{
1072 int i;
1073
1074 for (i = 0; i < bpp; i++)
1075 *cur++ += (*lst++ >> 1);
1076
1077 if (bytes == (uint32_t)bpp)
1078 return;
1079
1080 bytes -= bpp;
1081
1082 while (bytes--)
1083 {
1084 *cur += ((*lst++ + *(cur - bpp)) >> 1);
1085 cur++;
1086 }
1087}
1088
1089inline uint8_t png_decoder::paeth_predictor(int a, int b, int c)
1090{
1091 int p, pa, pb, pc;
1092
1093 /* a = left, b = above, c = upper left */
1094
1095 p = a + b - c;
1096
1097 pa = abs(p - a);
1098 pb = abs(p - b);
1099 pc = abs(p - c);
1100
1101 if ((pa <= pb) && (pa <= pc))
1102 return (uint8_t)a;
1103 else if (pb <= pc)
1104 return (uint8_t)b;
1105 else
1106 return (uint8_t)c;
1107}
1108
1109void png_decoder::unpredict_paeth(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)
1110{
1111 int i;
1112
1113 for (i = 0; i < bpp; i++)
1114 *cur++ += paeth_predictor(0, *lst++, 0);
1115
1116 if (bytes == (uint32_t)bpp)
1117 return;
1118
1119 bytes -= bpp;
1120
1121 while (bytes--)
1122 {
1123 int p, a, b, c, pa, pb, pc;
1124
1125 a = *(cur - bpp);
1126 b = *lst;
1127 c = *(lst - bpp);
1128
1129 p = a + b - c;
1130
1131 pa = abs(p - a);
1132 pb = abs(p - b);
1133 pc = abs(p - c);
1134
1135 if ((pa <= pb) && (pa <= pc))
1136 *cur++ += (uint8_t)a;
1137 else if (pb <= pc)
1138 *cur++ += (uint8_t)b;
1139 else
1140 *cur++ += (uint8_t)c;
1141
1142 lst++;
1143 }
1144}
1145
1146int png_decoder::adam7_pass_size(int size, int start, int step)
1147{
1148 if (size > start)
1149 return 1 + ((size - 1) - start) / step;
1150 else
1151 return 0;
1152}
1153
1154// TRUE if no more data, negative on error, FALSE if OK
1155int png_decoder::decompress_line(uint32_t* bytes_decoded)
1156{
1157 int status;
1158 uint32_t temp, src_bytes_left, dst_bytes_left;
1159
1160 m_inflate_dst_buf_ofs = 0;
1161
1162 for (; ; )
1163 {
1164 if (m_inflate_src_buf_ofs == PNG_INFLATE_SRC_BUF_SIZE)
1165 {
1166 int res = unchunk_data(inflate_src_buf, PNG_INFLATE_SRC_BUF_SIZE, &temp);
1167 if (res < 0)
1168 return res;
1169 m_inflate_eof_flag = res;
1170
1171 m_inflate_src_buf_size = temp;
1172
1173 m_inflate_src_buf_ofs = 0;
1174 }
1175
1176 for (; ; )
1177 {
1178 src_bytes_left = m_inflate_src_buf_size - m_inflate_src_buf_ofs;
1179 dst_bytes_left = m_dec_bytes_per_line - m_inflate_dst_buf_ofs;
1180
1181 m_inflator.next_in = inflate_src_buf + m_inflate_src_buf_ofs;
1182 m_inflator.avail_in = src_bytes_left;
1183
1184 m_inflator.next_out = m_pCur_line_buf + m_inflate_dst_buf_ofs;
1185 m_inflator.avail_out = dst_bytes_left;
1186
1187 status = buminiz::mz_inflate2(&m_inflator, buminiz::MZ_NO_FLUSH, PVPNG_ADLER32_CHECKING);
1188
1189 const uint32_t src_bytes_consumed = src_bytes_left - m_inflator.avail_in;
1190 const uint32_t dst_bytes_written = dst_bytes_left - m_inflator.avail_out;
1191
1192 m_inflate_src_buf_ofs += src_bytes_consumed;
1193 m_inflate_dst_buf_ofs += dst_bytes_written;
1194
1195 if (status != buminiz::MZ_OK)
1196 {
1197 if (status != buminiz::MZ_STREAM_END)
1198 return terminate(PNG_INVALID_DATA_STREAM);
1199
1200 if (bytes_decoded)
1201 *bytes_decoded = m_inflate_dst_buf_ofs;
1202
1203 return TRUE;
1204 }
1205
1206 if (m_inflate_dst_buf_ofs == m_dec_bytes_per_line)
1207 {
1208 if (bytes_decoded)
1209 *bytes_decoded = m_inflate_dst_buf_ofs;
1210
1211 return FALSE;
1212 }
1213
1214 if ((m_inflate_src_buf_ofs == m_inflate_src_buf_size) &&
1215 (m_inflate_eof_flag == FALSE))
1216 break;
1217 }
1218 }
1219}
1220
1221int png_decoder::find_iend_chunk()
1222{
1223 uint32_t dummy;
1224
1225 while (!m_end_of_idat_chunks)
1226 {
1227 int res = unchunk_data(m_temp_buf, TEMP_BUF_SIZE * 4, &dummy);
1228 if (res < 0)
1229 return res;
1230 }
1231
1232 for (; ; )
1233 {
1234 if ((m_chunk_name[0] == 'I') &&
1235 (m_chunk_name[1] == 'E') &&
1236 (m_chunk_name[2] == 'N') &&
1237 (m_chunk_name[3] == 'D'))
1238 break;
1239
1240 int res = fetch_next_chunk_init();
1241 if (res < 0)
1242 return res;
1243 }
1244
1245 return 0;
1246}
1247
1248int png_decoder::png_decode(void** ppImg_ptr, uint32_t* pImg_len)
1249{
1250 int status;
1251 uint8_t* decoded_line;
1252 uint32_t bytes_decoded;
1253
1254 if (m_adam7_decoded_flag)
1255 {
1256 if (m_pass_y_left == 0)
1257 return PNG_ALLDONE;
1258
1259 *ppImg_ptr = &m_adam7_image_buf[(m_ihdr.m_height - m_pass_y_left) * m_dst_bytes_per_line];
1260 *pImg_len = m_dst_bytes_per_line;
1261
1262 m_pass_y_left--;
1263
1264 return 0;
1265 }
1266
1267 if (m_pass_y_left == 0)
1268 {
1269 if (m_ihdr.m_ilace_type == 0)
1270 {
1271 status = find_iend_chunk();
1272 if (status < 0)
1273 return status;
1274
1275 return PNG_ALLDONE;
1276 }
1277
1278 for (; ; )
1279 {
1280 if (++m_adam7_pass_num == 7)
1281 {
1282 status = find_iend_chunk();
1283 if (status < 0)
1284 return status;
1285
1286 return PNG_ALLDONE;
1287 }
1288
1289 if (((m_pass_y_left = m_adam7_pass_size_y[m_adam7_pass_num]) != 0) &&
1290 ((m_pass_x_size = m_adam7_pass_size_x[m_adam7_pass_num]) != 0))
1291 break;
1292 }
1293
1294 switch (m_adam7_pass_num)
1295 {
1296 case 0:
1297 case 1:
1298 case 3:
1299 case 5:
1300 m_adam7_pass_y = 0;
1301 break;
1302 case 2:
1303 m_adam7_pass_y = 4;
1304 break;
1305 case 4:
1306 m_adam7_pass_y = 2;
1307 break;
1308 case 6:
1309 m_adam7_pass_y = 1;
1310 break;
1311 }
1312
1313 switch (m_ihdr.m_color_type)
1314 {
1315 case PNG_COLOR_TYPE_GREYSCALE:
1316 case PNG_COLOR_TYPE_PALETTIZED:
1317 {
1318 m_src_bytes_per_line = (((uint32_t)m_pass_x_size * m_ihdr.m_bit_depth) + 7) / 8;
1319 break;
1320 }
1321 case PNG_COLOR_TYPE_TRUECOLOR:
1322 {
1323 m_src_bytes_per_line = ((uint32_t)m_pass_x_size * m_dec_bytes_per_pixel);
1324 break;
1325 }
1326 case PNG_COLOR_TYPE_GREYSCALE_ALPHA:
1327 {
1328 m_src_bytes_per_line = ((uint32_t)m_pass_x_size * m_dec_bytes_per_pixel);
1329 break;
1330 }
1331 case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:
1332 {
1333 m_src_bytes_per_line = ((uint32_t)m_pass_x_size * m_dec_bytes_per_pixel);
1334 break;
1335 }
1336 }
1337
1338 m_dec_bytes_per_line = m_src_bytes_per_line + 1;
1339
1340 memset(m_pPre_line_buf, 0, m_src_bytes_per_line);
1341 }
1342
1343 int res = decompress_line(&bytes_decoded);
1344 if (res < 0)
1345 return terminate(res);
1346
1347 if (res)
1348 {
1349 if (m_ihdr.m_ilace_type == 0)
1350 {
1351 if (m_pass_y_left != 1)
1352 return terminate(PNG_INCOMPLETE_IMAGE);
1353 }
1354 else
1355 {
1356 if ((m_pass_y_left != 1) && (m_adam7_pass_num != 6))
1357 return terminate(PNG_INCOMPLETE_IMAGE);
1358 }
1359 }
1360
1361 if (bytes_decoded != m_dec_bytes_per_line)
1362 return terminate(PNG_INCOMPLETE_IMAGE);
1363
1364 decoded_line = &m_pCur_line_buf[1];
1365
1366 switch (m_pCur_line_buf[0])
1367 {
1368 case 0:
1369 break;
1370 case 1:
1371 {
1372 unpredict_sub(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);
1373 break;
1374 }
1375 case 2:
1376 {
1377 unpredict_up(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);
1378 break;
1379 }
1380 case 3:
1381 {
1382 unpredict_average(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);
1383 break;
1384 }
1385 case 4:
1386 {
1387 unpredict_paeth(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);
1388 break;
1389 }
1390 default:
1391 return terminate(PNG_UNS_PREDICTOR);
1392 }
1393
1394 memmove(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line);
1395
1396 if (m_pProcess_func)
1397 {
1398 if ((*m_pProcess_func)(m_pCur_line_buf + 1, m_pPro_line_buf, m_pass_x_size, this))
1399 decoded_line = m_pPro_line_buf;
1400 }
1401
1402 if (m_ihdr.m_ilace_type == 0)
1403 {
1404 *ppImg_ptr = decoded_line;
1405 *pImg_len = m_dst_bytes_per_line;
1406
1407 if (--m_pass_y_left == 0)
1408 {
1409 res = decompress_line(&bytes_decoded);
1410 if (res < 0)
1411 return terminate(res);
1412
1413 if (res == FALSE)
1414 return terminate(PNG_TOO_MUCH_DATA);
1415
1416 if (bytes_decoded)
1417 return terminate(PNG_TOO_MUCH_DATA);
1418 }
1419 }
1420 else
1421 {
1422 int i, x_ofs = 0, y_ofs = 0, x_stp = 0;
1423 uint8_t* p = decoded_line;
1424
1425 switch (m_adam7_pass_num)
1426 {
1427 case 0: { x_ofs = 0; x_stp = 8; break; }
1428 case 1: { x_ofs = 4; x_stp = 8; break; }
1429 case 2: { x_ofs = 0; x_stp = 4; break; }
1430 case 3: { x_ofs = 2; x_stp = 4; break; }
1431 case 4: { x_ofs = 0; x_stp = 2; break; }
1432 case 5: { x_ofs = 1; x_stp = 2; break; }
1433 case 6: { x_ofs = 0; x_stp = 1; break; }
1434 }
1435
1436 y_ofs = m_adam7_pass_y;
1437
1438 assert(x_ofs < (int)m_ihdr.m_width);
1439 assert(y_ofs < (int)m_ihdr.m_height);
1440
1441 if (m_dst_bytes_per_pixel == 1)
1442 {
1443 for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp)
1444 adam7_write_pixel_8(x_ofs, y_ofs, *p++);
1445 }
1446 else if (m_dst_bytes_per_pixel == 2)
1447 {
1448 for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp, p += 2)
1449 adam7_write_pixel_16(x_ofs, y_ofs, p[0], p[1]);
1450 }
1451 else if (m_dst_bytes_per_pixel == 3)
1452 {
1453 for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp, p += 3)
1454 adam7_write_pixel_24(x_ofs, y_ofs, p[0], p[1], p[2]);
1455 }
1456 else if (m_dst_bytes_per_pixel == 4)
1457 {
1458 for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp, p += 4)
1459 adam7_write_pixel_32(x_ofs, y_ofs, p[0], p[1], p[2], p[3]);
1460 }
1461 else
1462 {
1463 assert(0);
1464 }
1465
1466 switch (m_adam7_pass_num)
1467 {
1468 case 0:
1469 case 1:
1470 case 2: { m_adam7_pass_y += 8; break; }
1471 case 3:
1472 case 4: { m_adam7_pass_y += 4; break; }
1473 case 5:
1474 case 6: { m_adam7_pass_y += 2; break; }
1475 }
1476
1477 if ((--m_pass_y_left == 0) && (m_adam7_pass_num == 6))
1478 {
1479 res = decompress_line(&bytes_decoded);
1480 if (res < 0)
1481 return terminate(res);
1482
1483 if (res == FALSE)
1484 return terminate(PNG_TOO_MUCH_DATA);
1485
1486 if (bytes_decoded)
1487 return terminate(PNG_TOO_MUCH_DATA);
1488 }
1489 }
1490
1491 return 0;
1492}
1493
1494void png_decoder::png_decode_end()
1495{
1496 uninitialize();
1497}
1498
1499int png_decoder::png_decode_start()
1500{
1501 int status;
1502
1503 if (m_img_supported_flag != TRUE)
1504 return terminate(m_img_supported_flag);
1505
1506 switch (m_ihdr.m_color_type)
1507 {
1508 case PNG_COLOR_TYPE_GREYSCALE:
1509 {
1510 if (m_ihdr.m_bit_depth == 16)
1511 {
1512 // This is a special case. We can't pass back 8-bit samples and let the caller decide on transparency because the PNG is 16-bits.
1513 // So we expand to 8-bit Gray-Alpha and handle transparency during decoding.
1514 // We don't do this with all grayscale cases because that would require more code to deal with 1/2/4bpp expansion.
1515 m_dec_bytes_per_pixel = (m_ihdr.m_bit_depth + 7) / 8;
1516 m_dst_bytes_per_pixel = 2;
1517
1518 m_src_bytes_per_line = (((uint32_t)m_ihdr.m_width * m_ihdr.m_bit_depth) + 7) / 8;
1519 m_dst_bytes_per_line = 2 * m_ihdr.m_width;
1520
1521 m_pProcess_func = unpack_grey_16_2;
1522 }
1523 else
1524 {
1525 m_dec_bytes_per_pixel = (m_ihdr.m_bit_depth + 7) / 8;
1526 m_dst_bytes_per_pixel = 1;
1527
1528 m_src_bytes_per_line = (((uint32_t)m_ihdr.m_width * m_ihdr.m_bit_depth) + 7) / 8;
1529 m_dst_bytes_per_line = m_ihdr.m_width;
1530
1531 if (m_ihdr.m_bit_depth == 1)
1532 m_pProcess_func = unpack_grey_1;
1533 else if (m_ihdr.m_bit_depth == 2)
1534 m_pProcess_func = unpack_grey_2;
1535 else if (m_ihdr.m_bit_depth == 4)
1536 m_pProcess_func = unpack_grey_4;
1537 else
1538 m_pProcess_func = unpack_grey_8;
1539 }
1540
1541 break;
1542 }
1543 case PNG_COLOR_TYPE_PALETTIZED:
1544 {
1545 m_dec_bytes_per_pixel = (m_ihdr.m_bit_depth + 7) / 8;
1546 m_dst_bytes_per_pixel = 1;
1547
1548 m_src_bytes_per_line = (((uint32_t)m_ihdr.m_width * m_ihdr.m_bit_depth) + 7) / 8;
1549 m_dst_bytes_per_line = m_ihdr.m_width;
1550
1551 if (m_ihdr.m_bit_depth == 1)
1552 m_pProcess_func = unpack_grey_1;
1553 else if (m_ihdr.m_bit_depth == 2)
1554 m_pProcess_func = unpack_grey_2;
1555 else if (m_ihdr.m_bit_depth == 4)
1556 m_pProcess_func = unpack_grey_4;
1557 else if (m_ihdr.m_bit_depth == 8)
1558 m_pProcess_func = unpack_grey_8;
1559 else if (m_ihdr.m_bit_depth == 16)
1560 m_pProcess_func = unpack_grey_16;
1561
1562 break;
1563 }
1564 case PNG_COLOR_TYPE_TRUECOLOR:
1565 {
1566 // We always pass back alpha with transparency handling.
1567 m_dec_bytes_per_pixel = 3 * (m_ihdr.m_bit_depth / 8);
1568 m_dst_bytes_per_pixel = 4;
1569
1570 m_src_bytes_per_line = ((uint32_t)m_ihdr.m_width * m_dec_bytes_per_pixel);
1571 m_dst_bytes_per_line = 4 * m_ihdr.m_width;
1572
1573 if (m_ihdr.m_bit_depth == 8)
1574 m_pProcess_func = unpack_true_8;
1575 else if (m_ihdr.m_bit_depth == 16)
1576 m_pProcess_func = unpack_true_16;
1577
1578 break;
1579 }
1580 case PNG_COLOR_TYPE_GREYSCALE_ALPHA:
1581 {
1582 m_dec_bytes_per_pixel = 2 * (m_ihdr.m_bit_depth / 8);
1583 m_dst_bytes_per_pixel = 2;
1584
1585 m_src_bytes_per_line = ((uint32_t)m_ihdr.m_width * m_dec_bytes_per_pixel);
1586 m_dst_bytes_per_line = m_ihdr.m_width * 2;
1587
1588 if (m_ihdr.m_bit_depth == 8)
1589 m_pProcess_func = unpack_grey_alpha_8;
1590 else if (m_ihdr.m_bit_depth == 16)
1591 m_pProcess_func = unpack_grey_alpha_16;
1592
1593 break;
1594 }
1595 case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:
1596 {
1597 m_dec_bytes_per_pixel = 4 * (m_ihdr.m_bit_depth / 8);
1598 m_dst_bytes_per_pixel = 4;
1599
1600 m_src_bytes_per_line = ((uint32_t)m_ihdr.m_width * m_dec_bytes_per_pixel);
1601 m_dst_bytes_per_line = 4 * m_ihdr.m_width;
1602
1603 if (m_ihdr.m_bit_depth == 8)
1604 m_pProcess_func = unpack_true_alpha_8;
1605 else
1606 m_pProcess_func = unpack_true_alpha_16;
1607
1608 break;
1609 }
1610 }
1611
1612 m_dec_bytes_per_line = m_src_bytes_per_line + 1;
1613
1614 m_pPre_line_buf = (uint8_t*)png_calloc(m_src_bytes_per_line);
1615 m_pCur_line_buf = (uint8_t*)png_calloc(m_dec_bytes_per_line);
1616 m_pPro_line_buf = (uint8_t*)png_calloc(m_dst_bytes_per_line);
1617
1618 if (!m_pPre_line_buf || !m_pCur_line_buf || !m_pPro_line_buf)
1619 return terminate(PNG_NOTENOUGHMEM);
1620
1621 m_inflate_src_buf_ofs = PNG_INFLATE_SRC_BUF_SIZE;
1622
1623 int res = mz_inflateInit(&m_inflator);
1624 if (res != 0)
1625 return terminate(PNG_DECERROR);
1626
1627 if (m_ihdr.m_ilace_type == 1)
1628 {
1629 int i;
1630 uint32_t total_lines, lines_processed;
1631
1632 m_adam7_pass_size_x[0] = adam7_pass_size(m_ihdr.m_width, 0, 8);
1633 m_adam7_pass_size_x[1] = adam7_pass_size(m_ihdr.m_width, 4, 8);
1634 m_adam7_pass_size_x[2] = adam7_pass_size(m_ihdr.m_width, 0, 4);
1635 m_adam7_pass_size_x[3] = adam7_pass_size(m_ihdr.m_width, 2, 4);
1636 m_adam7_pass_size_x[4] = adam7_pass_size(m_ihdr.m_width, 0, 2);
1637 m_adam7_pass_size_x[5] = adam7_pass_size(m_ihdr.m_width, 1, 2);
1638 m_adam7_pass_size_x[6] = adam7_pass_size(m_ihdr.m_width, 0, 1);
1639
1640 m_adam7_pass_size_y[0] = adam7_pass_size(m_ihdr.m_height, 0, 8);
1641 m_adam7_pass_size_y[1] = adam7_pass_size(m_ihdr.m_height, 0, 8);
1642 m_adam7_pass_size_y[2] = adam7_pass_size(m_ihdr.m_height, 4, 8);
1643 m_adam7_pass_size_y[3] = adam7_pass_size(m_ihdr.m_height, 0, 4);
1644 m_adam7_pass_size_y[4] = adam7_pass_size(m_ihdr.m_height, 2, 4);
1645 m_adam7_pass_size_y[5] = adam7_pass_size(m_ihdr.m_height, 0, 2);
1646 m_adam7_pass_size_y[6] = adam7_pass_size(m_ihdr.m_height, 1, 2);
1647
1648 m_adam7_image_buf.resize(m_dst_bytes_per_line * m_ihdr.m_height);
1649
1650 m_adam7_pass_num = -1;
1651
1652 m_pass_y_left = 0;
1653
1654 total_lines = lines_processed = 0;
1655
1656 for (i = 0; i < 7; i++)
1657 total_lines += m_adam7_pass_size_y[i];
1658
1659 for (; ; )
1660 {
1661 void* dummy_ptr = nullptr;
1662 uint32_t dummy_len = 0;
1663
1664 status = png_decode(&dummy_ptr, &dummy_len);
1665
1666 if (status)
1667 {
1668 if (status == PNG_ALLDONE)
1669 break;
1670 else
1671 {
1672 uninitialize();
1673
1674 return status;
1675 }
1676 }
1677
1678 lines_processed++;
1679 }
1680
1681 m_adam7_decoded_flag = TRUE;
1682 m_pass_y_left = m_ihdr.m_height;
1683 }
1684 else
1685 {
1686 m_pass_x_size = m_ihdr.m_width;
1687 m_pass_y_left = m_ihdr.m_height;
1688 }
1689
1690 return 0;
1691}
1692
1693void png_decoder::calc_gamma_table()
1694{
1695 if (m_gama_value == 45000)
1696 {
1697 for (int i = 0; i < 256; i++)
1698 m_gamma_table[i] = (uint8_t)i;
1699 return;
1700 }
1701
1702 float gamma = (float)(m_gama_value) / 100000.0f;
1703
1704 gamma = 1.0f / (gamma * 2.2f);
1705
1706 for (int i = 0; i < 256; i++)
1707 {
1708 float temp = powf((float)(i) / 255.0f, gamma) * 255.0f;
1709
1710 int j = (int)(temp + .5f);
1711
1712 if (j < 0)
1713 j = 0;
1714 else if (j > 255)
1715 j = 255;
1716
1717 m_gamma_table[i] = (uint8_t)j;
1718 }
1719}
1720
1721void png_decoder::create_grey_palette()
1722{
1723 int i, j;
1724 uint8_t* p = m_img_pal;
1725
1726 const int img_colors = minimum(256, 1 << m_ihdr.m_bit_depth);
1727 for (i = 0; i < img_colors; i++)
1728 {
1729 j = ((uint32_t)255 * (uint32_t)i) / (img_colors - 1);
1730
1731 *p++ = (uint8_t)j;
1732 *p++ = (uint8_t)j;
1733 *p++ = (uint8_t)j;
1734 }
1735}
1736
1737int png_decoder::read_signature()
1738{
1739 if (m_pFile->read(m_temp_buf, 8) != 8)
1740 return terminate(PNG_UNKNOWNTYPE);
1741
1742 if ((m_temp_buf[0] != 137) ||
1743 (m_temp_buf[1] != 80) ||
1744 (m_temp_buf[2] != 78) ||
1745 (m_temp_buf[3] != 71) ||
1746 (m_temp_buf[4] != 13) ||
1747 (m_temp_buf[5] != 10) ||
1748 (m_temp_buf[6] != 26) ||
1749 (m_temp_buf[7] != 10))
1750 {
1751 return terminate(PNG_UNKNOWNTYPE);
1752 }
1753
1754 return 0;
1755}
1756
1757int png_decoder::read_ihdr_chunk()
1758{
1759 int res = fetch_next_chunk_init();
1760 if (res < 0)
1761 return res;
1762
1763 if ((m_chunk_name[0] != 'I') || (m_chunk_name[1] != 'H') || (m_chunk_name[2] != 'D') || (m_chunk_name[3] != 'R') || (m_chunk_size != 13))
1764 return terminate(PNG_NO_IHDR);
1765
1766 int64_t v64 = fetch_next_chunk_dword();
1767 if (v64 < 0)
1768 return (int)v64;
1769 m_ihdr.m_width = (uint32_t)v64;
1770
1771 v64 = fetch_next_chunk_dword();
1772 if (v64 < 0)
1773 return (int)v64;
1774 m_ihdr.m_height = (uint32_t)v64;
1775
1776 if ((m_ihdr.m_width == 0) || (m_ihdr.m_width > MAX_SUPPORTED_RES))
1777 return terminate(PNG_BAD_WIDTH);
1778
1779 if ((m_ihdr.m_height == 0) || (m_ihdr.m_height > MAX_SUPPORTED_RES))
1780 return terminate(PNG_BAD_HEIGHT);
1781
1782 int v = fetch_next_chunk_byte();
1783 if (v < 0)
1784 return v;
1785 m_ihdr.m_bit_depth = (uint8_t)v;
1786
1787 v = fetch_next_chunk_byte();
1788 if (v < 0)
1789 return v;
1790 m_ihdr.m_color_type = (uint8_t)v;
1791
1792 v = fetch_next_chunk_byte();
1793 if (v < 0)
1794 return v;
1795 m_ihdr.m_comp_type = (uint8_t)v;
1796
1797 v = fetch_next_chunk_byte();
1798 if (v < 0)
1799 return v;
1800 m_ihdr.m_filter_type = (uint8_t)v;
1801
1802 v = fetch_next_chunk_byte();
1803 if (v < 0)
1804 return v;
1805 m_ihdr.m_ilace_type = (uint8_t)v;
1806
1807 if (m_ihdr.m_comp_type != 0)
1808 m_img_supported_flag = PNG_UNS_COMPRESSION;
1809
1810 if (m_ihdr.m_filter_type != 0)
1811 m_img_supported_flag = PNG_UNS_FILTER;
1812
1813 if (m_ihdr.m_ilace_type > 1)
1814 m_img_supported_flag = PNG_UNS_ILACE;
1815
1816 switch (m_ihdr.m_color_type)
1817 {
1818 case PNG_COLOR_TYPE_GREYSCALE:
1819 {
1820 switch (m_ihdr.m_bit_depth)
1821 {
1822 case 1:
1823 case 2:
1824 case 4:
1825 case 8:
1826 case 16:
1827 {
1828 break;
1829 }
1830 default:
1831 return terminate(PNG_BAD_BIT_DEPTH);
1832 }
1833
1834 break;
1835 }
1836 case PNG_COLOR_TYPE_PALETTIZED:
1837 {
1838 switch (m_ihdr.m_bit_depth)
1839 {
1840 case 1:
1841 case 2:
1842 case 4:
1843 case 8:
1844 {
1845 break;
1846 }
1847 default:
1848 return terminate(PNG_BAD_BIT_DEPTH);
1849 }
1850
1851 break;
1852 }
1853 case PNG_COLOR_TYPE_TRUECOLOR:
1854 case PNG_COLOR_TYPE_GREYSCALE_ALPHA:
1855 case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:
1856 {
1857 switch (m_ihdr.m_bit_depth)
1858 {
1859 case 8:
1860 case 16:
1861 {
1862 break;
1863 }
1864 default:
1865 return terminate(PNG_BAD_BIT_DEPTH);
1866 }
1867
1868 break;
1869 }
1870 default:
1871 return terminate(PNG_UNS_COLOR_TYPE);
1872 }
1873
1874 return 0;
1875}
1876
1877int png_decoder::read_bkgd_chunk()
1878{
1879 m_bkgd_flag = TRUE;
1880
1881 if (m_ihdr.m_color_type == PNG_COLOR_TYPE_PALETTIZED)
1882 {
1883 int v = fetch_next_chunk_byte();
1884 if (v < 0)
1885 return v;
1886 m_bkgd_value[0] = v;
1887 }
1888 else if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE) || (m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE_ALPHA))
1889 {
1890 int v = fetch_next_chunk_word();
1891 if (v < 0)
1892 return v;
1893 m_bkgd_value[0] = v;
1894 }
1895 else if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_TRUECOLOR) || (m_ihdr.m_color_type == PNG_COLOR_TYPE_TRUECOLOR_ALPHA))
1896 {
1897 int v = fetch_next_chunk_word();
1898 if (v < 0)
1899 return v;
1900 m_bkgd_value[0] = v;
1901
1902 v = fetch_next_chunk_word();
1903 if (v < 0)
1904 return v;
1905 m_bkgd_value[1] = v;
1906
1907 v = fetch_next_chunk_word();
1908 if (v < 0)
1909 return v;
1910 m_bkgd_value[2] = v;
1911 }
1912
1913 return 0;
1914}
1915
1916int png_decoder::read_gama_chunk()
1917{
1918 m_gama_flag = TRUE;
1919
1920 int64_t v = fetch_next_chunk_dword();
1921 if (v < 0)
1922 return (int)v;
1923
1924 m_gama_value = (uint32_t)v;
1925
1926 return 0;
1927}
1928
1929int png_decoder::read_trns_chunk()
1930{
1931 int i;
1932
1933 m_trns_flag = TRUE;
1934
1935 if (m_ihdr.m_color_type == PNG_COLOR_TYPE_PALETTIZED)
1936 {
1937 for (i = 0; i < 256; i++)
1938 m_trns_value[i] = 255;
1939
1940 const uint32_t img_colors = 1 << m_ihdr.m_bit_depth;
1941 if (m_chunk_size > (uint32_t)img_colors)
1942 return terminate(PNG_BAD_TRNS_CHUNK);
1943
1944 for (i = 0; i < (int)m_chunk_size; i++)
1945 {
1946 int v = fetch_next_chunk_byte();
1947 if (v < 0)
1948 return v;
1949 m_trns_value[i] = v;
1950 }
1951 }
1952 else if (m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE)
1953 {
1954 int v = fetch_next_chunk_word();
1955 if (v < 0)
1956 return v;
1957 m_trns_value[0] = v;
1958 }
1959 else if (m_ihdr.m_color_type == PNG_COLOR_TYPE_TRUECOLOR)
1960 {
1961 int v = fetch_next_chunk_word();
1962 if (v < 0)
1963 return v;
1964 m_trns_value[0] = v;
1965
1966 v = fetch_next_chunk_word();
1967 if (v < 0)
1968 return v;
1969 m_trns_value[1] = v;
1970
1971 v = fetch_next_chunk_word();
1972 if (v < 0)
1973 return v;
1974 m_trns_value[2] = v;
1975 }
1976 else
1977 {
1978 return terminate(PNG_BAD_TRNS_CHUNK);
1979 }
1980 return 0;
1981}
1982
1983int png_decoder::read_plte_chunk()
1984{
1985 int i, j;
1986 uint8_t* p;
1987
1988 if (m_plte_flag)
1989 return terminate(PNG_BAD_PLTE_CHUNK);
1990
1991 m_plte_flag = TRUE;
1992
1993 memset(m_img_pal, 0, 768);
1994
1995 if (m_chunk_size % 3)
1996 return terminate(PNG_BAD_PLTE_CHUNK);
1997
1998 j = m_chunk_size / 3;
1999
2000 const int img_colors = minimum(256, 1 << m_ihdr.m_bit_depth);
2001 if (j > img_colors)
2002 return terminate(PNG_BAD_PLTE_CHUNK);
2003
2004 if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE) ||
2005 (m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE_ALPHA))
2006 return terminate(PNG_BAD_PLTE_CHUNK);
2007
2008 p = m_img_pal;
2009
2010 for (i = 0; i < j; i++)
2011 {
2012 int v = fetch_next_chunk_byte();
2013 if (v < 0)
2014 return v;
2015 *p++ = (uint8_t)v;
2016
2017 v = fetch_next_chunk_byte();
2018 if (v < 0)
2019 return v;
2020 *p++ = (uint8_t)v;
2021
2022 v = fetch_next_chunk_byte();
2023 if (v < 0)
2024 return v;
2025 *p++ = (uint8_t)v;
2026 }
2027
2028 return 0;
2029}
2030
2031int png_decoder::find_idat_chunk()
2032{
2033 for (; ; )
2034 {
2035 int res = fetch_next_chunk_init();
2036 if (res < 0)
2037 return res;
2038
2039 if (m_chunk_name[0] & 32) /* ancillary? */
2040 {
2041 if ((m_chunk_name[0] == 'b') && (m_chunk_name[1] == 'K') && (m_chunk_name[2] == 'G') && (m_chunk_name[3] == 'D'))
2042 {
2043 res = read_bkgd_chunk();
2044 if (res < 0)
2045 return res;
2046 }
2047 else if ((m_chunk_name[0] == 'g') && (m_chunk_name[1] == 'A') && (m_chunk_name[2] == 'M') && (m_chunk_name[3] == 'A'))
2048 {
2049 res = read_gama_chunk();
2050 if (res < 0)
2051 return res;
2052 }
2053 else if ((m_chunk_name[0] == 't') && (m_chunk_name[1] == 'R') && (m_chunk_name[2] == 'N') && (m_chunk_name[3] == 'S'))
2054 {
2055 res = read_trns_chunk();
2056 if (res < 0)
2057 return res;
2058 }
2059 }
2060 else
2061 {
2062 if ((m_chunk_name[0] == 'P') && (m_chunk_name[1] == 'L') && (m_chunk_name[2] == 'T') && (m_chunk_name[3] == 'E'))
2063 {
2064 res = read_plte_chunk();
2065 if (res < 0)
2066 return res;
2067 }
2068 else if ((m_chunk_name[0] == 'I') && (m_chunk_name[1] == 'D') && (m_chunk_name[2] == 'A') && (m_chunk_name[3] == 'T'))
2069 {
2070 break;
2071 }
2072 else
2073 {
2074 m_img_supported_flag = PNG_UNS_CRITICAL_CHUNK;
2075 }
2076 }
2077 }
2078
2079 return 0;
2080}
2081
2082png_decoder::png_decoder()
2083{
2084 clear();
2085}
2086
2087png_decoder::~png_decoder()
2088{
2089 uninitialize();
2090}
2091
2092void png_decoder::clear()
2093{
2094 clear_obj(m_pMalloc_blocks);
2095
2096 m_pFile = nullptr;
2097
2098 clear_obj(m_img_pal);
2099
2100 m_img_supported_flag = FALSE;
2101
2102 m_adam7_image_buf.clear();
2103
2104 clear_obj(m_ihdr);
2105
2106 m_chunk_flag = FALSE;
2107 m_chunk_size = 0;
2108 m_chunk_left = 0;
2109 m_chunk_crc32 = 0;
2110 clear_obj(m_chunk_name);
2111
2112 m_end_of_idat_chunks = 0;
2113
2114 m_dec_bytes_per_pixel = 0;
2115 m_dst_bytes_per_pixel = 0;
2116
2117 m_dec_bytes_per_line = 0;
2118 m_src_bytes_per_line = 0;
2119 m_dst_bytes_per_line = 0;
2120
2121 m_pProcess_func = nullptr;
2122
2123 m_pPre_line_buf = nullptr;
2124 m_pCur_line_buf = nullptr;
2125 m_pPro_line_buf = nullptr;
2126
2127 m_bkgd_flag = FALSE;
2128 clear_obj(m_bkgd_value);
2129
2130 m_gama_flag = FALSE;
2131 m_gama_value = 0;
2132
2133 m_plte_flag = FALSE;
2134
2135 m_trns_flag = FALSE;
2136 clear_obj(m_trns_value);
2137
2138 clear_obj(m_inflator);
2139
2140 m_inflate_src_buf_ofs = 0;
2141 m_inflate_src_buf_size = 0;
2142 m_inflate_dst_buf_ofs = 0;
2143
2144 m_inflate_eof_flag = FALSE;
2145
2146 clear_obj(m_trns_value);
2147
2148 m_pass_x_size = 0;
2149 m_pass_y_left = 0;
2150
2151 m_adam7_pass_num = 0;
2152 m_adam7_pass_y = 0;
2153 clear_obj(m_adam7_pass_size_x);
2154 clear_obj(m_adam7_pass_size_y);
2155
2156 m_adam7_decoded_flag = FALSE;
2157
2158 m_scanned_flag = false;
2159
2160 m_terminate_status = 0;
2161}
2162
2163int png_decoder::png_scan(png_file *pFile)
2164{
2165 m_pFile = pFile;
2166
2167 m_img_supported_flag = TRUE;
2168 m_terminate_status = 0;
2169
2170 int res = read_signature();
2171 if (res != 0)
2172 return res;
2173
2174 res = read_ihdr_chunk();
2175 if (res != 0)
2176 return res;
2177
2178 res = find_idat_chunk();
2179 if (res != 0)
2180 return res;
2181
2182 if (m_gama_flag)
2183 calc_gamma_table();
2184
2185 if (m_ihdr.m_color_type == PNG_COLOR_TYPE_PALETTIZED)
2186 {
2187 if (!m_plte_flag)
2188 return terminate(PNG_MISSING_PALETTE);
2189 }
2190 else if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE) || (m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE_ALPHA))
2191 {
2192 create_grey_palette();
2193 }
2194
2195 m_scanned_flag = true;
2196
2197 return 0;
2198}
2199
2200static inline uint8_t get_709_luma(uint32_t r, uint32_t g, uint32_t b)
2201{
2202 return (uint8_t)((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);
2203}
2204
2205bool get_png_info(const void* pImage_buf, size_t buf_size, png_info &info)
2206{
2207 memset(&info, 0, sizeof(info));
2208
2209 if ((!pImage_buf) || (buf_size < MIN_PNG_SIZE))
2210 return false;
2211
2212 png_readonly_memory_file mf;
2213 mf.init(pImage_buf, buf_size);
2214
2215 png_decoder dec;
2216
2217 int status = dec.png_scan(&mf);
2218 if ((status != 0) || (dec.m_img_supported_flag != TRUE))
2219 return false;
2220
2221 info.m_width = dec.m_ihdr.m_width;
2222 info.m_height = dec.m_ihdr.m_height;
2223 info.m_bit_depth = dec.m_ihdr.m_bit_depth;
2224 info.m_color_type = dec.m_ihdr.m_color_type;
2225 info.m_has_gamma = dec.m_gama_flag != 0;
2226 info.m_gamma_value = dec.m_gama_value;
2227 info.m_has_trns = dec.m_trns_flag != 0;
2228
2229 switch (dec.m_ihdr.m_color_type)
2230 {
2231 case PNG_COLOR_TYPE_GREYSCALE:
2232 info.m_num_chans = dec.m_trns_flag ? 2 : 1;
2233 break;
2234 case PNG_COLOR_TYPE_GREYSCALE_ALPHA:
2235 info.m_num_chans = 2;
2236 break;
2237 case PNG_COLOR_TYPE_PALETTIZED:
2238 case PNG_COLOR_TYPE_TRUECOLOR:
2239 info.m_num_chans = dec.m_trns_flag ? 4 : 3;
2240 break;
2241 case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:
2242 info.m_num_chans = 4;
2243 break;
2244 default:
2245 assert(0);
2246 break;
2247 }
2248
2249 return true;
2250}
2251
2252void* load_png(const void* pImage_buf, size_t buf_size, uint32_t desired_chans, uint32_t& width, uint32_t& height, uint32_t& num_chans)
2253{
2254 width = 0;
2255 height = 0;
2256 num_chans = 0;
2257
2258 if ((!pImage_buf) || (buf_size < MIN_PNG_SIZE))
2259 {
2260 assert(0);
2261 return nullptr;
2262 }
2263
2264 if (desired_chans > 4)
2265 {
2266 assert(0);
2267 return nullptr;
2268 }
2269
2270 png_readonly_memory_file mf;
2271 mf.init(pImage_buf, buf_size);
2272
2273 png_decoder dec;
2274
2275 int status = dec.png_scan(&mf);
2276 if ((status != 0) || (dec.m_img_supported_flag != TRUE))
2277 return nullptr;
2278
2279 uint32_t colortype = dec.m_ihdr.m_color_type;
2280 switch (colortype)
2281 {
2282 case PNG_COLOR_TYPE_GREYSCALE:
2283 num_chans = dec.m_trns_flag ? 2 : 1;
2284 break;
2285 case PNG_COLOR_TYPE_GREYSCALE_ALPHA:
2286 num_chans = 2;
2287 break;
2288 case PNG_COLOR_TYPE_PALETTIZED:
2289 case PNG_COLOR_TYPE_TRUECOLOR:
2290 num_chans = dec.m_trns_flag ? 4 : 3;
2291 break;
2292 case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:
2293 num_chans = 4;
2294 break;
2295 default:
2296 assert(0);
2297 break;
2298 }
2299
2300 if (!desired_chans)
2301 desired_chans = num_chans;
2302
2303#if 0
2304 printf("lode_png: %ux%u bitdepth: %u colortype: %u trns: %u ilace: %u\n",
2305 dec.m_ihdr.m_width,
2306 dec.m_ihdr.m_height,
2307 dec.m_ihdr.m_bit_depth,
2308 dec.m_ihdr.m_color_type,
2309 dec.m_trns_flag,
2310 dec.m_ihdr.m_ilace_type);
2311#endif
2312
2313 width = dec.m_ihdr.m_width;
2314 height = dec.m_ihdr.m_height;
2315 uint32_t bitdepth = dec.m_ihdr.m_bit_depth;
2316 uint32_t pitch = width * desired_chans;
2317
2318 uint64_t total_size = (uint64_t)pitch * height;
2319 if (total_size > 0x7FFFFFFFULL)
2320 return nullptr;
2321
2322 uint8_t* pBuf = (uint8_t*)malloc((size_t)total_size);
2323 if (!pBuf)
2324 return nullptr;
2325
2326 if (dec.png_decode_start() != 0)
2327 {
2328 free(pBuf);
2329 return nullptr;
2330 }
2331
2332 uint8_t* pDst = pBuf;
2333
2334 for (uint32_t y = 0; y < height; y++, pDst += pitch)
2335 {
2336 uint8_t* pLine;
2337 uint32_t line_bytes;
2338 if (dec.png_decode((void**)&pLine, &line_bytes) != 0)
2339 {
2340 free(pBuf);
2341 return nullptr;
2342 }
2343
2344 // This conversion matrix handles converting RGB->Luma, converting grayscale samples to 8-bit samples, converting palettized images, and PNG transparency.
2345 switch (colortype)
2346 {
2347 case PNG_COLOR_TYPE_GREYSCALE:
2348 {
2349 uint32_t trans_value = dec.m_trns_value[0];
2350
2351 switch (desired_chans)
2352 {
2353 case 1:
2354 if (bitdepth == 16)
2355 {
2356 assert(line_bytes == width * 2);
2357
2358 for (uint32_t i = 0; i < width; i++)
2359 pDst[i] = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2360 }
2361 else if (bitdepth == 8)
2362 {
2363 assert(line_bytes == width);
2364 memcpy(pDst, pLine, pitch);
2365 }
2366 else
2367 {
2368 assert(line_bytes == width);
2369 for (uint32_t i = 0; i < width; i++)
2370 pDst[i] = dec.m_img_pal[pLine[i] * 3];
2371 }
2372 break;
2373 case 2:
2374 if (bitdepth == 16)
2375 {
2376 assert(line_bytes == width * 2);
2377 for (uint32_t i = 0; i < width; i++)
2378 {
2379 pDst[i * 2 + 0] = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2380 pDst[i * 2 + 1] = pLine[i * 2 + 1];
2381 }
2382 }
2383 else if (dec.m_trns_flag)
2384 {
2385 assert(line_bytes == width);
2386 for (uint32_t i = 0; i < width; i++)
2387 {
2388 pDst[i * 2 + 0] = dec.m_img_pal[pLine[i] * 3];
2389 pDst[i * 2 + 1] = (pLine[i] == trans_value) ? 0 : 255;
2390 }
2391 }
2392 else
2393 {
2394 assert(line_bytes == width);
2395 for (uint32_t i = 0; i < width; i++)
2396 {
2397 pDst[i * 2 + 0] = dec.m_img_pal[pLine[i] * 3];
2398 pDst[i * 2 + 1] = 255;
2399 }
2400 }
2401 break;
2402 case 3:
2403 if (bitdepth == 16)
2404 {
2405 assert(line_bytes == width * 2);
2406 for (uint32_t i = 0; i < width; i++)
2407 {
2408 uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2409 pDst[i * 3 + 0] = c;
2410 pDst[i * 3 + 1] = c;
2411 pDst[i * 3 + 2] = c;
2412 }
2413 }
2414 else
2415 {
2416 assert(line_bytes == width);
2417 for (uint32_t i = 0; i < width; i++)
2418 {
2419 uint8_t c = dec.m_img_pal[pLine[i] * 3];
2420 pDst[i * 3 + 0] = c;
2421 pDst[i * 3 + 1] = c;
2422 pDst[i * 3 + 2] = c;
2423 }
2424 }
2425 break;
2426 case 4:
2427 if (bitdepth == 16)
2428 {
2429 assert(line_bytes == width * 2);
2430 for (uint32_t i = 0; i < width; i++)
2431 {
2432 uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2433 pDst[i * 4 + 0] = c;
2434 pDst[i * 4 + 1] = c;
2435 pDst[i * 4 + 2] = c;
2436 pDst[i * 4 + 3] = pLine[i * 2 + 1];
2437 }
2438 }
2439 else if (dec.m_trns_flag)
2440 {
2441 assert(line_bytes == width);
2442 for (uint32_t i = 0; i < width; i++)
2443 {
2444 uint8_t c = dec.m_img_pal[pLine[i] * 3];
2445 pDst[i * 4 + 0] = c;
2446 pDst[i * 4 + 1] = c;
2447 pDst[i * 4 + 2] = c;
2448 pDst[i * 4 + 3] = (pLine[i] == trans_value) ? 0 : 255;
2449 }
2450 }
2451 else
2452 {
2453 assert(line_bytes == width);
2454 for (uint32_t i = 0; i < width; i++)
2455 {
2456 uint8_t c = dec.m_img_pal[pLine[i] * 3];
2457 pDst[i * 4 + 0] = c;
2458 pDst[i * 4 + 1] = c;
2459 pDst[i * 4 + 2] = c;
2460 pDst[i * 4 + 3] = 255;
2461 }
2462 }
2463 break;
2464 }
2465
2466 break;
2467 }
2468 case PNG_COLOR_TYPE_GREYSCALE_ALPHA:
2469 {
2470 assert(line_bytes == width * 2);
2471
2472 switch (desired_chans)
2473 {
2474 case 1:
2475 for (uint32_t i = 0; i < width; i++)
2476 pDst[i] = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2477 break;
2478 case 2:
2479 assert(line_bytes == pitch);
2480 if (bitdepth >= 8)
2481 memcpy(pDst, pLine, pitch);
2482 else
2483 {
2484 for (uint32_t i = 0; i < width; i++)
2485 {
2486 pDst[i * 2 + 0] = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2487 pDst[i * 2 + 1] = pLine[i * 2 + 1];
2488 }
2489 }
2490 break;
2491 case 3:
2492 for (uint32_t i = 0; i < width; i++)
2493 {
2494 uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2495 pDst[i * 3 + 0] = c;
2496 pDst[i * 3 + 1] = c;
2497 pDst[i * 3 + 2] = c;
2498 }
2499 break;
2500 case 4:
2501 for (uint32_t i = 0; i < width; i++)
2502 {
2503 uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];
2504 pDst[i * 4 + 0] = c;
2505 pDst[i * 4 + 1] = c;
2506 pDst[i * 4 + 2] = c;
2507 pDst[i * 4 + 3] = pLine[i * 2 + 1];
2508 }
2509 break;
2510 }
2511
2512 break;
2513 }
2514 case PNG_COLOR_TYPE_PALETTIZED:
2515 {
2516 assert(line_bytes == width);
2517
2518 switch (desired_chans)
2519 {
2520 case 1:
2521 for (uint32_t i = 0; i < width; i++)
2522 {
2523 const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];
2524 pDst[i] = get_709_luma(p[0], p[1], p[2]);
2525 }
2526 break;
2527 case 2:
2528 if (dec.m_trns_flag)
2529 {
2530 for (uint32_t i = 0; i < width; i++)
2531 {
2532 const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];
2533 pDst[i * 2 + 0] = get_709_luma(p[0], p[1], p[2]);
2534 pDst[i * 2 + 1] = (uint8_t)dec.m_trns_value[pLine[i]];
2535 }
2536 }
2537 else
2538 {
2539 for (uint32_t i = 0; i < width; i++)
2540 {
2541 const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];
2542 pDst[i * 2 + 0] = get_709_luma(p[0], p[1], p[2]);
2543 pDst[i * 2 + 1] = 255;
2544 }
2545 }
2546 break;
2547 case 3:
2548 for (uint32_t i = 0; i < width; i++)
2549 {
2550 const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];
2551 pDst[i * 3 + 0] = p[0];
2552 pDst[i * 3 + 1] = p[1];
2553 pDst[i * 3 + 2] = p[2];
2554 }
2555 break;
2556 case 4:
2557 if (dec.m_trns_flag)
2558 {
2559 for (uint32_t i = 0; i < width; i++)
2560 {
2561 const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];
2562 pDst[i * 4 + 0] = p[0];
2563 pDst[i * 4 + 1] = p[1];
2564 pDst[i * 4 + 2] = p[2];
2565 pDst[i * 4 + 3] = (uint8_t)dec.m_trns_value[pLine[i]];
2566 }
2567 }
2568 else
2569 {
2570 for (uint32_t i = 0; i < width; i++)
2571 {
2572 const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];
2573 pDst[i * 4 + 0] = p[0];
2574 pDst[i * 4 + 1] = p[1];
2575 pDst[i * 4 + 2] = p[2];
2576 pDst[i * 4 + 3] = 255;
2577 }
2578 }
2579 break;
2580 }
2581
2582 break;
2583 }
2584 case PNG_COLOR_TYPE_TRUECOLOR:
2585 case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:
2586 {
2587 assert(line_bytes == width * 4);
2588
2589 switch (desired_chans)
2590 {
2591 case 1:
2592 for (uint32_t i = 0; i < width; i++)
2593 {
2594 const uint8_t* p = &pLine[i * 4];
2595 pDst[i] = get_709_luma(p[0], p[1], p[2]);
2596 }
2597 break;
2598 case 2:
2599 for (uint32_t i = 0; i < width; i++)
2600 {
2601 const uint8_t* p = &pLine[i * 4];
2602 pDst[i * 2 + 0] = get_709_luma(p[0], p[1], p[2]);
2603 pDst[i * 2 + 1] = p[3];
2604 }
2605 break;
2606 case 3:
2607 for (uint32_t i = 0; i < width; i++)
2608 {
2609 const uint8_t* p = &pLine[i * 4];
2610 pDst[i * 3 + 0] = p[0];
2611 pDst[i * 3 + 1] = p[1];
2612 pDst[i * 3 + 2] = p[2];
2613 }
2614 break;
2615 case 4:
2616 memcpy(pDst, pLine, pitch);
2617 break;
2618 }
2619
2620 break;
2621 }
2622 default:
2623 assert(0);
2624 break;
2625 }
2626
2627 } // y
2628
2629 return pBuf;
2630}
2631
2632} // namespace pv_png
2633
2634/*
2635 This is free and unencumbered software released into the public domain.
2636
2637 Anyone is free to copy, modify, publish, use, compile, sell, or
2638 distribute this software, either in source code form or as a compiled
2639 binary, for any purpose, commercial or non-commercial, and by any
2640 means.
2641
2642 In jurisdictions that recognize copyright laws, the author or authors
2643 of this software dedicate any and all copyright interest in the
2644 software to the public domain. We make this dedication for the benefit
2645 of the public at large and to the detriment of our heirs and
2646 successors. We intend this dedication to be an overt act of
2647 relinquishment in perpetuity of all present and future rights to this
2648 software under copyright law.
2649
2650 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2651 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2652 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2653 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2654 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2655 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2656 OTHER DEALINGS IN THE SOFTWARE.
2657
2658 For more information, please refer to <http://unlicense.org/>
2659
2660 Richard Geldreich, Jr.
2661 1/20/2022
2662*/
2663