Path: blob/master/thirdparty/basis_universal/encoder/pvpngreader.cpp
9902 views
// pngreader.cpp - Public Domain - see unlicense at bottom of file.1//2// Notes:3// This is ancient code from ~1995 ported to C++. It was originally written for a4// DOS app with very limited memory. It's not as fast as it should be, but it works.5// The low-level PNG reader class was written assuming the PNG file could not fit6// entirely into memory, which dictated how it was written/structured.7// It has been modified to use either zlib or miniz.8// It supports all PNG color types/bit depths/interlacing, however 16-bit/component9// images are converted to 8-bit.10// TRNS chunks are converted to alpha as needed.11// GAMA chunk is read, but not applied.1213#include "../transcoder/basisu.h"1415#define MINIZ_HEADER_FILE_ONLY16#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES17#include "basisu_miniz.h"1819#include "pvpngreader.h"2021#include <stdlib.h>22#include <stdio.h>23#include <math.h>24#include <string.h>25#include <vector>26#include <assert.h>2728#define PVPNG_IDAT_CRC_CHECKING (1)29#define PVPNG_ADLER32_CHECKING (1)3031namespace pv_png32{3334const uint32_t MIN_PNG_SIZE = 8 + 13 + 8 + 1 + 4 + 12;3536template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; }37template <typename S> inline S minimum(S a, S b) { return (a < b) ? a : b; }3839template <typename T> inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); }4041#define MAX_SUPPORTED_RES (32768)42#define FALSE (0)43#define TRUE (1)44#define PNG_MAX_ALLOC_BLOCKS (16)4546enum47{48PNG_DECERROR = -3,49PNG_ALLDONE = -5,50PNG_READPASTEOF = -11,51PNG_UNKNOWNTYPE = -16,52PNG_FILEREADERROR = -17,53PNG_NOTENOUGHMEM = -108,54PNG_BAD_CHUNK_CRC32 = -13000,55PNG_NO_IHDR = -13001,56PNG_BAD_WIDTH = -13002,57PNG_BAD_HEIGHT = -13003,58PNG_UNS_COMPRESSION = -13004,59PNG_UNS_FILTER = -13005,60PNG_UNS_ILACE = -13006,61PNG_UNS_COLOR_TYPE = -13007,62PNG_BAD_BIT_DEPTH = -13008,63PNG_BAD_CHUNK_SIZE = -13009,64PNG_UNS_CRITICAL_CHUNK = -13010,65PNG_BAD_TRNS_CHUNK = -13011,66PNG_BAD_PLTE_CHUNK = -13012,67PNG_UNS_RESOLUTION = -13013,68PNG_INVALID_DATA_STREAM = -13014,69PNG_MISSING_PALETTE = -13015,70PNG_UNS_PREDICTOR = -13016,71PNG_INCOMPLETE_IMAGE = -13017,72PNG_TOO_MUCH_DATA = -1301873};7475#define PNG_COLOR_TYPE_PAL_MASK (1)76#define PNG_COLOR_TYPE_COL_MASK (2)77#define PNG_COLOR_TYPE_ALP_MASK (4)7879#define PNG_INFLATE_SRC_BUF_SIZE (4096)8081struct ihdr_struct82{83uint32_t m_width;84uint32_t m_height;85uint8_t m_bit_depth;86uint8_t m_color_type;87uint8_t m_comp_type;88uint8_t m_filter_type;89uint8_t m_ilace_type;90};9192class png_file93{94public:95png_file() { }96virtual ~png_file() { }9798virtual bool resize(uint64_t new_size) = 0;99virtual uint64_t get_size() = 0;100virtual uint64_t tell() = 0;101virtual bool seek(uint64_t ofs) = 0;102virtual size_t write(const void* pBuf, size_t len) = 0;103virtual size_t read(void* pBuf, size_t len) = 0;104};105106class png_memory_file : public png_file107{108public:109std::vector<uint8_t> m_buf;110uint64_t m_ofs;111112png_memory_file() :113png_file(),114m_ofs(0)115{116}117118virtual ~png_memory_file()119{120}121122std::vector<uint8_t>& get_buf() { return m_buf; }123const std::vector<uint8_t>& get_buf() const { return m_buf; }124125void init()126{127m_ofs = 0;128m_buf.resize(0);129}130131virtual bool resize(uint64_t new_size)132{133if ((sizeof(size_t) == sizeof(uint32_t)) && (new_size >= 0x7FFFFFFF))134return false;135136m_buf.resize((size_t)new_size);137m_ofs = m_buf.size();138139return true;140}141142virtual uint64_t get_size()143{144return m_buf.size();145}146147virtual uint64_t tell()148{149return m_ofs;150}151152virtual bool seek(uint64_t ofs)153{154m_ofs = ofs;155return true;156}157158virtual size_t write(const void* pBuf, size_t len)159{160uint64_t new_size = m_ofs + len;161if (new_size > m_buf.size())162{163if ((sizeof(size_t) == sizeof(uint32_t)) && (new_size > 0x7FFFFFFFUL))164return 0;165m_buf.resize((size_t)new_size);166}167168memcpy(&m_buf[(size_t)m_ofs], pBuf, len);169m_ofs += len;170171return len;172}173174virtual size_t read(void* pBuf, size_t len)175{176if (m_ofs >= m_buf.size())177return 0;178179uint64_t max_bytes = minimum<uint64_t>(len, m_buf.size() - m_ofs);180memcpy(pBuf, &m_buf[(size_t)m_ofs], (size_t)max_bytes);181182m_ofs += max_bytes;183184return (size_t)max_bytes;185}186};187188class png_readonly_memory_file : public png_file189{190public:191const uint8_t* m_pBuf;192size_t m_buf_size;193uint64_t m_ofs;194195png_readonly_memory_file() :196png_file(),197m_pBuf(nullptr),198m_buf_size(0),199m_ofs(0)200{201}202203virtual ~png_readonly_memory_file()204{205}206207void init(const void *pBuf, size_t buf_size)208{209m_pBuf = static_cast<const uint8_t*>(pBuf);210m_buf_size = buf_size;211m_ofs = 0;212}213214virtual bool resize(uint64_t new_size)215{216(void)new_size;217assert(0);218return false;219}220221virtual uint64_t get_size()222{223return m_buf_size;224}225226virtual uint64_t tell()227{228return m_ofs;229}230231virtual bool seek(uint64_t ofs)232{233m_ofs = ofs;234return true;235}236237virtual size_t write(const void* pBuf, size_t len)238{239(void)pBuf;240(void)len;241assert(0);242return 0;243}244245virtual size_t read(void* pBuf, size_t len)246{247if (m_ofs >= m_buf_size)248return 0;249250uint64_t max_bytes = minimum<uint64_t>(len, m_buf_size - m_ofs);251memcpy(pBuf, &m_pBuf[(size_t)m_ofs], (size_t)max_bytes);252253m_ofs += max_bytes;254255return (size_t)max_bytes;256}257};258259#ifdef _MSC_VER260#define ftell64 _ftelli64261#define fseek64 _fseeki64262#else263#define ftell64 ftello264#define fseek64 fseeko265#endif266267class png_cfile : public png_file268{269public:270FILE* m_pFile;271272png_cfile() :273png_file(),274m_pFile(nullptr)275{276}277278virtual ~png_cfile()279{280close();281}282283bool init(const char *pFilename, const char *pMode)284{285close();286287m_pFile = nullptr;288289#ifdef _MSC_VER290fopen_s(&m_pFile, pFilename, pMode);291#else292m_pFile = fopen(pFilename, pMode);293#endif294295return m_pFile != nullptr;296}297298bool close()299{300bool status = true;301if (m_pFile)302{303if (fclose(m_pFile) == EOF)304status = false;305m_pFile = nullptr;306}307return status;308}309310virtual bool resize(uint64_t new_size)311{312if (new_size)313{314if (!seek(new_size - 1))315return false;316317int v = 0;318if (write(&v, 1) != 1)319return false;320}321else322{323if (!seek(0))324return false;325}326327return true;328}329330virtual uint64_t get_size()331{332int64_t cur_ofs = ftell64(m_pFile);333if (cur_ofs < 0)334return 0;335336if (fseek64(m_pFile, 0, SEEK_END) != 0)337return 0;338339const int64_t cur_size = ftell64(m_pFile);340if (cur_size < 0)341return 0;342343if (fseek64(m_pFile, cur_ofs, SEEK_SET) != 0)344return 0;345346return cur_size;347}348349virtual uint64_t tell()350{351int64_t cur_ofs = ftell64(m_pFile);352if (cur_ofs < 0)353return 0;354355return cur_ofs;356}357358virtual bool seek(uint64_t ofs)359{360return fseek64(m_pFile, ofs, SEEK_SET) == 0;361}362363virtual size_t write(const void* pBuf, size_t len)364{365return (size_t)fwrite(pBuf, 1, len, m_pFile);366}367368virtual size_t read(void* pBuf, size_t len)369{370return (size_t)fread(pBuf, 1, len, m_pFile);371}372};373374// This low-level helper class handles the actual decoding of PNG files.375class png_decoder376{377public:378png_decoder();379~png_decoder();380381// Scans the PNG file, but doesn't decode the IDAT data.382// Returns 0 on success, or an error code.383// 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.384int png_scan(png_file *pFile);385386// Decodes a single scanline of PNG image data.387// Returns a pointer to the scanline's pixel data and its size in bytes.388// This data is only minimally processed from the internal PNG pixel data.389// The caller must use the ihdr, trns_flag and values, and the palette to actually decode the pixel data.390//391// Possible returned pixel formats is somewhat complex due to the history of this code:392// 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)393// 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!)394// 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)395// 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)396//397// Returns 0 on success, a non-zero error code, or PNG_ALLDONE.398int png_decode(void** ppImg_ptr, uint32_t* pImg_len);399400// Starts decoding. Returns 0 on success, otherwise an error code.401int png_decode_start();402403// Deinitializes the decoder, freeing all allocations.404void png_decode_end();405406png_file* m_pFile;407408// Image's 24bpp palette - 3 bytes per entry409uint8_t m_plte_flag;410uint8_t m_img_pal[768];411412int m_img_supported_flag;413414ihdr_struct m_ihdr;415416uint8_t m_chunk_flag;417uint32_t m_chunk_size;418uint32_t m_chunk_left;419uint32_t m_chunk_crc32;420uint8_t m_chunk_name[4];421422uint8_t m_end_of_idat_chunks;423424void* m_pMalloc_blocks[PNG_MAX_ALLOC_BLOCKS];425426uint32_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)427uint32_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/component428429uint32_t m_dec_bytes_per_line; // bytes per line decoded from the PNG file (before 1/2/4 expansion), +1 for the filter byte430uint32_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 deinterlacing431uint32_t m_dst_bytes_per_line; // bytes per line returned to the caller (1-4 times width)432433int (*m_pProcess_func)(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi);434435uint8_t* m_pPre_line_buf;436uint8_t* m_pCur_line_buf;437uint8_t* m_pPro_line_buf;438439uint8_t m_bkgd_flag;440uint32_t m_bkgd_value[3];441442uint8_t m_gama_flag;443uint32_t m_gama_value;444445uint8_t m_trns_flag;446uint32_t m_trns_value[256];447448buminiz::mz_stream m_inflator;449450uint8_t inflate_src_buf[PNG_INFLATE_SRC_BUF_SIZE];451452uint32_t m_inflate_src_buf_ofs;453uint32_t m_inflate_src_buf_size;454uint32_t m_inflate_dst_buf_ofs;455456int m_inflate_eof_flag;457458uint8_t m_gamma_table[256];459460int m_pass_x_size;461int m_pass_y_left;462463int m_adam7_pass_num;464int m_adam7_pass_y;465int m_adam7_pass_size_x[7];466int m_adam7_pass_size_y[7];467468std::vector<uint8_t> m_adam7_image_buf;469470int m_adam7_decoded_flag;471472bool m_scanned_flag;473474int m_terminate_status;475476#define TEMP_BUF_SIZE (384)477uint8_t m_temp_buf[TEMP_BUF_SIZE * 4];478479void clear();480void uninitialize();481int terminate(int status);482void* png_malloc(uint32_t i);483void* png_calloc(uint32_t i);484int block_read(void* buf, uint32_t len);485int64_t block_read_dword();486int fetch_next_chunk_data(uint8_t* buf, int bytes);487int fetch_next_chunk_byte();488int fetch_next_chunk_word();489int64_t fetch_next_chunk_dword();490int fetch_next_chunk_init();491int unchunk_data(uint8_t* buf, uint32_t bytes, uint32_t* ptr_bytes_read);492inline void adam7_write_pixel_8(int x, int y, int c);493inline void adam7_write_pixel_16(int x, int y, int r, int g);494inline void adam7_write_pixel_24(int x, int y, int r, int g, int b);495inline void adam7_write_pixel_32(int x, int y, int r, int g, int b, int a);496void unpredict_sub(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);497void unpredict_up(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);498void unpredict_average(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);499inline uint8_t paeth_predictor(int a, int b, int c);500void unpredict_paeth(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp);501int adam7_pass_size(int size, int start, int step);502int decompress_line(uint32_t* bytes_decoded);503int find_iend_chunk();504void calc_gamma_table();505void create_grey_palette();506int read_signature();507int read_ihdr_chunk();508int read_bkgd_chunk();509int read_gama_chunk();510int read_trns_chunk();511int read_plte_chunk();512int find_idat_chunk();513};514515void png_decoder::uninitialize()516{517m_pFile = nullptr;518519for (int i = 0; i < PNG_MAX_ALLOC_BLOCKS; i++)520{521free(m_pMalloc_blocks[i]);522m_pMalloc_blocks[i] = nullptr;523}524525mz_inflateEnd(&m_inflator);526}527528int png_decoder::terminate(int status)529{530if (m_terminate_status == 0)531m_terminate_status = status;532533uninitialize();534return status;535}536537void* png_decoder::png_malloc(uint32_t len)538{539if (!len)540len++;541542void* p = malloc(len);543544if (!p)545return nullptr;546547int j;548for (j = 0; j < PNG_MAX_ALLOC_BLOCKS; j++)549if (!m_pMalloc_blocks[j])550break;551552if (j == PNG_MAX_ALLOC_BLOCKS)553return nullptr;554555m_pMalloc_blocks[j] = p;556557return p;558}559560void* png_decoder::png_calloc(uint32_t len)561{562void* p = png_malloc(len);563if (!p)564return nullptr;565566if (p)567memset(p, 0, len);568569return p;570}571572int png_decoder::block_read(void* buf, uint32_t len)573{574size_t bytes_read = m_pFile->read(buf, len);575if (bytes_read != len)576return terminate(PNG_READPASTEOF);577return 0;578}579580int64_t png_decoder::block_read_dword()581{582uint8_t buf[4];583584int status = block_read(buf, 4);585if (status != 0)586return status;587588uint32_t v = buf[3] + ((uint32_t)buf[2] << 8) + ((uint32_t)buf[1] << 16) + ((uint32_t)buf[0] << 24);589return (int64_t)v;590}591592int png_decoder::fetch_next_chunk_data(uint8_t* buf, int bytes)593{594if (!m_chunk_flag)595return 0;596597bytes = minimum<int>(bytes, m_chunk_left);598599int status = block_read(buf, bytes);600if (status != 0)601return status;602603#if PVPNG_IDAT_CRC_CHECKING604bool check_crc32 = true;605#else606const bool is_idat = (m_chunk_name[0] == 'I') && (m_chunk_name[1] == 'D') && (m_chunk_name[2] == 'A') && (m_chunk_name[3] == 'T');607bool check_crc32 = !is_idat;608#endif609610if (check_crc32)611m_chunk_crc32 = buminiz::mz_crc32(m_chunk_crc32, buf, bytes);612613if ((m_chunk_left -= bytes) == 0)614{615int64_t res = block_read_dword();616if (res < 0)617return (int)res;618619if (check_crc32)620{621if (m_chunk_crc32 != (uint32_t)res)622return terminate(PNG_BAD_CHUNK_CRC32);623}624625m_chunk_flag = FALSE;626}627628return bytes;629}630631int png_decoder::fetch_next_chunk_byte()632{633uint8_t buf[1];634635int status = fetch_next_chunk_data(buf, 1);636if (status < 0)637return status;638639if (status != 1)640return terminate(PNG_BAD_CHUNK_SIZE);641642return buf[0];643}644645int png_decoder::fetch_next_chunk_word()646{647uint8_t buf[2];648649int status = fetch_next_chunk_data(buf, 2);650if (status < 0)651return status;652653if (status != 2)654return terminate(PNG_BAD_CHUNK_SIZE);655656return buf[1] + ((uint32_t)buf[0] << 8);657}658659int64_t png_decoder::fetch_next_chunk_dword()660{661uint8_t buf[4];662663int status = fetch_next_chunk_data(buf, 4);664if (status < 0)665return status;666667if (status != 4)668terminate(PNG_BAD_CHUNK_SIZE);669670uint32_t v = buf[3] + ((uint32_t)buf[2] << 8) + ((uint32_t)buf[1] << 16) + ((uint32_t)buf[0] << 24);671return (int64_t)v;672}673674int png_decoder::fetch_next_chunk_init()675{676while (m_chunk_flag)677{678int status = fetch_next_chunk_data(m_temp_buf, TEMP_BUF_SIZE * 4);679if (status != 0)680return status;681}682683int64_t n = block_read_dword();684if (n < 0)685return (int)n;686687m_chunk_size = (uint32_t)n;688689m_chunk_flag = TRUE;690m_chunk_left = m_chunk_size + 4;691m_chunk_crc32 = 0;692693int status = fetch_next_chunk_data(m_chunk_name, 4);694if (status < 0)695return status;696697return 0;698}699700int png_decoder::unchunk_data(uint8_t* buf, uint32_t bytes, uint32_t* ptr_bytes_read)701{702uint32_t bytes_read = 0;703704if ((!bytes) || (m_end_of_idat_chunks))705{706*ptr_bytes_read = 0;707return TRUE;708}709710while (bytes_read != bytes)711{712if (!m_chunk_flag)713{714int res = fetch_next_chunk_init();715if (res < 0)716return res;717718if ((m_chunk_name[0] != 'I') ||719(m_chunk_name[1] != 'D') ||720(m_chunk_name[2] != 'A') ||721(m_chunk_name[3] != 'T'))722{723*ptr_bytes_read = bytes_read;724m_end_of_idat_chunks = TRUE;725return TRUE;726}727}728729int res = fetch_next_chunk_data(buf + bytes_read, bytes - bytes_read);730if (res < 0)731return res;732733bytes_read += (uint32_t)res;734}735736*ptr_bytes_read = bytes_read;737738return FALSE;739}740741inline void png_decoder::adam7_write_pixel_8(int x, int y, int c)742{743m_adam7_image_buf[x + y * m_dst_bytes_per_line] = (uint8_t)c;744}745746inline void png_decoder::adam7_write_pixel_16(int x, int y, int r, int g)747{748uint32_t ofs = x * 2 + y * m_dst_bytes_per_line;749m_adam7_image_buf[ofs + 0] = (uint8_t)r;750m_adam7_image_buf[ofs + 1] = (uint8_t)g;751}752753inline void png_decoder::adam7_write_pixel_24(int x, int y, int r, int g, int b)754{755uint32_t ofs = x * 3 + y * m_dst_bytes_per_line;756m_adam7_image_buf[ofs + 0] = (uint8_t)r;757m_adam7_image_buf[ofs + 1] = (uint8_t)g;758m_adam7_image_buf[ofs + 2] = (uint8_t)b;759}760761inline void png_decoder::adam7_write_pixel_32(int x, int y, int r, int g, int b, int a)762{763uint32_t ofs = x * 4 + y * m_dst_bytes_per_line;764m_adam7_image_buf[ofs + 0] = (uint8_t)r;765m_adam7_image_buf[ofs + 1] = (uint8_t)g;766m_adam7_image_buf[ofs + 2] = (uint8_t)b;767m_adam7_image_buf[ofs + 3] = (uint8_t)a;768}769770static void PixelDePack2(void* src, void* dst, int numbytes)771{772uint8_t* src8 = (uint8_t*)src;773uint8_t* dst8 = (uint8_t*)dst;774775while (numbytes)776{777uint8_t v = *src8++;778779for (uint32_t i = 0; i < 8; i++)780dst8[7 - i] = (v >> i) & 1;781782dst8 += 8;783numbytes--;784}785}786787static void PixelDePack16(void* src, void* dst, int numbytes)788{789uint8_t* src8 = (uint8_t*)src;790uint8_t* dst8 = (uint8_t*)dst;791792while (numbytes)793{794uint8_t v = *src8++;795796dst8[0] = (uint8_t)v >> 4;797dst8[1] = (uint8_t)v & 0xF;798dst8 += 2;799800numbytes--;801}802}803804static int unpack_grey_1(uint8_t* src, uint8_t* dst, int pixels, png_decoder *pwi)805{806(void)pwi;807PixelDePack2(src, dst, pixels >> 3);808809dst += (pixels & 0xFFF8);810811if ((pixels & 7) != 0)812{813uint8_t c = src[pixels >> 3];814815pixels &= 7;816817while (pixels--)818{819*dst++ = ((c & 128) >> 7);820821c <<= 1;822}823}824825return TRUE;826}827828static int unpack_grey_2(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)829{830(void)pwi;831int i = pixels;832uint8_t c;833834while (i >= 4)835{836c = *src++;837838*dst++ = (c >> 6);839*dst++ = (c >> 4) & 3;840*dst++ = (c >> 2) & 3;841*dst++ = (c) & 3;842843i -= 4;844}845846if (i)847{848c = *src;849850while (i--)851{852*dst++ = (c >> 6);853854c <<= 2;855}856}857858return TRUE;859}860861static int unpack_grey_4(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)862{863(void)pwi;864865PixelDePack16(src, dst, pixels >> 1);866867if (pixels & 1)868dst[pixels & 0xFFFE] = (src[pixels >> 1] >> 4);869870return TRUE;871}872873static int unpack_grey_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)874{875(void)src;876(void)dst;877(void)pixels;878(void)pwi;879return FALSE;880}881882static int unpack_grey_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)883{884(void)pwi;885while (pixels--)886{887*dst++ = *src++;888889src++;890}891892return TRUE;893}894895static int unpack_grey_16_2(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)896{897if (pwi->m_trns_flag)898{899while (pixels--)900{901uint32_t v = (src[0] << 8) + src[1];902src += 2;903904*dst++ = (uint8_t)(v >> 8);905*dst++ = (v == pwi->m_trns_value[0]) ? 0 : 255;906}907}908else909{910while (pixels--)911{912*dst++ = *src++;913*dst++ = 0xFF;914915src++;916}917}918919return TRUE;920}921922static int unpack_true_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)923{924if (pwi->m_trns_flag)925{926const uint32_t tr = pwi->m_trns_value[0];927const uint32_t tg = pwi->m_trns_value[1];928const uint32_t tb = pwi->m_trns_value[2];929930for (int i = 0; i < pixels; i++)931{932uint8_t r = src[i * 3 + 0];933uint8_t g = src[i * 3 + 1];934uint8_t b = src[i * 3 + 2];935936dst[i * 4 + 0] = r;937dst[i * 4 + 1] = g;938dst[i * 4 + 2] = b;939dst[i * 4 + 3] = ((r == tr) && (g == tg) && (b == tb)) ? 0 : 255;940}941}942else943{944for (int i = 0; i < pixels; i++)945{946dst[i * 4 + 0] = src[i * 3 + 0];947dst[i * 4 + 1] = src[i * 3 + 1];948dst[i * 4 + 2] = src[i * 3 + 2];949dst[i * 4 + 3] = 255;950}951}952953return TRUE;954}955956static int unpack_true_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)957{958if (pwi->m_trns_flag)959{960const uint32_t tr = pwi->m_trns_value[0];961const uint32_t tg = pwi->m_trns_value[1];962const uint32_t tb = pwi->m_trns_value[2];963964for (int i = 0; i < pixels; i++)965{966uint32_t r = (src[i * 6 + 0] << 8) + src[i * 6 + 1];967uint32_t g = (src[i * 6 + 2] << 8) + src[i * 6 + 3];968uint32_t b = (src[i * 6 + 4] << 8) + src[i * 6 + 5];969970dst[i * 4 + 0] = (uint8_t)(r >> 8);971dst[i * 4 + 1] = (uint8_t)(g >> 8);972dst[i * 4 + 2] = (uint8_t)(b >> 8);973dst[i * 4 + 3] = ((r == tr) && (g == tg) && (b == tb)) ? 0 : 255;974}975}976else977{978while (pixels--)979{980dst[0] = src[0];981dst[1] = src[2];982dst[2] = src[4];983dst[3] = 255;984985dst += 4;986src += 6;987}988}989990return TRUE;991}992993static int unpack_grey_alpha_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)994{995(void)pwi;996while (pixels--)997{998dst[0] = src[0];999dst[1] = src[1];1000dst += 2;1001src += 2;1002}10031004return TRUE;1005}10061007static int unpack_grey_alpha_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)1008{1009(void)pwi;1010while (pixels--)1011{1012dst[0] = src[0];1013dst[1] = src[2];1014dst += 2;1015src += 4;1016}10171018return TRUE;1019}10201021static int unpack_true_alpha_8(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)1022{1023(void)src;1024(void)dst;1025(void)pixels;1026(void)pwi;1027return FALSE;1028}10291030static int unpack_true_alpha_16(uint8_t* src, uint8_t* dst, int pixels, png_decoder* pwi)1031{1032(void)pwi;1033while (pixels--)1034{1035dst[0] = src[0];1036dst[1] = src[2];1037dst[2] = src[4];1038dst[3] = src[6];1039dst += 4;1040src += 8;1041}10421043return TRUE;1044}10451046void png_decoder::unpredict_sub(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)1047{1048(void)lst;1049if (bytes == (uint32_t)bpp)1050return;10511052cur += bpp;1053bytes -= bpp;10541055while (bytes--)1056{1057*cur += *(cur - bpp);1058cur++;1059}1060}10611062void png_decoder::unpredict_up(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)1063{1064(void)bpp;1065while (bytes--)1066*cur++ += *lst++;1067}10681069void png_decoder::unpredict_average(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)1070{1071int i;10721073for (i = 0; i < bpp; i++)1074*cur++ += (*lst++ >> 1);10751076if (bytes == (uint32_t)bpp)1077return;10781079bytes -= bpp;10801081while (bytes--)1082{1083*cur += ((*lst++ + *(cur - bpp)) >> 1);1084cur++;1085}1086}10871088inline uint8_t png_decoder::paeth_predictor(int a, int b, int c)1089{1090int p, pa, pb, pc;10911092/* a = left, b = above, c = upper left */10931094p = a + b - c;10951096pa = abs(p - a);1097pb = abs(p - b);1098pc = abs(p - c);10991100if ((pa <= pb) && (pa <= pc))1101return (uint8_t)a;1102else if (pb <= pc)1103return (uint8_t)b;1104else1105return (uint8_t)c;1106}11071108void png_decoder::unpredict_paeth(uint8_t* lst, uint8_t* cur, uint32_t bytes, int bpp)1109{1110int i;11111112for (i = 0; i < bpp; i++)1113*cur++ += paeth_predictor(0, *lst++, 0);11141115if (bytes == (uint32_t)bpp)1116return;11171118bytes -= bpp;11191120while (bytes--)1121{1122int p, a, b, c, pa, pb, pc;11231124a = *(cur - bpp);1125b = *lst;1126c = *(lst - bpp);11271128p = a + b - c;11291130pa = abs(p - a);1131pb = abs(p - b);1132pc = abs(p - c);11331134if ((pa <= pb) && (pa <= pc))1135*cur++ += (uint8_t)a;1136else if (pb <= pc)1137*cur++ += (uint8_t)b;1138else1139*cur++ += (uint8_t)c;11401141lst++;1142}1143}11441145int png_decoder::adam7_pass_size(int size, int start, int step)1146{1147if (size > start)1148return 1 + ((size - 1) - start) / step;1149else1150return 0;1151}11521153// TRUE if no more data, negative on error, FALSE if OK1154int png_decoder::decompress_line(uint32_t* bytes_decoded)1155{1156int status;1157uint32_t temp, src_bytes_left, dst_bytes_left;11581159m_inflate_dst_buf_ofs = 0;11601161for (; ; )1162{1163if (m_inflate_src_buf_ofs == PNG_INFLATE_SRC_BUF_SIZE)1164{1165int res = unchunk_data(inflate_src_buf, PNG_INFLATE_SRC_BUF_SIZE, &temp);1166if (res < 0)1167return res;1168m_inflate_eof_flag = res;11691170m_inflate_src_buf_size = temp;11711172m_inflate_src_buf_ofs = 0;1173}11741175for (; ; )1176{1177src_bytes_left = m_inflate_src_buf_size - m_inflate_src_buf_ofs;1178dst_bytes_left = m_dec_bytes_per_line - m_inflate_dst_buf_ofs;11791180m_inflator.next_in = inflate_src_buf + m_inflate_src_buf_ofs;1181m_inflator.avail_in = src_bytes_left;11821183m_inflator.next_out = m_pCur_line_buf + m_inflate_dst_buf_ofs;1184m_inflator.avail_out = dst_bytes_left;11851186status = buminiz::mz_inflate2(&m_inflator, buminiz::MZ_NO_FLUSH, PVPNG_ADLER32_CHECKING);11871188const uint32_t src_bytes_consumed = src_bytes_left - m_inflator.avail_in;1189const uint32_t dst_bytes_written = dst_bytes_left - m_inflator.avail_out;11901191m_inflate_src_buf_ofs += src_bytes_consumed;1192m_inflate_dst_buf_ofs += dst_bytes_written;11931194if (status != buminiz::MZ_OK)1195{1196if (status != buminiz::MZ_STREAM_END)1197return terminate(PNG_INVALID_DATA_STREAM);11981199if (bytes_decoded)1200*bytes_decoded = m_inflate_dst_buf_ofs;12011202return TRUE;1203}12041205if (m_inflate_dst_buf_ofs == m_dec_bytes_per_line)1206{1207if (bytes_decoded)1208*bytes_decoded = m_inflate_dst_buf_ofs;12091210return FALSE;1211}12121213if ((m_inflate_src_buf_ofs == m_inflate_src_buf_size) &&1214(m_inflate_eof_flag == FALSE))1215break;1216}1217}1218}12191220int png_decoder::find_iend_chunk()1221{1222uint32_t dummy;12231224while (!m_end_of_idat_chunks)1225{1226int res = unchunk_data(m_temp_buf, TEMP_BUF_SIZE * 4, &dummy);1227if (res < 0)1228return res;1229}12301231for (; ; )1232{1233if ((m_chunk_name[0] == 'I') &&1234(m_chunk_name[1] == 'E') &&1235(m_chunk_name[2] == 'N') &&1236(m_chunk_name[3] == 'D'))1237break;12381239int res = fetch_next_chunk_init();1240if (res < 0)1241return res;1242}12431244return 0;1245}12461247int png_decoder::png_decode(void** ppImg_ptr, uint32_t* pImg_len)1248{1249int status;1250uint8_t* decoded_line;1251uint32_t bytes_decoded;12521253if (m_adam7_decoded_flag)1254{1255if (m_pass_y_left == 0)1256return PNG_ALLDONE;12571258*ppImg_ptr = &m_adam7_image_buf[(m_ihdr.m_height - m_pass_y_left) * m_dst_bytes_per_line];1259*pImg_len = m_dst_bytes_per_line;12601261m_pass_y_left--;12621263return 0;1264}12651266if (m_pass_y_left == 0)1267{1268if (m_ihdr.m_ilace_type == 0)1269{1270status = find_iend_chunk();1271if (status < 0)1272return status;12731274return PNG_ALLDONE;1275}12761277for (; ; )1278{1279if (++m_adam7_pass_num == 7)1280{1281status = find_iend_chunk();1282if (status < 0)1283return status;12841285return PNG_ALLDONE;1286}12871288if (((m_pass_y_left = m_adam7_pass_size_y[m_adam7_pass_num]) != 0) &&1289((m_pass_x_size = m_adam7_pass_size_x[m_adam7_pass_num]) != 0))1290break;1291}12921293switch (m_adam7_pass_num)1294{1295case 0:1296case 1:1297case 3:1298case 5:1299m_adam7_pass_y = 0;1300break;1301case 2:1302m_adam7_pass_y = 4;1303break;1304case 4:1305m_adam7_pass_y = 2;1306break;1307case 6:1308m_adam7_pass_y = 1;1309break;1310}13111312switch (m_ihdr.m_color_type)1313{1314case PNG_COLOR_TYPE_GREYSCALE:1315case PNG_COLOR_TYPE_PALETTIZED:1316{1317m_src_bytes_per_line = (((uint32_t)m_pass_x_size * m_ihdr.m_bit_depth) + 7) / 8;1318break;1319}1320case PNG_COLOR_TYPE_TRUECOLOR:1321{1322m_src_bytes_per_line = ((uint32_t)m_pass_x_size * m_dec_bytes_per_pixel);1323break;1324}1325case PNG_COLOR_TYPE_GREYSCALE_ALPHA:1326{1327m_src_bytes_per_line = ((uint32_t)m_pass_x_size * m_dec_bytes_per_pixel);1328break;1329}1330case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:1331{1332m_src_bytes_per_line = ((uint32_t)m_pass_x_size * m_dec_bytes_per_pixel);1333break;1334}1335}13361337m_dec_bytes_per_line = m_src_bytes_per_line + 1;13381339memset(m_pPre_line_buf, 0, m_src_bytes_per_line);1340}13411342int res = decompress_line(&bytes_decoded);1343if (res < 0)1344return terminate(res);13451346if (res)1347{1348if (m_ihdr.m_ilace_type == 0)1349{1350if (m_pass_y_left != 1)1351return terminate(PNG_INCOMPLETE_IMAGE);1352}1353else1354{1355if ((m_pass_y_left != 1) && (m_adam7_pass_num != 6))1356return terminate(PNG_INCOMPLETE_IMAGE);1357}1358}13591360if (bytes_decoded != m_dec_bytes_per_line)1361return terminate(PNG_INCOMPLETE_IMAGE);13621363decoded_line = &m_pCur_line_buf[1];13641365switch (m_pCur_line_buf[0])1366{1367case 0:1368break;1369case 1:1370{1371unpredict_sub(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);1372break;1373}1374case 2:1375{1376unpredict_up(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);1377break;1378}1379case 3:1380{1381unpredict_average(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);1382break;1383}1384case 4:1385{1386unpredict_paeth(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line, m_dec_bytes_per_pixel);1387break;1388}1389default:1390return terminate(PNG_UNS_PREDICTOR);1391}13921393memmove(m_pPre_line_buf, m_pCur_line_buf + 1, m_src_bytes_per_line);13941395if (m_pProcess_func)1396{1397if ((*m_pProcess_func)(m_pCur_line_buf + 1, m_pPro_line_buf, m_pass_x_size, this))1398decoded_line = m_pPro_line_buf;1399}14001401if (m_ihdr.m_ilace_type == 0)1402{1403*ppImg_ptr = decoded_line;1404*pImg_len = m_dst_bytes_per_line;14051406if (--m_pass_y_left == 0)1407{1408res = decompress_line(&bytes_decoded);1409if (res < 0)1410return terminate(res);14111412if (res == FALSE)1413return terminate(PNG_TOO_MUCH_DATA);14141415if (bytes_decoded)1416return terminate(PNG_TOO_MUCH_DATA);1417}1418}1419else1420{1421int i, x_ofs = 0, y_ofs = 0, x_stp = 0;1422uint8_t* p = decoded_line;14231424switch (m_adam7_pass_num)1425{1426case 0: { x_ofs = 0; x_stp = 8; break; }1427case 1: { x_ofs = 4; x_stp = 8; break; }1428case 2: { x_ofs = 0; x_stp = 4; break; }1429case 3: { x_ofs = 2; x_stp = 4; break; }1430case 4: { x_ofs = 0; x_stp = 2; break; }1431case 5: { x_ofs = 1; x_stp = 2; break; }1432case 6: { x_ofs = 0; x_stp = 1; break; }1433}14341435y_ofs = m_adam7_pass_y;14361437assert(x_ofs < (int)m_ihdr.m_width);1438assert(y_ofs < (int)m_ihdr.m_height);14391440if (m_dst_bytes_per_pixel == 1)1441{1442for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp)1443adam7_write_pixel_8(x_ofs, y_ofs, *p++);1444}1445else if (m_dst_bytes_per_pixel == 2)1446{1447for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp, p += 2)1448adam7_write_pixel_16(x_ofs, y_ofs, p[0], p[1]);1449}1450else if (m_dst_bytes_per_pixel == 3)1451{1452for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp, p += 3)1453adam7_write_pixel_24(x_ofs, y_ofs, p[0], p[1], p[2]);1454}1455else if (m_dst_bytes_per_pixel == 4)1456{1457for (i = m_pass_x_size; i > 0; i--, x_ofs += x_stp, p += 4)1458adam7_write_pixel_32(x_ofs, y_ofs, p[0], p[1], p[2], p[3]);1459}1460else1461{1462assert(0);1463}14641465switch (m_adam7_pass_num)1466{1467case 0:1468case 1:1469case 2: { m_adam7_pass_y += 8; break; }1470case 3:1471case 4: { m_adam7_pass_y += 4; break; }1472case 5:1473case 6: { m_adam7_pass_y += 2; break; }1474}14751476if ((--m_pass_y_left == 0) && (m_adam7_pass_num == 6))1477{1478res = decompress_line(&bytes_decoded);1479if (res < 0)1480return terminate(res);14811482if (res == FALSE)1483return terminate(PNG_TOO_MUCH_DATA);14841485if (bytes_decoded)1486return terminate(PNG_TOO_MUCH_DATA);1487}1488}14891490return 0;1491}14921493void png_decoder::png_decode_end()1494{1495uninitialize();1496}14971498int png_decoder::png_decode_start()1499{1500int status;15011502if (m_img_supported_flag != TRUE)1503return terminate(m_img_supported_flag);15041505switch (m_ihdr.m_color_type)1506{1507case PNG_COLOR_TYPE_GREYSCALE:1508{1509if (m_ihdr.m_bit_depth == 16)1510{1511// 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.1512// So we expand to 8-bit Gray-Alpha and handle transparency during decoding.1513// We don't do this with all grayscale cases because that would require more code to deal with 1/2/4bpp expansion.1514m_dec_bytes_per_pixel = (m_ihdr.m_bit_depth + 7) / 8;1515m_dst_bytes_per_pixel = 2;15161517m_src_bytes_per_line = (((uint32_t)m_ihdr.m_width * m_ihdr.m_bit_depth) + 7) / 8;1518m_dst_bytes_per_line = 2 * m_ihdr.m_width;15191520m_pProcess_func = unpack_grey_16_2;1521}1522else1523{1524m_dec_bytes_per_pixel = (m_ihdr.m_bit_depth + 7) / 8;1525m_dst_bytes_per_pixel = 1;15261527m_src_bytes_per_line = (((uint32_t)m_ihdr.m_width * m_ihdr.m_bit_depth) + 7) / 8;1528m_dst_bytes_per_line = m_ihdr.m_width;15291530if (m_ihdr.m_bit_depth == 1)1531m_pProcess_func = unpack_grey_1;1532else if (m_ihdr.m_bit_depth == 2)1533m_pProcess_func = unpack_grey_2;1534else if (m_ihdr.m_bit_depth == 4)1535m_pProcess_func = unpack_grey_4;1536else1537m_pProcess_func = unpack_grey_8;1538}15391540break;1541}1542case PNG_COLOR_TYPE_PALETTIZED:1543{1544m_dec_bytes_per_pixel = (m_ihdr.m_bit_depth + 7) / 8;1545m_dst_bytes_per_pixel = 1;15461547m_src_bytes_per_line = (((uint32_t)m_ihdr.m_width * m_ihdr.m_bit_depth) + 7) / 8;1548m_dst_bytes_per_line = m_ihdr.m_width;15491550if (m_ihdr.m_bit_depth == 1)1551m_pProcess_func = unpack_grey_1;1552else if (m_ihdr.m_bit_depth == 2)1553m_pProcess_func = unpack_grey_2;1554else if (m_ihdr.m_bit_depth == 4)1555m_pProcess_func = unpack_grey_4;1556else if (m_ihdr.m_bit_depth == 8)1557m_pProcess_func = unpack_grey_8;1558else if (m_ihdr.m_bit_depth == 16)1559m_pProcess_func = unpack_grey_16;15601561break;1562}1563case PNG_COLOR_TYPE_TRUECOLOR:1564{1565// We always pass back alpha with transparency handling.1566m_dec_bytes_per_pixel = 3 * (m_ihdr.m_bit_depth / 8);1567m_dst_bytes_per_pixel = 4;15681569m_src_bytes_per_line = ((uint32_t)m_ihdr.m_width * m_dec_bytes_per_pixel);1570m_dst_bytes_per_line = 4 * m_ihdr.m_width;15711572if (m_ihdr.m_bit_depth == 8)1573m_pProcess_func = unpack_true_8;1574else if (m_ihdr.m_bit_depth == 16)1575m_pProcess_func = unpack_true_16;15761577break;1578}1579case PNG_COLOR_TYPE_GREYSCALE_ALPHA:1580{1581m_dec_bytes_per_pixel = 2 * (m_ihdr.m_bit_depth / 8);1582m_dst_bytes_per_pixel = 2;15831584m_src_bytes_per_line = ((uint32_t)m_ihdr.m_width * m_dec_bytes_per_pixel);1585m_dst_bytes_per_line = m_ihdr.m_width * 2;15861587if (m_ihdr.m_bit_depth == 8)1588m_pProcess_func = unpack_grey_alpha_8;1589else if (m_ihdr.m_bit_depth == 16)1590m_pProcess_func = unpack_grey_alpha_16;15911592break;1593}1594case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:1595{1596m_dec_bytes_per_pixel = 4 * (m_ihdr.m_bit_depth / 8);1597m_dst_bytes_per_pixel = 4;15981599m_src_bytes_per_line = ((uint32_t)m_ihdr.m_width * m_dec_bytes_per_pixel);1600m_dst_bytes_per_line = 4 * m_ihdr.m_width;16011602if (m_ihdr.m_bit_depth == 8)1603m_pProcess_func = unpack_true_alpha_8;1604else1605m_pProcess_func = unpack_true_alpha_16;16061607break;1608}1609}16101611m_dec_bytes_per_line = m_src_bytes_per_line + 1;16121613m_pPre_line_buf = (uint8_t*)png_calloc(m_src_bytes_per_line);1614m_pCur_line_buf = (uint8_t*)png_calloc(m_dec_bytes_per_line);1615m_pPro_line_buf = (uint8_t*)png_calloc(m_dst_bytes_per_line);16161617if (!m_pPre_line_buf || !m_pCur_line_buf || !m_pPro_line_buf)1618return terminate(PNG_NOTENOUGHMEM);16191620m_inflate_src_buf_ofs = PNG_INFLATE_SRC_BUF_SIZE;16211622int res = mz_inflateInit(&m_inflator);1623if (res != 0)1624return terminate(PNG_DECERROR);16251626if (m_ihdr.m_ilace_type == 1)1627{1628//int i;1629//uint32_t total_lines, lines_processed;16301631m_adam7_pass_size_x[0] = adam7_pass_size(m_ihdr.m_width, 0, 8);1632m_adam7_pass_size_x[1] = adam7_pass_size(m_ihdr.m_width, 4, 8);1633m_adam7_pass_size_x[2] = adam7_pass_size(m_ihdr.m_width, 0, 4);1634m_adam7_pass_size_x[3] = adam7_pass_size(m_ihdr.m_width, 2, 4);1635m_adam7_pass_size_x[4] = adam7_pass_size(m_ihdr.m_width, 0, 2);1636m_adam7_pass_size_x[5] = adam7_pass_size(m_ihdr.m_width, 1, 2);1637m_adam7_pass_size_x[6] = adam7_pass_size(m_ihdr.m_width, 0, 1);16381639m_adam7_pass_size_y[0] = adam7_pass_size(m_ihdr.m_height, 0, 8);1640m_adam7_pass_size_y[1] = adam7_pass_size(m_ihdr.m_height, 0, 8);1641m_adam7_pass_size_y[2] = adam7_pass_size(m_ihdr.m_height, 4, 8);1642m_adam7_pass_size_y[3] = adam7_pass_size(m_ihdr.m_height, 0, 4);1643m_adam7_pass_size_y[4] = adam7_pass_size(m_ihdr.m_height, 2, 4);1644m_adam7_pass_size_y[5] = adam7_pass_size(m_ihdr.m_height, 0, 2);1645m_adam7_pass_size_y[6] = adam7_pass_size(m_ihdr.m_height, 1, 2);16461647m_adam7_image_buf.resize(m_dst_bytes_per_line * m_ihdr.m_height);16481649m_adam7_pass_num = -1;16501651m_pass_y_left = 0;16521653#if 01654total_lines = lines_processed = 0;16551656for (i = 0; i < 7; i++)1657total_lines += m_adam7_pass_size_y[i];1658#endif16591660for (; ; )1661{1662void* dummy_ptr = nullptr;1663uint32_t dummy_len = 0;16641665status = png_decode(&dummy_ptr, &dummy_len);16661667if (status)1668{1669if (status == PNG_ALLDONE)1670break;1671else1672{1673uninitialize();16741675return status;1676}1677}16781679//lines_processed++;1680}16811682m_adam7_decoded_flag = TRUE;1683m_pass_y_left = m_ihdr.m_height;1684}1685else1686{1687m_pass_x_size = m_ihdr.m_width;1688m_pass_y_left = m_ihdr.m_height;1689}16901691return 0;1692}16931694void png_decoder::calc_gamma_table()1695{1696if (m_gama_value == 45000)1697{1698for (int i = 0; i < 256; i++)1699m_gamma_table[i] = (uint8_t)i;1700return;1701}17021703float gamma = (float)(m_gama_value) / 100000.0f;17041705gamma = 1.0f / (gamma * 2.2f);17061707for (int i = 0; i < 256; i++)1708{1709float temp = powf((float)(i) / 255.0f, gamma) * 255.0f;17101711int j = (int)(temp + .5f);17121713if (j < 0)1714j = 0;1715else if (j > 255)1716j = 255;17171718m_gamma_table[i] = (uint8_t)j;1719}1720}17211722void png_decoder::create_grey_palette()1723{1724int i, j;1725uint8_t* p = m_img_pal;17261727const int img_colors = minimum(256, 1 << m_ihdr.m_bit_depth);1728for (i = 0; i < img_colors; i++)1729{1730j = ((uint32_t)255 * (uint32_t)i) / (img_colors - 1);17311732*p++ = (uint8_t)j;1733*p++ = (uint8_t)j;1734*p++ = (uint8_t)j;1735}1736}17371738int png_decoder::read_signature()1739{1740if (m_pFile->read(m_temp_buf, 8) != 8)1741return terminate(PNG_UNKNOWNTYPE);17421743if ((m_temp_buf[0] != 137) ||1744(m_temp_buf[1] != 80) ||1745(m_temp_buf[2] != 78) ||1746(m_temp_buf[3] != 71) ||1747(m_temp_buf[4] != 13) ||1748(m_temp_buf[5] != 10) ||1749(m_temp_buf[6] != 26) ||1750(m_temp_buf[7] != 10))1751{1752return terminate(PNG_UNKNOWNTYPE);1753}17541755return 0;1756}17571758int png_decoder::read_ihdr_chunk()1759{1760int res = fetch_next_chunk_init();1761if (res < 0)1762return res;17631764if ((m_chunk_name[0] != 'I') || (m_chunk_name[1] != 'H') || (m_chunk_name[2] != 'D') || (m_chunk_name[3] != 'R') || (m_chunk_size != 13))1765return terminate(PNG_NO_IHDR);17661767int64_t v64 = fetch_next_chunk_dword();1768if (v64 < 0)1769return (int)v64;1770m_ihdr.m_width = (uint32_t)v64;17711772v64 = fetch_next_chunk_dword();1773if (v64 < 0)1774return (int)v64;1775m_ihdr.m_height = (uint32_t)v64;17761777if ((m_ihdr.m_width == 0) || (m_ihdr.m_width > MAX_SUPPORTED_RES))1778return terminate(PNG_BAD_WIDTH);17791780if ((m_ihdr.m_height == 0) || (m_ihdr.m_height > MAX_SUPPORTED_RES))1781return terminate(PNG_BAD_HEIGHT);17821783int v = fetch_next_chunk_byte();1784if (v < 0)1785return v;1786m_ihdr.m_bit_depth = (uint8_t)v;17871788v = fetch_next_chunk_byte();1789if (v < 0)1790return v;1791m_ihdr.m_color_type = (uint8_t)v;17921793v = fetch_next_chunk_byte();1794if (v < 0)1795return v;1796m_ihdr.m_comp_type = (uint8_t)v;17971798v = fetch_next_chunk_byte();1799if (v < 0)1800return v;1801m_ihdr.m_filter_type = (uint8_t)v;18021803v = fetch_next_chunk_byte();1804if (v < 0)1805return v;1806m_ihdr.m_ilace_type = (uint8_t)v;18071808if (m_ihdr.m_comp_type != 0)1809m_img_supported_flag = PNG_UNS_COMPRESSION;18101811if (m_ihdr.m_filter_type != 0)1812m_img_supported_flag = PNG_UNS_FILTER;18131814if (m_ihdr.m_ilace_type > 1)1815m_img_supported_flag = PNG_UNS_ILACE;18161817switch (m_ihdr.m_color_type)1818{1819case PNG_COLOR_TYPE_GREYSCALE:1820{1821switch (m_ihdr.m_bit_depth)1822{1823case 1:1824case 2:1825case 4:1826case 8:1827case 16:1828{1829break;1830}1831default:1832return terminate(PNG_BAD_BIT_DEPTH);1833}18341835break;1836}1837case PNG_COLOR_TYPE_PALETTIZED:1838{1839switch (m_ihdr.m_bit_depth)1840{1841case 1:1842case 2:1843case 4:1844case 8:1845{1846break;1847}1848default:1849return terminate(PNG_BAD_BIT_DEPTH);1850}18511852break;1853}1854case PNG_COLOR_TYPE_TRUECOLOR:1855case PNG_COLOR_TYPE_GREYSCALE_ALPHA:1856case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:1857{1858switch (m_ihdr.m_bit_depth)1859{1860case 8:1861case 16:1862{1863break;1864}1865default:1866return terminate(PNG_BAD_BIT_DEPTH);1867}18681869break;1870}1871default:1872return terminate(PNG_UNS_COLOR_TYPE);1873}18741875return 0;1876}18771878int png_decoder::read_bkgd_chunk()1879{1880m_bkgd_flag = TRUE;18811882if (m_ihdr.m_color_type == PNG_COLOR_TYPE_PALETTIZED)1883{1884int v = fetch_next_chunk_byte();1885if (v < 0)1886return v;1887m_bkgd_value[0] = v;1888}1889else if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE) || (m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE_ALPHA))1890{1891int v = fetch_next_chunk_word();1892if (v < 0)1893return v;1894m_bkgd_value[0] = v;1895}1896else if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_TRUECOLOR) || (m_ihdr.m_color_type == PNG_COLOR_TYPE_TRUECOLOR_ALPHA))1897{1898int v = fetch_next_chunk_word();1899if (v < 0)1900return v;1901m_bkgd_value[0] = v;19021903v = fetch_next_chunk_word();1904if (v < 0)1905return v;1906m_bkgd_value[1] = v;19071908v = fetch_next_chunk_word();1909if (v < 0)1910return v;1911m_bkgd_value[2] = v;1912}19131914return 0;1915}19161917int png_decoder::read_gama_chunk()1918{1919m_gama_flag = TRUE;19201921int64_t v = fetch_next_chunk_dword();1922if (v < 0)1923return (int)v;19241925m_gama_value = (uint32_t)v;19261927return 0;1928}19291930int png_decoder::read_trns_chunk()1931{1932int i;19331934m_trns_flag = TRUE;19351936if (m_ihdr.m_color_type == PNG_COLOR_TYPE_PALETTIZED)1937{1938for (i = 0; i < 256; i++)1939m_trns_value[i] = 255;19401941const uint32_t img_colors = 1 << m_ihdr.m_bit_depth;1942if (m_chunk_size > (uint32_t)img_colors)1943return terminate(PNG_BAD_TRNS_CHUNK);19441945for (i = 0; i < (int)m_chunk_size; i++)1946{1947int v = fetch_next_chunk_byte();1948if (v < 0)1949return v;1950m_trns_value[i] = v;1951}1952}1953else if (m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE)1954{1955int v = fetch_next_chunk_word();1956if (v < 0)1957return v;1958m_trns_value[0] = v;1959}1960else if (m_ihdr.m_color_type == PNG_COLOR_TYPE_TRUECOLOR)1961{1962int v = fetch_next_chunk_word();1963if (v < 0)1964return v;1965m_trns_value[0] = v;19661967v = fetch_next_chunk_word();1968if (v < 0)1969return v;1970m_trns_value[1] = v;19711972v = fetch_next_chunk_word();1973if (v < 0)1974return v;1975m_trns_value[2] = v;1976}1977else1978{1979return terminate(PNG_BAD_TRNS_CHUNK);1980}1981return 0;1982}19831984int png_decoder::read_plte_chunk()1985{1986int i, j;1987uint8_t* p;19881989if (m_plte_flag)1990return terminate(PNG_BAD_PLTE_CHUNK);19911992m_plte_flag = TRUE;19931994memset(m_img_pal, 0, 768);19951996if (m_chunk_size % 3)1997return terminate(PNG_BAD_PLTE_CHUNK);19981999j = m_chunk_size / 3;20002001const int img_colors = minimum(256, 1 << m_ihdr.m_bit_depth);2002if (j > img_colors)2003return terminate(PNG_BAD_PLTE_CHUNK);20042005if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE) ||2006(m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE_ALPHA))2007return terminate(PNG_BAD_PLTE_CHUNK);20082009p = m_img_pal;20102011for (i = 0; i < j; i++)2012{2013int v = fetch_next_chunk_byte();2014if (v < 0)2015return v;2016*p++ = (uint8_t)v;20172018v = fetch_next_chunk_byte();2019if (v < 0)2020return v;2021*p++ = (uint8_t)v;20222023v = fetch_next_chunk_byte();2024if (v < 0)2025return v;2026*p++ = (uint8_t)v;2027}20282029return 0;2030}20312032int png_decoder::find_idat_chunk()2033{2034for (; ; )2035{2036int res = fetch_next_chunk_init();2037if (res < 0)2038return res;20392040if (m_chunk_name[0] & 32) /* ancillary? */2041{2042if ((m_chunk_name[0] == 'b') && (m_chunk_name[1] == 'K') && (m_chunk_name[2] == 'G') && (m_chunk_name[3] == 'D'))2043{2044res = read_bkgd_chunk();2045if (res < 0)2046return res;2047}2048else if ((m_chunk_name[0] == 'g') && (m_chunk_name[1] == 'A') && (m_chunk_name[2] == 'M') && (m_chunk_name[3] == 'A'))2049{2050res = read_gama_chunk();2051if (res < 0)2052return res;2053}2054else if ((m_chunk_name[0] == 't') && (m_chunk_name[1] == 'R') && (m_chunk_name[2] == 'N') && (m_chunk_name[3] == 'S'))2055{2056res = read_trns_chunk();2057if (res < 0)2058return res;2059}2060}2061else2062{2063if ((m_chunk_name[0] == 'P') && (m_chunk_name[1] == 'L') && (m_chunk_name[2] == 'T') && (m_chunk_name[3] == 'E'))2064{2065res = read_plte_chunk();2066if (res < 0)2067return res;2068}2069else if ((m_chunk_name[0] == 'I') && (m_chunk_name[1] == 'D') && (m_chunk_name[2] == 'A') && (m_chunk_name[3] == 'T'))2070{2071break;2072}2073else2074{2075m_img_supported_flag = PNG_UNS_CRITICAL_CHUNK;2076}2077}2078}20792080return 0;2081}20822083png_decoder::png_decoder()2084{2085clear();2086}20872088png_decoder::~png_decoder()2089{2090uninitialize();2091}20922093void png_decoder::clear()2094{2095clear_obj(m_pMalloc_blocks);20962097m_pFile = nullptr;20982099clear_obj(m_img_pal);21002101m_img_supported_flag = FALSE;21022103m_adam7_image_buf.clear();21042105clear_obj(m_ihdr);21062107m_chunk_flag = FALSE;2108m_chunk_size = 0;2109m_chunk_left = 0;2110m_chunk_crc32 = 0;2111clear_obj(m_chunk_name);21122113m_end_of_idat_chunks = 0;21142115m_dec_bytes_per_pixel = 0;2116m_dst_bytes_per_pixel = 0;21172118m_dec_bytes_per_line = 0;2119m_src_bytes_per_line = 0;2120m_dst_bytes_per_line = 0;21212122m_pProcess_func = nullptr;21232124m_pPre_line_buf = nullptr;2125m_pCur_line_buf = nullptr;2126m_pPro_line_buf = nullptr;21272128m_bkgd_flag = FALSE;2129clear_obj(m_bkgd_value);21302131m_gama_flag = FALSE;2132m_gama_value = 0;21332134m_plte_flag = FALSE;21352136m_trns_flag = FALSE;2137clear_obj(m_trns_value);21382139clear_obj(m_inflator);21402141m_inflate_src_buf_ofs = 0;2142m_inflate_src_buf_size = 0;2143m_inflate_dst_buf_ofs = 0;21442145m_inflate_eof_flag = FALSE;21462147clear_obj(m_trns_value);21482149m_pass_x_size = 0;2150m_pass_y_left = 0;21512152m_adam7_pass_num = 0;2153m_adam7_pass_y = 0;2154clear_obj(m_adam7_pass_size_x);2155clear_obj(m_adam7_pass_size_y);21562157m_adam7_decoded_flag = FALSE;21582159m_scanned_flag = false;21602161m_terminate_status = 0;2162}21632164int png_decoder::png_scan(png_file *pFile)2165{2166m_pFile = pFile;21672168m_img_supported_flag = TRUE;2169m_terminate_status = 0;21702171int res = read_signature();2172if (res != 0)2173return res;21742175res = read_ihdr_chunk();2176if (res != 0)2177return res;21782179res = find_idat_chunk();2180if (res != 0)2181return res;21822183if (m_gama_flag)2184calc_gamma_table();21852186if (m_ihdr.m_color_type == PNG_COLOR_TYPE_PALETTIZED)2187{2188if (!m_plte_flag)2189return terminate(PNG_MISSING_PALETTE);2190}2191else if ((m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE) || (m_ihdr.m_color_type == PNG_COLOR_TYPE_GREYSCALE_ALPHA))2192{2193create_grey_palette();2194}21952196m_scanned_flag = true;21972198return 0;2199}22002201static inline uint8_t get_709_luma(uint32_t r, uint32_t g, uint32_t b)2202{2203return (uint8_t)((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);2204}22052206bool get_png_info(const void* pImage_buf, size_t buf_size, png_info &info)2207{2208memset(&info, 0, sizeof(info));22092210if ((!pImage_buf) || (buf_size < MIN_PNG_SIZE))2211return false;22122213png_readonly_memory_file mf;2214mf.init(pImage_buf, buf_size);22152216png_decoder dec;22172218int status = dec.png_scan(&mf);2219if ((status != 0) || (dec.m_img_supported_flag != TRUE))2220return false;22212222info.m_width = dec.m_ihdr.m_width;2223info.m_height = dec.m_ihdr.m_height;2224info.m_bit_depth = dec.m_ihdr.m_bit_depth;2225info.m_color_type = dec.m_ihdr.m_color_type;2226info.m_has_gamma = dec.m_gama_flag != 0;2227info.m_gamma_value = dec.m_gama_value;2228info.m_has_trns = dec.m_trns_flag != 0;22292230switch (dec.m_ihdr.m_color_type)2231{2232case PNG_COLOR_TYPE_GREYSCALE:2233info.m_num_chans = dec.m_trns_flag ? 2 : 1;2234break;2235case PNG_COLOR_TYPE_GREYSCALE_ALPHA:2236info.m_num_chans = 2;2237break;2238case PNG_COLOR_TYPE_PALETTIZED:2239case PNG_COLOR_TYPE_TRUECOLOR:2240info.m_num_chans = dec.m_trns_flag ? 4 : 3;2241break;2242case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:2243info.m_num_chans = 4;2244break;2245default:2246assert(0);2247break;2248}22492250return true;2251}22522253void* load_png(const void* pImage_buf, size_t buf_size, uint32_t desired_chans, uint32_t& width, uint32_t& height, uint32_t& num_chans)2254{2255width = 0;2256height = 0;2257num_chans = 0;22582259if ((!pImage_buf) || (buf_size < MIN_PNG_SIZE))2260{2261assert(0);2262return nullptr;2263}22642265if (desired_chans > 4)2266{2267assert(0);2268return nullptr;2269}22702271png_readonly_memory_file mf;2272mf.init(pImage_buf, buf_size);22732274png_decoder dec;22752276int status = dec.png_scan(&mf);2277if ((status != 0) || (dec.m_img_supported_flag != TRUE))2278return nullptr;22792280uint32_t colortype = dec.m_ihdr.m_color_type;2281switch (colortype)2282{2283case PNG_COLOR_TYPE_GREYSCALE:2284num_chans = dec.m_trns_flag ? 2 : 1;2285break;2286case PNG_COLOR_TYPE_GREYSCALE_ALPHA:2287num_chans = 2;2288break;2289case PNG_COLOR_TYPE_PALETTIZED:2290case PNG_COLOR_TYPE_TRUECOLOR:2291num_chans = dec.m_trns_flag ? 4 : 3;2292break;2293case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:2294num_chans = 4;2295break;2296default:2297assert(0);2298break;2299}23002301if (!desired_chans)2302desired_chans = num_chans;23032304#if 02305printf("lode_png: %ux%u bitdepth: %u colortype: %u trns: %u ilace: %u\n",2306dec.m_ihdr.m_width,2307dec.m_ihdr.m_height,2308dec.m_ihdr.m_bit_depth,2309dec.m_ihdr.m_color_type,2310dec.m_trns_flag,2311dec.m_ihdr.m_ilace_type);2312#endif23132314width = dec.m_ihdr.m_width;2315height = dec.m_ihdr.m_height;2316uint32_t bitdepth = dec.m_ihdr.m_bit_depth;2317uint32_t pitch = width * desired_chans;23182319uint64_t total_size = (uint64_t)pitch * height;2320if (total_size > 0x7FFFFFFFULL)2321return nullptr;23222323uint8_t* pBuf = (uint8_t*)malloc((size_t)total_size);2324if (!pBuf)2325return nullptr;23262327if (dec.png_decode_start() != 0)2328{2329free(pBuf);2330return nullptr;2331}23322333uint8_t* pDst = pBuf;23342335for (uint32_t y = 0; y < height; y++, pDst += pitch)2336{2337uint8_t* pLine;2338uint32_t line_bytes;2339if (dec.png_decode((void**)&pLine, &line_bytes) != 0)2340{2341free(pBuf);2342return nullptr;2343}23442345// This conversion matrix handles converting RGB->Luma, converting grayscale samples to 8-bit samples, converting palettized images, and PNG transparency.2346switch (colortype)2347{2348case PNG_COLOR_TYPE_GREYSCALE:2349{2350uint32_t trans_value = dec.m_trns_value[0];23512352switch (desired_chans)2353{2354case 1:2355if (bitdepth == 16)2356{2357assert(line_bytes == width * 2);23582359for (uint32_t i = 0; i < width; i++)2360pDst[i] = dec.m_img_pal[pLine[i * 2 + 0] * 3];2361}2362else if (bitdepth == 8)2363{2364assert(line_bytes == width);2365memcpy(pDst, pLine, pitch);2366}2367else2368{2369assert(line_bytes == width);2370for (uint32_t i = 0; i < width; i++)2371pDst[i] = dec.m_img_pal[pLine[i] * 3];2372}2373break;2374case 2:2375if (bitdepth == 16)2376{2377assert(line_bytes == width * 2);2378for (uint32_t i = 0; i < width; i++)2379{2380pDst[i * 2 + 0] = dec.m_img_pal[pLine[i * 2 + 0] * 3];2381pDst[i * 2 + 1] = pLine[i * 2 + 1];2382}2383}2384else if (dec.m_trns_flag)2385{2386assert(line_bytes == width);2387for (uint32_t i = 0; i < width; i++)2388{2389pDst[i * 2 + 0] = dec.m_img_pal[pLine[i] * 3];2390pDst[i * 2 + 1] = (pLine[i] == trans_value) ? 0 : 255;2391}2392}2393else2394{2395assert(line_bytes == width);2396for (uint32_t i = 0; i < width; i++)2397{2398pDst[i * 2 + 0] = dec.m_img_pal[pLine[i] * 3];2399pDst[i * 2 + 1] = 255;2400}2401}2402break;2403case 3:2404if (bitdepth == 16)2405{2406assert(line_bytes == width * 2);2407for (uint32_t i = 0; i < width; i++)2408{2409uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];2410pDst[i * 3 + 0] = c;2411pDst[i * 3 + 1] = c;2412pDst[i * 3 + 2] = c;2413}2414}2415else2416{2417assert(line_bytes == width);2418for (uint32_t i = 0; i < width; i++)2419{2420uint8_t c = dec.m_img_pal[pLine[i] * 3];2421pDst[i * 3 + 0] = c;2422pDst[i * 3 + 1] = c;2423pDst[i * 3 + 2] = c;2424}2425}2426break;2427case 4:2428if (bitdepth == 16)2429{2430assert(line_bytes == width * 2);2431for (uint32_t i = 0; i < width; i++)2432{2433uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];2434pDst[i * 4 + 0] = c;2435pDst[i * 4 + 1] = c;2436pDst[i * 4 + 2] = c;2437pDst[i * 4 + 3] = pLine[i * 2 + 1];2438}2439}2440else if (dec.m_trns_flag)2441{2442assert(line_bytes == width);2443for (uint32_t i = 0; i < width; i++)2444{2445uint8_t c = dec.m_img_pal[pLine[i] * 3];2446pDst[i * 4 + 0] = c;2447pDst[i * 4 + 1] = c;2448pDst[i * 4 + 2] = c;2449pDst[i * 4 + 3] = (pLine[i] == trans_value) ? 0 : 255;2450}2451}2452else2453{2454assert(line_bytes == width);2455for (uint32_t i = 0; i < width; i++)2456{2457uint8_t c = dec.m_img_pal[pLine[i] * 3];2458pDst[i * 4 + 0] = c;2459pDst[i * 4 + 1] = c;2460pDst[i * 4 + 2] = c;2461pDst[i * 4 + 3] = 255;2462}2463}2464break;2465}24662467break;2468}2469case PNG_COLOR_TYPE_GREYSCALE_ALPHA:2470{2471assert(line_bytes == width * 2);24722473switch (desired_chans)2474{2475case 1:2476for (uint32_t i = 0; i < width; i++)2477pDst[i] = dec.m_img_pal[pLine[i * 2 + 0] * 3];2478break;2479case 2:2480assert(line_bytes == pitch);2481if (bitdepth >= 8)2482memcpy(pDst, pLine, pitch);2483else2484{2485for (uint32_t i = 0; i < width; i++)2486{2487pDst[i * 2 + 0] = dec.m_img_pal[pLine[i * 2 + 0] * 3];2488pDst[i * 2 + 1] = pLine[i * 2 + 1];2489}2490}2491break;2492case 3:2493for (uint32_t i = 0; i < width; i++)2494{2495uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];2496pDst[i * 3 + 0] = c;2497pDst[i * 3 + 1] = c;2498pDst[i * 3 + 2] = c;2499}2500break;2501case 4:2502for (uint32_t i = 0; i < width; i++)2503{2504uint8_t c = dec.m_img_pal[pLine[i * 2 + 0] * 3];2505pDst[i * 4 + 0] = c;2506pDst[i * 4 + 1] = c;2507pDst[i * 4 + 2] = c;2508pDst[i * 4 + 3] = pLine[i * 2 + 1];2509}2510break;2511}25122513break;2514}2515case PNG_COLOR_TYPE_PALETTIZED:2516{2517assert(line_bytes == width);25182519switch (desired_chans)2520{2521case 1:2522for (uint32_t i = 0; i < width; i++)2523{2524const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];2525pDst[i] = get_709_luma(p[0], p[1], p[2]);2526}2527break;2528case 2:2529if (dec.m_trns_flag)2530{2531for (uint32_t i = 0; i < width; i++)2532{2533const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];2534pDst[i * 2 + 0] = get_709_luma(p[0], p[1], p[2]);2535pDst[i * 2 + 1] = (uint8_t)dec.m_trns_value[pLine[i]];2536}2537}2538else2539{2540for (uint32_t i = 0; i < width; i++)2541{2542const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];2543pDst[i * 2 + 0] = get_709_luma(p[0], p[1], p[2]);2544pDst[i * 2 + 1] = 255;2545}2546}2547break;2548case 3:2549for (uint32_t i = 0; i < width; i++)2550{2551const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];2552pDst[i * 3 + 0] = p[0];2553pDst[i * 3 + 1] = p[1];2554pDst[i * 3 + 2] = p[2];2555}2556break;2557case 4:2558if (dec.m_trns_flag)2559{2560for (uint32_t i = 0; i < width; i++)2561{2562const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];2563pDst[i * 4 + 0] = p[0];2564pDst[i * 4 + 1] = p[1];2565pDst[i * 4 + 2] = p[2];2566pDst[i * 4 + 3] = (uint8_t)dec.m_trns_value[pLine[i]];2567}2568}2569else2570{2571for (uint32_t i = 0; i < width; i++)2572{2573const uint8_t* p = &dec.m_img_pal[pLine[i] * 3];2574pDst[i * 4 + 0] = p[0];2575pDst[i * 4 + 1] = p[1];2576pDst[i * 4 + 2] = p[2];2577pDst[i * 4 + 3] = 255;2578}2579}2580break;2581}25822583break;2584}2585case PNG_COLOR_TYPE_TRUECOLOR:2586case PNG_COLOR_TYPE_TRUECOLOR_ALPHA:2587{2588assert(line_bytes == width * 4);25892590switch (desired_chans)2591{2592case 1:2593for (uint32_t i = 0; i < width; i++)2594{2595const uint8_t* p = &pLine[i * 4];2596pDst[i] = get_709_luma(p[0], p[1], p[2]);2597}2598break;2599case 2:2600for (uint32_t i = 0; i < width; i++)2601{2602const uint8_t* p = &pLine[i * 4];2603pDst[i * 2 + 0] = get_709_luma(p[0], p[1], p[2]);2604pDst[i * 2 + 1] = p[3];2605}2606break;2607case 3:2608for (uint32_t i = 0; i < width; i++)2609{2610const uint8_t* p = &pLine[i * 4];2611pDst[i * 3 + 0] = p[0];2612pDst[i * 3 + 1] = p[1];2613pDst[i * 3 + 2] = p[2];2614}2615break;2616case 4:2617memcpy(pDst, pLine, pitch);2618break;2619}26202621break;2622}2623default:2624assert(0);2625break;2626}26272628} // y26292630return pBuf;2631}26322633} // namespace pv_png26342635/*2636This is free and unencumbered software released into the public domain.26372638Anyone is free to copy, modify, publish, use, compile, sell, or2639distribute this software, either in source code form or as a compiled2640binary, for any purpose, commercial or non-commercial, and by any2641means.26422643In jurisdictions that recognize copyright laws, the author or authors2644of this software dedicate any and all copyright interest in the2645software to the public domain. We make this dedication for the benefit2646of the public at large and to the detriment of our heirs and2647successors. We intend this dedication to be an overt act of2648relinquishment in perpetuity of all present and future rights to this2649software under copyright law.26502651THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,2652EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF2653MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.2654IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR2655OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,2656ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR2657OTHER DEALINGS IN THE SOFTWARE.26582659For more information, please refer to <http://unlicense.org/>26602661Richard Geldreich, Jr.26621/20/20222663*/266426652666