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 |
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 | |
32 | namespace pv_png |
33 | { |
34 | |
35 | const uint32_t MIN_PNG_SIZE = 8 + 13 + 8 + 1 + 4 + 12; |
36 | |
37 | template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; } |
38 | template <typename S> inline S minimum(S a, S b) { return (a < b) ? a : b; } |
39 | |
40 | template <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 | |
47 | enum |
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 | |
82 | struct 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 | |
93 | class png_file |
94 | { |
95 | public: |
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 | |
107 | class png_memory_file : public png_file |
108 | { |
109 | public: |
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 | |
189 | class png_readonly_memory_file : public png_file |
190 | { |
191 | public: |
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 | |
268 | class png_cfile : public png_file |
269 | { |
270 | public: |
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. |
376 | class png_decoder |
377 | { |
378 | public: |
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 | |
516 | void 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 | |
529 | int 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 | |
538 | void* 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 | |
561 | void* 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 | |
573 | int 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 | |
581 | int64_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 | |
593 | int 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 | |
632 | int 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 | |
646 | int 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 | |
660 | int64_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 | |
675 | int 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 | |
701 | int 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 | |
742 | inline 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 | |
747 | inline 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 | |
754 | inline 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 | |
762 | inline 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 | |
771 | static 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 | |
788 | static 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 | |
805 | static 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 | |
829 | static 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 | |
862 | static 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 | |
874 | static 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 | |
883 | static 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 | |
896 | static 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 | |
923 | static 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 | |
957 | static 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 | |
994 | static 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 | |
1008 | static 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 | |
1022 | static 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 | |
1031 | static 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 | |
1047 | void 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 | |
1063 | void 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 | |
1070 | void 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 | |
1089 | inline 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 | |
1109 | void 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 | |
1146 | int 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 |
1155 | int 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 | |
1221 | int 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 | |
1248 | int 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 | |
1494 | void png_decoder::png_decode_end() |
1495 | { |
1496 | uninitialize(); |
1497 | } |
1498 | |
1499 | int 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 | |
1693 | void 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 | |
1721 | void 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 | |
1737 | int 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 | |
1757 | int 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 | |
1877 | int 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 | |
1916 | int 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 | |
1929 | int 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 | |
1983 | int 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 | |
2031 | int 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 | |
2082 | png_decoder::png_decoder() |
2083 | { |
2084 | clear(); |
2085 | } |
2086 | |
2087 | png_decoder::~png_decoder() |
2088 | { |
2089 | uninitialize(); |
2090 | } |
2091 | |
2092 | void 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 | |
2163 | int 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 | |
2200 | static 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 | |
2205 | bool 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 | |
2252 | void* 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 | |