Advertisement
LeventeDaradici

pngle.c

May 11th, 2023
1,088
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 28.25 KB | Source Code | 0 0
  1. /*-
  2.  * MIT License
  3.  *
  4.  * Copyright (c) 2019 kikuchan
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  7.  * of this software and associated documentation files (the "Software"), to deal
  8.  * in the Software without restriction, including without limitation the rights
  9.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10.  * copies of the Software, and to permit persons to whom the Software is
  11.  * furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included in all
  14.  * copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22.  * SOFTWARE.
  23.  */
  24. //#define PNGLE_NO_GAMMA_CORRECTION
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <stdint.h>
  29. #include <math.h>
  30.  
  31. #include "miniz.h"
  32. #include "pngle.h"
  33.  
  34. #ifndef MIN
  35. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  36. #endif
  37.  
  38. #ifdef PNGLE_DEBUG
  39. #define debug_printf(...) fprintf(stderr, __VA_ARGS__)
  40. #else
  41. #define debug_printf(...) ((void)0)
  42. #endif
  43.  
  44. #define PNGLE_ERROR(s) (pngle->error = (s), pngle->state = PNGLE_STATE_ERROR, -1)
  45. #define PNGLE_CALLOC(a, b, name) (debug_printf("[pngle] Allocating %zu bytes for %s\n", (size_t)(a) * (size_t)(b), (name)), calloc((size_t)(a), (size_t)(b)))
  46.  
  47. #define PNGLE_UNUSED(x) (void)(x)
  48.  
  49. typedef enum {
  50.   PNGLE_STATE_ERROR = -2,
  51.   PNGLE_STATE_EOF = -1,
  52.   PNGLE_STATE_INITIAL = 0,
  53.  
  54.   PNGLE_STATE_FIND_CHUNK_HEADER,
  55.   PNGLE_STATE_HANDLE_CHUNK,
  56.   PNGLE_STATE_CRC,
  57. } pngle_state_t;
  58.  
  59. typedef enum {
  60. // Supported chunks
  61. //   Filter chunk names by following command to (re)generate hex constants;
  62. //     % perl -ne 'chomp; s/.*\s*\/\/\s*//; print "\tPNGLE_CHUNK_$_ = 0x" . unpack("H*") . "UL, // $_\n";'
  63.   PNGLE_CHUNK_IHDR = 0x49484452UL, // IHDR
  64.   PNGLE_CHUNK_PLTE = 0x504c5445UL, // PLTE
  65.   PNGLE_CHUNK_IDAT = 0x49444154UL, // IDAT
  66.   PNGLE_CHUNK_IEND = 0x49454e44UL, // IEND
  67.   PNGLE_CHUNK_tRNS = 0x74524e53UL, // tRNS
  68.   PNGLE_CHUNK_gAMA = 0x67414d41UL, // gAMA
  69. } pngle_chunk_t;
  70.  
  71. // typedef struct _pngle_t pngle_t; // declared in pngle.h
  72. struct _pngle_t {
  73.   pngle_ihdr_t hdr;
  74.  
  75.   uint_fast8_t channels; // 0 indicates IHDR hasn't been processed yet
  76.  
  77.   // PLTE chunk
  78.   size_t n_palettes;
  79.   uint8_t *palette;
  80.  
  81.   // tRNS chunk
  82.   size_t n_trans_palettes;
  83.   uint8_t *trans_palette;
  84.  
  85.   // parser state (reset on every chunk header)
  86.   pngle_state_t state;
  87.   uint32_t chunk_type;
  88.   uint32_t chunk_remain;
  89.   mz_ulong crc32;
  90.  
  91.   // decompression state (reset on IHDR)
  92.   tinfl_decompressor inflator; // 11000 bytes
  93.   uint8_t lz_buf[TINFL_LZ_DICT_SIZE]; // 32768 bytes
  94.   uint8_t *next_out; // NULL indicates IDAT hasn't been processed yet
  95.   size_t  avail_out;
  96.  
  97.   // scanline decoder (reset on every set_interlace_pass() call)
  98.   uint8_t *scanline_ringbuf;
  99.   size_t scanline_ringbuf_size;
  100.   size_t scanline_ringbuf_cidx;
  101.   int_fast8_t scanline_remain_bytes_to_render;
  102.   int_fast8_t filter_type;
  103.   uint32_t drawing_x;
  104.   uint32_t drawing_y;
  105.  
  106.   // interlace
  107.   uint_fast8_t interlace_pass;
  108.  
  109.   const char *error;
  110.  
  111. #ifndef PNGLE_NO_GAMMA_CORRECTION
  112.   uint8_t *gamma_table;
  113.   double display_gamma;
  114. #endif
  115.  
  116.   pngle_init_callback_t init_callback;
  117.   pngle_draw_callback_t draw_callback;
  118.   pngle_done_callback_t done_callback;
  119.  
  120.   void *user_data;
  121. };
  122.  
  123. // magic
  124. static const uint8_t png_sig[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
  125. static uint32_t interlace_off_x[8] = { 0,  0, 4, 0, 2, 0, 1, 0 };
  126. static uint32_t interlace_off_y[8] = { 0,  0, 0, 4, 0, 2, 0, 1 };
  127. static uint32_t interlace_div_x[8] = { 1,  8, 8, 4, 4, 2, 2, 1 };
  128. static uint32_t interlace_div_y[8] = { 1,  8, 8, 8, 4, 4, 2, 2 };
  129.  
  130.  
  131. static inline uint8_t  read_uint8(const uint8_t *p)
  132. {
  133.   return *p;
  134. }
  135.  
  136. static inline uint32_t read_uint32(const uint8_t *p)
  137. {
  138.   return (p[0] << 24)
  139.        | (p[1] << 16)
  140.        | (p[2] <<  8)
  141.        | (p[3] <<  0)
  142.   ;
  143. }
  144.  
  145. static inline uint32_t U32_CLAMP_ADD(uint32_t a, uint32_t b, uint32_t top)
  146. {
  147.   uint32_t v = a + b;
  148.   if (v < a) return top; // uint32 overflow
  149.   if (v > top) return top; // clamp
  150.   return v;
  151. }
  152.  
  153.  
  154. void pngle_reset(pngle_t *pngle)
  155. {
  156.   if (!pngle) return ;
  157.  
  158.   pngle->state = PNGLE_STATE_INITIAL;
  159.   pngle->error = "No error";
  160.  
  161.   if (pngle->scanline_ringbuf) free(pngle->scanline_ringbuf);
  162.   if (pngle->palette) free(pngle->palette);
  163.   if (pngle->trans_palette) free(pngle->trans_palette);
  164. #ifndef PNGLE_NO_GAMMA_CORRECTION
  165.   if (pngle->gamma_table) free(pngle->gamma_table);
  166. #endif
  167.  
  168.   pngle->scanline_ringbuf = NULL;
  169.   pngle->palette = NULL;
  170.   pngle->trans_palette = NULL;
  171. #ifndef PNGLE_NO_GAMMA_CORRECTION
  172.   pngle->gamma_table = NULL;
  173. #endif
  174.  
  175.   pngle->channels = 0; // indicates IHDR hasn't been processed yet
  176.   pngle->next_out = NULL; // indicates IDAT hasn't been processed yet
  177.  
  178.   // clear them just in case...
  179.   memset(&pngle->hdr, 0, sizeof(pngle->hdr));
  180.   pngle->n_palettes = 0;
  181.   pngle->n_trans_palettes = 0;
  182.  
  183.   tinfl_init(&pngle->inflator);
  184. }
  185.  
  186. pngle_t *pngle_new()
  187. {
  188.   pngle_t *pngle = (pngle_t *)PNGLE_CALLOC(1, sizeof(pngle_t), "pngle_t");
  189.   if (!pngle) return NULL;
  190.  
  191.   pngle_reset(pngle);
  192.  
  193.   return pngle;
  194. }
  195.  
  196. void pngle_destroy(pngle_t *pngle)
  197. {
  198.   if (pngle) {
  199.     pngle_reset(pngle);
  200.     free(pngle);
  201.   }
  202. }
  203.  
  204. const char *pngle_error(pngle_t *pngle)
  205. {
  206.   if (!pngle) return "Uninitialized";
  207.   return pngle->error;
  208. }
  209.  
  210. uint32_t pngle_get_width(pngle_t *pngle)
  211. {
  212.   if (!pngle) return 0;
  213.   return pngle->hdr.width;
  214. }
  215.  
  216. uint32_t pngle_get_height(pngle_t *pngle)
  217. {
  218.   if (!pngle) return 0;
  219.   return pngle->hdr.height;
  220. }
  221.  
  222. pngle_ihdr_t *pngle_get_ihdr(pngle_t *pngle)
  223. {
  224.   if (!pngle) return NULL;
  225.   if (pngle->channels == 0) return NULL;
  226.   return &pngle->hdr;
  227. }
  228.  
  229.  
  230. static int is_trans_color(pngle_t *pngle, uint16_t *value, size_t n)
  231. {
  232.   if (pngle->n_trans_palettes != 1) return 0; // false (none or indexed)
  233.  
  234.   for (size_t i = 0; i < n; i++) {
  235.     if (value[i] != (pngle->trans_palette[i * 2 + 0] * 0x100 + pngle->trans_palette[i * 2 + 1])) return 0; // false
  236.   }
  237.   return 1; // true
  238. }
  239.  
  240. static inline void scanline_ringbuf_push(pngle_t *pngle, uint8_t value)
  241. {
  242.   pngle->scanline_ringbuf[pngle->scanline_ringbuf_cidx] = value;
  243.   pngle->scanline_ringbuf_cidx = (pngle->scanline_ringbuf_cidx + 1) % pngle->scanline_ringbuf_size;
  244. }
  245.  
  246. static inline uint16_t get_value(pngle_t *pngle, size_t *ridx, int *bitcount, int depth)
  247. {
  248.   uint16_t v;
  249.  
  250.   switch (depth) {
  251.   case 1:
  252.   case 2:
  253.   case 4:
  254.     if (*bitcount >= 8) {
  255.       *bitcount = 0;
  256.       *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
  257.     }
  258.     *bitcount += depth;
  259.     uint8_t mask = ((1UL << depth) - 1);
  260.     uint8_t shift = (8 - *bitcount);
  261.     return (pngle->scanline_ringbuf[*ridx] >> shift) & mask;
  262.  
  263.   case 8:
  264.     v = pngle->scanline_ringbuf[*ridx];
  265.     *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
  266.     return v;
  267.  
  268.   case 16:
  269.     v = pngle->scanline_ringbuf[*ridx];
  270.     *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
  271.  
  272.     v = v * 0x100 + pngle->scanline_ringbuf[*ridx];
  273.     *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
  274.     return v;
  275.   }
  276.  
  277.   return 0;
  278. }
  279.  
  280. static int pngle_draw_pixels(pngle_t *pngle, size_t scanline_ringbuf_xidx)
  281. {
  282.   uint16_t v[4]; // MAX_CHANNELS
  283.   int bitcount = 0;
  284.   uint8_t pixel_depth = (pngle->hdr.color_type & 1) ? 8 : pngle->hdr.depth;
  285.   uint16_t maxval = (1UL << pixel_depth) - 1;
  286.  
  287.   int n_pixels = pngle->hdr.depth == 16 ? 1 : (8 / pngle->hdr.depth);
  288.  
  289.   for (; n_pixels-- > 0 && pngle->drawing_x < pngle->hdr.width; pngle->drawing_x = U32_CLAMP_ADD(pngle->drawing_x, interlace_div_x[pngle->interlace_pass], pngle->hdr.width)) {
  290.     for (uint_fast8_t c = 0; c < pngle->channels; c++) {
  291.       v[c] = get_value(pngle, &scanline_ringbuf_xidx, &bitcount, pngle->hdr.depth);
  292.     }
  293.  
  294.     // color type: 0000 0111
  295.     //                     ^-- indexed color (palette)
  296.     //                    ^--- Color
  297.     //                   ^---- Alpha channel
  298.  
  299.     if (pngle->hdr.color_type & 2) {
  300.       // color
  301.       if (pngle->hdr.color_type & 1) {
  302.         // indexed color: type 3
  303.  
  304.         // lookup palette info
  305.         uint16_t pidx = v[0];
  306.         if (pidx >= pngle->n_palettes) return PNGLE_ERROR("Color index is out of range");
  307.  
  308.         v[0] = pngle->palette[pidx * 3 + 0];
  309.         v[1] = pngle->palette[pidx * 3 + 1];
  310.         v[2] = pngle->palette[pidx * 3 + 2];
  311.  
  312.         // tRNS as an indexed alpha value table (for color type 3)
  313.         v[3] = pidx < pngle->n_trans_palettes ? pngle->trans_palette[pidx] : maxval;
  314.       } else {
  315.         // true color: 2, and 6
  316.         v[3] = (pngle->hdr.color_type & 4) ? v[3] : is_trans_color(pngle, v, 3) ? 0 : maxval;
  317.       }
  318.     } else {
  319.       // alpha, tRNS, or opaque
  320.       v[3] = (pngle->hdr.color_type & 4) ? v[1] : is_trans_color(pngle, v, 1) ? 0 : maxval;
  321.  
  322.       // monochrome
  323.       v[1] = v[2] = v[0];
  324.     }
  325.  
  326.     if (pngle->draw_callback) {
  327.       uint8_t rgba[4] = {
  328.         (v[0] * 255 + maxval / 2) / maxval,
  329.         (v[1] * 255 + maxval / 2) / maxval,
  330.         (v[2] * 255 + maxval / 2) / maxval,
  331.         (v[3] * 255 + maxval / 2) / maxval
  332.       };
  333.  
  334. #ifndef PNGLE_NO_GAMMA_CORRECTION
  335.       if (pngle->gamma_table) {
  336.         for (int i = 0; i < 3; i++) {
  337.           rgba[i] = pngle->gamma_table[v[i]];
  338.         }
  339.       }
  340. #endif
  341.  
  342.       pngle->draw_callback(pngle, pngle->drawing_x, pngle->drawing_y
  343.         , MIN(interlace_div_x[pngle->interlace_pass] - interlace_off_x[pngle->interlace_pass], pngle->hdr.width  - pngle->drawing_x)
  344.         , MIN(interlace_div_y[pngle->interlace_pass] - interlace_off_y[pngle->interlace_pass], pngle->hdr.height - pngle->drawing_y)
  345.         , rgba
  346.       );
  347.     }
  348.   }
  349.  
  350.   return 0;
  351. }
  352.  
  353. static inline int paeth(int a, int b, int c)
  354. {
  355.   int p = a + b - c;
  356.   int pa = abs(p - a);
  357.   int pb = abs(p - b);
  358.   int pc = abs(p - c);
  359.  
  360.   if (pa <= pb && pa <= pc) return a;
  361.   if (pb <= pc) return b;
  362.   return c;
  363. }
  364.  
  365. static int set_interlace_pass(pngle_t *pngle, uint_fast8_t pass)
  366. {
  367.   pngle->interlace_pass = pass;
  368.  
  369.   uint_fast8_t bytes_per_pixel = (pngle->channels * pngle->hdr.depth + 7) / 8; // 1 if depth <= 8
  370.   size_t scanline_pixels = (pngle->hdr.width - interlace_off_x[pngle->interlace_pass] + interlace_div_x[pngle->interlace_pass] - 1) / interlace_div_x[pngle->interlace_pass];
  371.   size_t scanline_stride = (scanline_pixels * pngle->channels * pngle->hdr.depth + 7) / 8;
  372.  
  373.   pngle->scanline_ringbuf_size = scanline_stride + bytes_per_pixel * 2; // 2 rooms for c/x and a
  374.  
  375.   if (pngle->scanline_ringbuf) free(pngle->scanline_ringbuf);
  376.   if ((pngle->scanline_ringbuf = PNGLE_CALLOC(pngle->scanline_ringbuf_size, 1, "scanline ringbuf")) == NULL) return PNGLE_ERROR("Insufficient memory");
  377.  
  378.   pngle->drawing_x = interlace_off_x[pngle->interlace_pass];
  379.   pngle->drawing_y = interlace_off_y[pngle->interlace_pass];
  380.   pngle->filter_type = -1;
  381.  
  382.   pngle->scanline_ringbuf_cidx = 0;
  383.   pngle->scanline_remain_bytes_to_render = -1;
  384.  
  385.   return 0;
  386. }
  387.  
  388. static int setup_gamma_table(pngle_t *pngle, uint32_t png_gamma)
  389. {
  390. #ifndef PNGLE_NO_GAMMA_CORRECTION
  391.   if (pngle->gamma_table) free(pngle->gamma_table);
  392.  
  393.   if (pngle->display_gamma <= 0) return 0; // disable gamma correction
  394.   if (png_gamma == 0) return 0;
  395.  
  396.   uint8_t pixel_depth = (pngle->hdr.color_type & 1) ? 8 : pngle->hdr.depth;
  397.   uint16_t maxval = (1UL << pixel_depth) - 1;
  398.  
  399.   pngle->gamma_table = PNGLE_CALLOC(1, maxval + 1, "gamma table");
  400.   if (!pngle->gamma_table) return PNGLE_ERROR("Insufficient memory");
  401.  
  402.   for (int i = 0; i < maxval + 1; i++) {
  403.     pngle->gamma_table[i] = (uint8_t)floor(pow(i / (double)maxval, 100000.0 / png_gamma / pngle->display_gamma) * 255.0 + 0.5);
  404.   }
  405.   debug_printf("[pngle] gamma value = %d\n", png_gamma);
  406. #else
  407.   PNGLE_UNUSED(pngle);
  408.   PNGLE_UNUSED(png_gamma);
  409. #endif
  410.   return 0;
  411. }
  412.  
  413.  
  414. static int pngle_on_data(pngle_t *pngle, const uint8_t *p, int len)
  415. {
  416.   const uint8_t *ep = p + len;
  417.  
  418.   uint_fast8_t bytes_per_pixel = (pngle->channels * pngle->hdr.depth + 7) / 8; // 1 if depth <= 8
  419.  
  420.   while (p < ep) {
  421.     if (pngle->drawing_x >= pngle->hdr.width) {
  422.       // New row
  423.       pngle->drawing_x = interlace_off_x[pngle->interlace_pass];
  424.       pngle->drawing_y = U32_CLAMP_ADD(pngle->drawing_y, interlace_div_y[pngle->interlace_pass], pngle->hdr.height);
  425.       pngle->filter_type = -1; // Indicate new line
  426.     }
  427.  
  428.     if (pngle->drawing_x >= pngle->hdr.width || pngle->drawing_y >= pngle->hdr.height) {
  429.       if (pngle->interlace_pass == 0 || pngle->interlace_pass >= 7) return len; // Do nothing further
  430.  
  431.       // Interlace: Next pass
  432.       if (set_interlace_pass(pngle, pngle->interlace_pass + 1) < 0) return -1;
  433.       debug_printf("[pngle] interlace pass changed to: %d\n", pngle->interlace_pass);
  434.  
  435.       continue; // This is required because "No filter type bytes are present in an empty pass".
  436.     }
  437.  
  438.     if (pngle->filter_type < 0) {
  439.       if (*p > 4) {
  440.         debug_printf("[pngle] Invalid filter type is found; 0x%02x\n", *p);
  441.         return PNGLE_ERROR("Invalid filter type is found");
  442.       }
  443.  
  444.       pngle->filter_type = (int_fast8_t)*p++; // 0 - 4
  445.  
  446.       // push sentinel bytes for new line
  447.       for (uint_fast8_t i = 0; i < bytes_per_pixel; i++) {
  448.         scanline_ringbuf_push(pngle, 0);
  449.       }
  450.  
  451.       continue;
  452.     }
  453.  
  454.     size_t cidx =  pngle->scanline_ringbuf_cidx;
  455.     size_t bidx = (pngle->scanline_ringbuf_cidx                                + bytes_per_pixel) % pngle->scanline_ringbuf_size;
  456.     size_t aidx = (pngle->scanline_ringbuf_cidx + pngle->scanline_ringbuf_size - bytes_per_pixel) % pngle->scanline_ringbuf_size;
  457.     // debug_printf("[pngle] cidx = %zd, bidx = %zd, aidx = %zd\n", cidx, bidx, aidx);
  458.  
  459.     uint8_t c = pngle->scanline_ringbuf[cidx]; // left-up
  460.     uint8_t b = pngle->scanline_ringbuf[bidx]; // up
  461.     uint8_t a = pngle->scanline_ringbuf[aidx]; // left
  462.     uint8_t x = *p++; // target
  463.     // debug_printf("[pngle] c = 0x%02x, b = 0x%02x, a = 0x%02x, x = 0x%02x\n", c, b, a, x);
  464.  
  465.     // Reverse the filter
  466.     switch (pngle->filter_type) {
  467.     case 0: break; // None
  468.     case 1: x += a; break; // Sub
  469.     case 2: x += b; break; // Up
  470.     case 3: x += (a + b) / 2; break; // Average
  471.     case 4: x += paeth(a, b, c); break; // Paeth
  472.     }
  473.  
  474.     scanline_ringbuf_push(pngle, x); // updates scanline_ringbuf_cidx
  475.  
  476.     if (pngle->scanline_remain_bytes_to_render < 0) pngle->scanline_remain_bytes_to_render = bytes_per_pixel;
  477.     if (--pngle->scanline_remain_bytes_to_render == 0) {
  478.       size_t xidx = (pngle->scanline_ringbuf_cidx + pngle->scanline_ringbuf_size - bytes_per_pixel) % pngle->scanline_ringbuf_size;
  479.  
  480.       if (pngle_draw_pixels(pngle, xidx) < 0) return -1;
  481.  
  482.       pngle->scanline_remain_bytes_to_render = -1; // reset
  483.     }
  484.   }
  485.  
  486.   return len;
  487. }
  488.  
  489.  
  490. static int pngle_handle_chunk(pngle_t *pngle, const uint8_t *buf, size_t len)
  491. {
  492.   size_t consume = 0;
  493.  
  494.   switch (pngle->chunk_type) {
  495.   case PNGLE_CHUNK_IHDR:
  496.     // parse IHDR
  497.     consume = 13;
  498.     if (len < consume) return 0;
  499.  
  500.     debug_printf("[pngle]   Parse IHDR\n");
  501.  
  502.     pngle->hdr.width       = read_uint32(buf +  0);
  503.     pngle->hdr.height      = read_uint32(buf +  4);
  504.     pngle->hdr.depth       = read_uint8 (buf +  8);
  505.     pngle->hdr.color_type  = read_uint8 (buf +  9);
  506.     pngle->hdr.compression = read_uint8 (buf + 10);
  507.     pngle->hdr.filter      = read_uint8 (buf + 11);
  508.     pngle->hdr.interlace   = read_uint8 (buf + 12);
  509.  
  510.  
  511.     debug_printf("[pngle]     width      : %d\n", pngle->hdr.width      );
  512.     debug_printf("[pngle]     height     : %d\n", pngle->hdr.height     );
  513.     debug_printf("[pngle]     depth      : %d\n", pngle->hdr.depth      );
  514.     debug_printf("[pngle]     color_type : %d\n", pngle->hdr.color_type );
  515.     debug_printf("[pngle]     compression: %d\n", pngle->hdr.compression);
  516.     debug_printf("[pngle]     filter     : %d\n", pngle->hdr.filter     );
  517.     debug_printf("[pngle]     interlace  : %d\n", pngle->hdr.interlace  );
  518.  
  519.     /*
  520.             Color    Allowed    Interpretation                            channels
  521.             Type    Bit Depths
  522.  
  523.             0       1,2,4,8,16  Each pixel is a grayscale sample.         1 channels (Brightness)
  524.  
  525.             2       8,16        Each pixel is an R,G,B triple.            3 channels (R, G, B)
  526.  
  527.             3       1,2,4,8     Each pixel is a palette index;            1 channels (palette info)
  528.                                 a PLTE chunk must appear.
  529.  
  530.             4       8,16        Each pixel is a grayscale sample,         2 channels (Brightness, Alpha)
  531.                                 followed by an alpha sample.
  532.  
  533.             6       8,16        Each pixel is an R,G,B triple,            4 channels (R, G, B, Alpha)
  534.                                 followed by an alpha sample.
  535.     */
  536.     //  111
  537.     //    ^-- indexed color (palette)
  538.     //   ^--- Color
  539.     //  ^---- Alpha channel
  540.  
  541.     switch (pngle->hdr.color_type) {
  542.     case 0: pngle->channels = 1; if (pngle->hdr.depth != 1 && pngle->hdr.depth != 2 && pngle->hdr.depth != 4 && pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // grayscale
  543.     case 2: pngle->channels = 3; if (                                                                           pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor
  544.     case 3: pngle->channels = 1; if (pngle->hdr.depth != 1 && pngle->hdr.depth != 2 && pngle->hdr.depth != 4 && pngle->hdr.depth != 8                          ) return PNGLE_ERROR("Invalid bit depth"); break; // indexed color
  545.     case 4: pngle->channels = 2; if (                                                                           pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // grayscale + alpha
  546.     case 6: pngle->channels = 4; if (                                                                           pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor + alpha
  547.     default:
  548.       return PNGLE_ERROR("Incorrect IHDR info");
  549.     }
  550.  
  551.     if (pngle->hdr.compression != 0) return PNGLE_ERROR("Unsupported compression type in IHDR");
  552.     if (pngle->hdr.filter      != 0) return PNGLE_ERROR("Unsupported filter type in IHDR");
  553.  
  554.     // interlace
  555.     if (set_interlace_pass(pngle, pngle->hdr.interlace ? 1 : 0) < 0) return -1;
  556.  
  557.     // callback
  558.     if (pngle->init_callback) pngle->init_callback(pngle, pngle->hdr.width, pngle->hdr.height);
  559.  
  560.     break;
  561.  
  562.   case PNGLE_CHUNK_IDAT:
  563.     // parse & decode IDAT chunk
  564.     if (len < 1) return 0;
  565.  
  566.     debug_printf("[pngle]   Reading IDAT (len %zd / chunk remain %u)\n", len, pngle->chunk_remain);
  567.  
  568.     size_t in_bytes  = len;
  569.     size_t out_bytes = pngle->avail_out;
  570.  
  571.     //debug_printf("[pngle]     in_bytes %zd, out_bytes %zd, next_out %p\n", in_bytes, out_bytes, pngle->next_out);
  572.  
  573.     // XXX: tinfl_decompress always requires (next_out - lz_buf + avail_out) == TINFL_LZ_DICT_SIZE
  574.     tinfl_status status = tinfl_decompress(&pngle->inflator, (const mz_uint8 *)buf, &in_bytes, pngle->lz_buf, (mz_uint8 *)pngle->next_out, &out_bytes, TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_PARSE_ZLIB_HEADER);
  575.  
  576.     //debug_printf("[pngle]       tinfl_decompress\n");
  577.     //debug_printf("[pngle]       => in_bytes %zd, out_bytes %zd, next_out %p, status %d\n", in_bytes, out_bytes, pngle->next_out, status);
  578.  
  579.     if (status < TINFL_STATUS_DONE) {
  580.       // Decompression failed.
  581.       debug_printf("[pngle] tinfl_decompress() failed with status %d!\n", status);
  582.       return PNGLE_ERROR("Failed to decompress the IDAT stream");
  583.     }
  584.  
  585.     pngle->next_out   += out_bytes;
  586.     pngle->avail_out  -= out_bytes;
  587.  
  588.     // debug_printf("[pngle]         => avail_out %zd, next_out %p\n", pngle->avail_out, pngle->next_out);
  589.  
  590.     if (status == TINFL_STATUS_DONE || pngle->avail_out == 0) {
  591.       // Output buffer is full, or decompression is done, so write buffer to output file.
  592.       // XXX: This is the only chance to process the buffer.
  593.       uint8_t *read_ptr = pngle->lz_buf;
  594.       size_t n = TINFL_LZ_DICT_SIZE - (size_t)pngle->avail_out;
  595.  
  596.       // pngle_on_data() usually returns n, otherwise -1 on error
  597.       if (pngle_on_data(pngle, read_ptr, n) < 0) return -1;
  598.  
  599.       // XXX: tinfl_decompress always requires (next_out - lz_buf + avail_out) == TINFL_LZ_DICT_SIZE
  600.       pngle->next_out = pngle->lz_buf;
  601.       pngle->avail_out = TINFL_LZ_DICT_SIZE;
  602.     }
  603.  
  604.     consume = in_bytes;
  605.     break;
  606.  
  607.   case PNGLE_CHUNK_PLTE:
  608.     consume = 3;
  609.     if (len < consume) return 0;
  610.  
  611.     memcpy(pngle->palette + pngle->n_palettes * 3, buf, 3);
  612.  
  613.     debug_printf("[pngle] PLTE[%zd]: (%d, %d, %d)\n"
  614.       , pngle->n_palettes
  615.       , pngle->palette[pngle->n_palettes * 3 + 0]
  616.       , pngle->palette[pngle->n_palettes * 3 + 1]
  617.       , pngle->palette[pngle->n_palettes * 3 + 2]
  618.     );
  619.  
  620.     pngle->n_palettes++;
  621.  
  622.     break;
  623.  
  624.   case PNGLE_CHUNK_IEND:
  625.     consume = 0;
  626.     break;
  627.  
  628.   case PNGLE_CHUNK_tRNS:
  629.     switch (pngle->hdr.color_type) {
  630.     case 3: consume =     1; break;
  631.     case 0: consume = 2 * 1; break;
  632.     case 2: consume = 2 * 3; break;
  633.     default:
  634.       return PNGLE_ERROR("tRNS chunk is prohibited on the color type");
  635.     }
  636.     if (len < consume) return 0;
  637.  
  638.     memcpy(pngle->trans_palette + pngle->n_trans_palettes, buf, consume);
  639.  
  640.     pngle->n_trans_palettes++;
  641.  
  642.     break;
  643.  
  644.   case PNGLE_CHUNK_gAMA:
  645.     consume = 4;
  646.     if (len < consume) return 0;
  647.  
  648.     if (setup_gamma_table(pngle, read_uint32(buf)) < 0) return -1;
  649.  
  650.     break;
  651.  
  652.   default:
  653.     // unknown chunk
  654.     consume = len;
  655.  
  656.     debug_printf("[pngle] Unknown chunk; %zd bytes discarded\n", consume);
  657.     break;
  658.   }
  659.  
  660.   return consume;
  661. }
  662.  
  663. static int pngle_feed_internal(pngle_t *pngle, const uint8_t *buf, size_t len)
  664. {
  665.   if (!pngle) return -1;
  666.  
  667.   switch (pngle->state) {
  668.   case PNGLE_STATE_ERROR:
  669.     return -1;
  670.  
  671.   case PNGLE_STATE_EOF:
  672.     return len;
  673.  
  674.   case PNGLE_STATE_INITIAL:
  675.     // find PNG header
  676.     if (len < sizeof(png_sig)) return 0;
  677.  
  678.     if (memcmp(png_sig, buf, sizeof(png_sig))) return PNGLE_ERROR("Incorrect PNG signature");
  679.  
  680.     debug_printf("[pngle] PNG signature found\n");
  681.  
  682.     pngle->state = PNGLE_STATE_FIND_CHUNK_HEADER;
  683.     return sizeof(png_sig);
  684.  
  685.   case PNGLE_STATE_FIND_CHUNK_HEADER:
  686.     if (len < 8) return 0;
  687.  
  688.     pngle->chunk_remain = read_uint32(buf);
  689.     pngle->chunk_type = read_uint32(buf + 4);
  690.  
  691.     pngle->crc32 = mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)(buf + 4), 4);
  692.  
  693.     debug_printf("[pngle] Chunk '%.4s' len %u\n", buf + 4, pngle->chunk_remain);
  694.  
  695.     pngle->state = PNGLE_STATE_HANDLE_CHUNK;
  696.  
  697.     // initialize & sanity check
  698.     switch (pngle->chunk_type) {
  699.     case PNGLE_CHUNK_IHDR:
  700.       if (pngle->chunk_remain != 13) return PNGLE_ERROR("Invalid IHDR chunk size");
  701.       if (pngle->channels != 0) return PNGLE_ERROR("Multiple IHDR chunks are not allowed");
  702.       break;
  703.  
  704.     case PNGLE_CHUNK_IDAT:
  705.       if (pngle->chunk_remain <= 0) return PNGLE_ERROR("Invalid IDAT chunk size");
  706.       if (pngle->channels == 0) return PNGLE_ERROR("No IHDR chunk is found");
  707.       if (pngle->hdr.color_type == 3 && pngle->palette == NULL) return PNGLE_ERROR("No PLTE chunk is found");
  708.  
  709.       if (pngle->next_out == NULL) {
  710.         // Very first IDAT
  711.         pngle->next_out = pngle->lz_buf;
  712.         pngle->avail_out = TINFL_LZ_DICT_SIZE;
  713.       }
  714.       break;
  715.  
  716.     case PNGLE_CHUNK_PLTE:
  717.       if (pngle->chunk_remain <= 0) return PNGLE_ERROR("Invalid PLTE chunk size");
  718.       if (pngle->channels == 0) return PNGLE_ERROR("No IHDR chunk is found");
  719.       if (pngle->palette) return PNGLE_ERROR("Too many PLTE chunk");
  720.  
  721.       switch (pngle->hdr.color_type) {
  722.       case 3: // indexed color
  723.         break;
  724.       case 2: // truecolor
  725.       case 6: // truecolor + alpha
  726.         // suggested palettes
  727.         break;
  728.       default:
  729.         return PNGLE_ERROR("PLTE chunk is prohibited on the color type");
  730.       }
  731.  
  732.       if (pngle->chunk_remain % 3) return PNGLE_ERROR("Invalid PLTE chunk size");
  733.       if (pngle->chunk_remain / 3 > MIN(256, (1UL << pngle->hdr.depth))) return PNGLE_ERROR("Too many palettes in PLTE");
  734.       if ((pngle->palette = PNGLE_CALLOC(pngle->chunk_remain / 3, 3, "palette")) == NULL) return PNGLE_ERROR("Insufficient memory");
  735.       pngle->n_palettes = 0;
  736.       break;
  737.  
  738.     case PNGLE_CHUNK_IEND:
  739.       if (pngle->next_out == NULL) return PNGLE_ERROR("No IDAT chunk is found");
  740.       if (pngle->chunk_remain > 0) return PNGLE_ERROR("Invalid IEND chunk size");
  741.       break;
  742.  
  743.     case PNGLE_CHUNK_tRNS:
  744.       if (pngle->chunk_remain <= 0) return PNGLE_ERROR("Invalid tRNS chunk size");
  745.       if (pngle->channels == 0) return PNGLE_ERROR("No IHDR chunk is found");
  746.       if (pngle->trans_palette) return PNGLE_ERROR("Too many tRNS chunk");
  747.  
  748.       switch (pngle->hdr.color_type) {
  749.       case 3: // indexed color
  750.         if (pngle->chunk_remain > (1UL << pngle->hdr.depth)) return PNGLE_ERROR("Too many palettes in tRNS");
  751.         break;
  752.       case 0: // grayscale
  753.         if (pngle->chunk_remain != 2) return PNGLE_ERROR("Invalid tRNS chunk size");
  754.         break;
  755.       case 2: // truecolor
  756.         if (pngle->chunk_remain != 6) return PNGLE_ERROR("Invalid tRNS chunk size");
  757.         break;
  758.  
  759.       default:
  760.         return PNGLE_ERROR("tRNS chunk is prohibited on the color type");
  761.       }
  762.       if ((pngle->trans_palette = PNGLE_CALLOC(pngle->chunk_remain, 1, "trans palette")) == NULL) return PNGLE_ERROR("Insufficient memory");
  763.       pngle->n_trans_palettes = 0;
  764.       break;
  765.  
  766.     default:
  767.       break;
  768.     }
  769.  
  770.     return 8;
  771.  
  772.   case PNGLE_STATE_HANDLE_CHUNK:
  773.     len = MIN(len, pngle->chunk_remain);
  774.  
  775.     int consumed = pngle_handle_chunk(pngle, buf, len);
  776.  
  777.     if (consumed > 0) {
  778.       if (pngle->chunk_remain < (uint32_t)consumed) return PNGLE_ERROR("Chunk data has been consumed too much");
  779.  
  780.       pngle->chunk_remain -= consumed;
  781.       pngle->crc32 = mz_crc32(pngle->crc32, (const mz_uint8 *)buf, consumed);
  782.     }
  783.     if (pngle->chunk_remain <= 0) pngle->state = PNGLE_STATE_CRC;
  784.  
  785.     return consumed;
  786.  
  787.   case PNGLE_STATE_CRC:
  788.     if (len < 4) return 0;
  789.  
  790.     uint32_t crc32 = read_uint32(buf);
  791.  
  792.     if (crc32 != pngle->crc32) {
  793.       debug_printf("[pngle] CRC: %08x vs %08x => NG\n", crc32, (uint32_t)pngle->crc32);
  794.       return PNGLE_ERROR("CRC mismatch");
  795.     }
  796.  
  797.     debug_printf("[pngle] CRC: %08x vs %08x => OK\n", crc32, (uint32_t)pngle->crc32);
  798.     pngle->state = PNGLE_STATE_FIND_CHUNK_HEADER;
  799.  
  800.     // XXX:
  801.     if (pngle->chunk_type == PNGLE_CHUNK_IEND) {
  802.       pngle->state = PNGLE_STATE_EOF;
  803.       if (pngle->done_callback) pngle->done_callback(pngle);
  804.       debug_printf("[pngle] DONE\n");
  805.     }
  806.  
  807.     return 4;
  808.  
  809.   default:
  810.     break;
  811.   }
  812.  
  813.   return PNGLE_ERROR("Invalid state");
  814. }
  815.  
  816. int pngle_feed(pngle_t *pngle, const void *buf, size_t len)
  817. {
  818.   size_t pos = 0;
  819.   pngle_state_t last_state = pngle->state;
  820.  
  821.   while (pos < len) {
  822.     int r = pngle_feed_internal(pngle, (const uint8_t *)buf + pos, len - pos);
  823.     if (r < 0) return r; // error
  824.  
  825.     if (r == 0 && last_state == pngle->state) break;
  826.     last_state = pngle->state;
  827.  
  828.     pos += r;
  829.   }
  830.  
  831.   return pos;
  832. }
  833.  
  834. void pngle_set_display_gamma(pngle_t *pngle, double display_gamma)
  835. {
  836.   if (!pngle) return ;
  837. #ifndef PNGLE_NO_GAMMA_CORRECTION
  838.   pngle->display_gamma = display_gamma;
  839. #else
  840.   PNGLE_UNUSED(display_gamma);
  841. #endif
  842. }
  843.  
  844. void pngle_set_init_callback(pngle_t *pngle, pngle_init_callback_t callback)
  845. {
  846.   if (!pngle) return ;
  847.   pngle->init_callback = callback;
  848. }
  849.  
  850. void pngle_set_draw_callback(pngle_t *pngle, pngle_draw_callback_t callback)
  851. {
  852.   if (!pngle) return ;
  853.   pngle->draw_callback = callback;
  854. }
  855.  
  856. void pngle_set_done_callback(pngle_t *pngle, pngle_done_callback_t callback)
  857. {
  858.   if (!pngle) return ;
  859.   pngle->done_callback = callback;
  860. }
  861.  
  862. void pngle_set_user_data(pngle_t *pngle, void *user_data)
  863. {
  864.   if (!pngle) return ;
  865.   pngle->user_data = user_data;
  866. }
  867.  
  868. void *pngle_get_user_data(pngle_t *pngle)
  869. {
  870.   if (!pngle) return NULL;
  871.   return pngle->user_data;
  872. }
  873.  
  874. /* vim: set ts=4 sw=4 noexpandtab: */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement