diff --git a/libretro-common/formats/png/Makefile b/libretro-common/formats/png/Makefile index 19f80815d0..2c5b6a9fda 100644 --- a/libretro-common/formats/png/Makefile +++ b/libretro-common/formats/png/Makefile @@ -8,7 +8,7 @@ CFLAGS += -DHAVE_IMLIB2 LDFLAGS += -lImlib2 endif -SOURCES := rpng_nbio.c rpng_encode.c rpng_test.c ../../file/nbio/nbio_stdio.c +SOURCES := rpng.c rpng_nbio.c rpng_encode.c rpng_test.c ../../file/nbio/nbio_stdio.c OBJS := $(SOURCES:.c=.o) CFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB -DHAVE_ZLIB_DEFLATE -DRPNG_TEST -I../../include diff --git a/libretro-common/formats/png/rpng.c b/libretro-common/formats/png/rpng.c index 5126fee593..ada152fc1e 100644 --- a/libretro-common/formats/png/rpng.c +++ b/libretro-common/formats/png/rpng.c @@ -32,6 +32,8 @@ #include #endif +#include "rpng_common.h" + #undef GOTO_END_ERROR #define GOTO_END_ERROR() do { \ fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__); \ @@ -39,48 +41,7 @@ goto end; \ } while(0) -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -static const uint8_t png_magic[8] = { - 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a, -}; - -struct png_chunk -{ - uint32_t size; - char type[4]; - uint8_t *data; -}; - -struct png_ihdr -{ - uint32_t width; - uint32_t height; - uint8_t depth; - uint8_t color_type; - uint8_t compression; - uint8_t filter; - uint8_t interlace; -}; - -enum png_chunk_type -{ - PNG_CHUNK_NOOP = 0, - PNG_CHUNK_ERROR, - PNG_CHUNK_IHDR, - PNG_CHUNK_IDAT, - PNG_CHUNK_PLTE, - PNG_CHUNK_IEND -}; - -static uint32_t dword_be(const uint8_t *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0); -} - -static bool read_chunk_header(FILE *file, struct png_chunk *chunk) +static bool read_chunk_header_fio(FILE *file, struct png_chunk *chunk) { uint8_t dword[4] = {0}; @@ -95,36 +56,6 @@ static bool read_chunk_header(FILE *file, struct png_chunk *chunk) return true; } -struct -{ - const char *id; - enum png_chunk_type type; -} static const chunk_map[] = { - { "IHDR", PNG_CHUNK_IHDR }, - { "IDAT", PNG_CHUNK_IDAT }, - { "IEND", PNG_CHUNK_IEND }, - { "PLTE", PNG_CHUNK_PLTE }, -}; - -struct idat_buffer -{ - uint8_t *data; - size_t size; -}; - -static enum png_chunk_type png_chunk_type(const struct png_chunk *chunk) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(chunk_map); i++) - { - if (memcmp(chunk->type, chunk_map[i].id, 4) == 0) - return chunk_map[i].type; - } - - return PNG_CHUNK_NOOP; -} - static bool png_read_chunk(FILE *file, struct png_chunk *chunk) { free(chunk->data); @@ -240,136 +171,6 @@ end: return ret; } -// Paeth prediction filter. -static inline int paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p - a); - int pb = abs(p - b); - int pc = abs(p - c); - - if (pa <= pb && pa <= pc) - return a; - else if (pb <= pc) - return b; - return c; -} - -static inline void copy_line_rgb(uint32_t *data, - const uint8_t *decoded, unsigned width, unsigned bpp) -{ - unsigned i; - - bpp /= 8; - - for (i = 0; i < width; i++) - { - uint32_t r, g, b; - - r = *decoded; - decoded += bpp; - g = *decoded; - decoded += bpp; - b = *decoded; - decoded += bpp; - data[i] = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0); - } -} - -static inline void copy_line_rgba(uint32_t *data, - const uint8_t *decoded, unsigned width, unsigned bpp) -{ - unsigned i; - - bpp /= 8; - - for (i = 0; i < width; i++) - { - uint32_t r, g, b, a; - r = *decoded; - decoded += bpp; - g = *decoded; - decoded += bpp; - b = *decoded; - decoded += bpp; - a = *decoded; - decoded += bpp; - data[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0); - } -} - -static inline void copy_line_bw(uint32_t *data, - const uint8_t *decoded, unsigned width, unsigned depth) -{ - unsigned i, bit; - static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 }; - unsigned mul, mask; - - if (depth == 16) - { - for (i = 0; i < width; i++) - { - uint32_t val = decoded[i << 1]; - data[i] = (val * 0x010101) | (0xffu << 24); - } - return; - } - - mul = mul_table[depth]; - mask = (1 << depth) - 1; - bit = 0; - - for (i = 0; i < width; i++, bit += depth) - { - unsigned byte = bit >> 3; - unsigned val = decoded[byte] >> (8 - depth - (bit & 7)); - - val &= mask; - val *= mul; - data[i] = (val * 0x010101) | (0xffu << 24); - } -} - -static inline void copy_line_gray_alpha(uint32_t *data, - const uint8_t *decoded, unsigned width, - unsigned bpp) -{ - unsigned i; - - bpp /= 8; - - for (i = 0; i < width; i++) - { - uint32_t gray, alpha; - - gray = *decoded; - decoded += bpp; - alpha = *decoded; - decoded += bpp; - - data[i] = (gray * 0x010101) | (alpha << 24); - } -} - -static inline void copy_line_plt(uint32_t *data, - const uint8_t *decoded, unsigned width, - unsigned depth, const uint32_t *palette) -{ - unsigned i, bit; - unsigned mask = (1 << depth) - 1; - - bit = 0; - - for (i = 0; i < width; i++, bit += depth) - { - unsigned byte = bit >> 3; - unsigned val = decoded[byte] >> (8 - depth - (bit & 7)); - - val &= mask; - data[i] = palette[val]; - } -} - static void png_pass_geom(const struct png_ihdr *ihdr, unsigned width, unsigned height, unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size) @@ -607,7 +408,7 @@ static bool png_reverse_filter_adam7(uint32_t *data, return true; } -static bool png_append_idat(FILE *file, +static bool png_append_idat_fio(FILE *file, const struct png_chunk *chunk, struct idat_buffer *buf) { uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk->size); @@ -624,7 +425,7 @@ static bool png_append_idat(FILE *file, return true; } -static bool png_read_plte(FILE *file, uint32_t *buffer, unsigned entries) +static bool png_read_plte_fio(FILE *file, uint32_t *buffer, unsigned entries) { unsigned i; uint8_t buf[256 * 3]; @@ -691,7 +492,7 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, { struct png_chunk chunk = {0}; - if (!read_chunk_header(file, &chunk)) + if (!read_chunk_header_fio(file, &chunk)) GOTO_END_ERROR(); switch (png_chunk_type(&chunk)) @@ -722,7 +523,7 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, if (chunk.size % 3) GOTO_END_ERROR(); - if (!png_read_plte(file, palette, chunk.size / 3)) + if (!png_read_plte_fio(file, palette, chunk.size / 3)) GOTO_END_ERROR(); has_plte = true; @@ -732,7 +533,7 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, if (!has_ihdr || has_iend || (ihdr.color_type == 3 && !has_plte)) GOTO_END_ERROR(); - if (!png_append_idat(file, &chunk, &idat_buf)) + if (!png_append_idat_fio(file, &chunk, &idat_buf)) GOTO_END_ERROR(); has_idat = true; @@ -806,327 +607,3 @@ end: free(inflate_buf); return ret; } - -#ifdef HAVE_ZLIB_DEFLATE - -static void dword_write_be(uint8_t *buf, uint32_t val) -{ - *buf++ = (uint8_t)(val >> 24); - *buf++ = (uint8_t)(val >> 16); - *buf++ = (uint8_t)(val >> 8); - *buf++ = (uint8_t)(val >> 0); -} - -static bool png_write_crc(FILE *file, const uint8_t *data, size_t size) -{ - uint32_t crc = crc32(0, data, size); - uint8_t crc_raw[4] = {0}; - dword_write_be(crc_raw, crc); - return fwrite(crc_raw, 1, sizeof(crc_raw), file) == sizeof(crc_raw); -} - -static bool png_write_ihdr(FILE *file, const struct png_ihdr *ihdr) -{ - uint8_t ihdr_raw[] = { - '0', '0', '0', '0', /* Size */ - 'I', 'H', 'D', 'R', - - 0, 0, 0, 0, /* Width */ - 0, 0, 0, 0, /* Height */ - ihdr->depth, - ihdr->color_type, - ihdr->compression, - ihdr->filter, - ihdr->interlace, - }; - - dword_write_be(ihdr_raw + 0, sizeof(ihdr_raw) - 8); - dword_write_be(ihdr_raw + 8, ihdr->width); - dword_write_be(ihdr_raw + 12, ihdr->height); - if (fwrite(ihdr_raw, 1, sizeof(ihdr_raw), file) != sizeof(ihdr_raw)) - return false; - - if (!png_write_crc(file, ihdr_raw + sizeof(uint32_t), - sizeof(ihdr_raw) - sizeof(uint32_t))) - return false; - - return true; -} - -static bool png_write_idat(FILE *file, const uint8_t *data, size_t size) -{ - if (fwrite(data, 1, size, file) != size) - return false; - - if (!png_write_crc(file, data + sizeof(uint32_t), size - sizeof(uint32_t))) - return false; - - return true; -} - -static bool png_write_iend(FILE *file) -{ - const uint8_t data[] = { - 0, 0, 0, 0, - 'I', 'E', 'N', 'D', - }; - - if (fwrite(data, 1, sizeof(data), file) != sizeof(data)) - return false; - - if (!png_write_crc(file, data + sizeof(uint32_t), - sizeof(data) - sizeof(uint32_t))) - return false; - - return true; -} - -static void copy_argb_line(uint8_t *dst, const uint32_t *src, unsigned width) -{ - unsigned i; - for (i = 0; i < width; i++) - { - uint32_t col = src[i]; - *dst++ = (uint8_t)(col >> 16); - *dst++ = (uint8_t)(col >> 8); - *dst++ = (uint8_t)(col >> 0); - *dst++ = (uint8_t)(col >> 24); - } -} - -static void copy_bgr24_line(uint8_t *dst, const uint8_t *src, unsigned width) -{ - unsigned i; - for (i = 0; i < width; i++, dst += 3, src += 3) - { - dst[2] = src[0]; - dst[1] = src[1]; - dst[0] = src[2]; - } -} - -static unsigned count_sad(const uint8_t *data, size_t size) -{ - size_t i; - unsigned cnt = 0; - for (i = 0; i < size; i++) - cnt += abs((int8_t)data[i]); - return cnt; -} - -static unsigned filter_up(uint8_t *target, const uint8_t *line, - const uint8_t *prev, unsigned width, unsigned bpp) -{ - unsigned i; - width *= bpp; - for (i = 0; i < width; i++) - target[i] = line[i] - prev[i]; - - return count_sad(target, width); -} - -static unsigned filter_sub(uint8_t *target, const uint8_t *line, - unsigned width, unsigned bpp) -{ - unsigned i; - width *= bpp; - for (i = 0; i < bpp; i++) - target[i] = line[i]; - for (i = bpp; i < width; i++) - target[i] = line[i] - line[i - bpp]; - - return count_sad(target, width); -} - -static unsigned filter_avg(uint8_t *target, const uint8_t *line, - const uint8_t *prev, unsigned width, unsigned bpp) -{ - unsigned i; - width *= bpp; - for (i = 0; i < bpp; i++) - target[i] = line[i] - (prev[i] >> 1); - for (i = bpp; i < width; i++) - target[i] = line[i] - ((line[i - bpp] + prev[i]) >> 1); - - return count_sad(target, width); -} - -static unsigned filter_paeth(uint8_t *target, - const uint8_t *line, const uint8_t *prev, - unsigned width, unsigned bpp) -{ - unsigned i; - width *= bpp; - for (i = 0; i < bpp; i++) - target[i] = line[i] - paeth(0, prev[i], 0); - for (i = bpp; i < width; i++) - target[i] = line[i] - paeth(line[i - bpp], prev[i], prev[i - bpp]); - - return count_sad(target, width); -} - -static bool rpng_save_image(const char *path, - const uint8_t *data, - unsigned width, unsigned height, unsigned pitch, unsigned bpp) -{ - unsigned h; - bool ret = true; - struct png_ihdr ihdr = {0}; - - size_t encode_buf_size = 0; - uint8_t *encode_buf = NULL; - uint8_t *deflate_buf = NULL; - uint8_t *rgba_line = NULL; - uint8_t *up_filtered = NULL; - uint8_t *sub_filtered = NULL; - uint8_t *avg_filtered = NULL; - uint8_t *paeth_filtered = NULL; - uint8_t *prev_encoded = NULL; - uint8_t *encode_target = NULL; - - z_stream stream = {0}; - - FILE *file = fopen(path, "wb"); - if (!file) - GOTO_END_ERROR(); - - if (fwrite(png_magic, 1, sizeof(png_magic), file) != sizeof(png_magic)) - GOTO_END_ERROR(); - - ihdr.width = width; - ihdr.height = height; - ihdr.depth = 8; - ihdr.color_type = bpp == sizeof(uint32_t) ? 6 : 2; /* RGBA or RGB */ - if (!png_write_ihdr(file, &ihdr)) - GOTO_END_ERROR(); - - encode_buf_size = (width * bpp + 1) * height; - encode_buf = (uint8_t*)malloc(encode_buf_size); - if (!encode_buf) - GOTO_END_ERROR(); - - prev_encoded = (uint8_t*)calloc(1, width * bpp); - if (!prev_encoded) - GOTO_END_ERROR(); - - rgba_line = (uint8_t*)malloc(width * bpp); - up_filtered = (uint8_t*)malloc(width * bpp); - sub_filtered = (uint8_t*)malloc(width * bpp); - avg_filtered = (uint8_t*)malloc(width * bpp); - paeth_filtered = (uint8_t*)malloc(width * bpp); - if (!rgba_line || !up_filtered || !sub_filtered || !avg_filtered || !paeth_filtered) - GOTO_END_ERROR(); - - encode_target = encode_buf; - for (h = 0; h < height; - h++, encode_target += width * bpp, data += pitch) - { - if (bpp == sizeof(uint32_t)) - copy_argb_line(rgba_line, (const uint32_t*)data, width); - else - copy_bgr24_line(rgba_line, data, width); - - /* Try every filtering method, and choose the method - * which has most entries as zero. - * - * This is probably not very optimal, but it's very - * simple to implement. - */ - unsigned none_score = count_sad(rgba_line, width * bpp); - unsigned up_score = filter_up(up_filtered, rgba_line, prev_encoded, width, bpp); - unsigned sub_score = filter_sub(sub_filtered, rgba_line, width, bpp); - unsigned avg_score = filter_avg(avg_filtered, rgba_line, prev_encoded, width, bpp); - unsigned paeth_score = filter_paeth(paeth_filtered, rgba_line, prev_encoded, width, bpp); - - uint8_t filter = 0; - unsigned min_sad = none_score; - const uint8_t *chosen_filtered = rgba_line; - - if (sub_score < min_sad) - { - filter = 1; - chosen_filtered = sub_filtered; - min_sad = sub_score; - } - - if (up_score < min_sad) - { - filter = 2; - chosen_filtered = up_filtered; - min_sad = up_score; - } - - if (avg_score < min_sad) - { - filter = 3; - chosen_filtered = avg_filtered; - min_sad = avg_score; - } - - if (paeth_score < min_sad) - { - filter = 4; - chosen_filtered = paeth_filtered; - min_sad = paeth_score; - } - - *encode_target++ = filter; - memcpy(encode_target, chosen_filtered, width * bpp); - - memcpy(prev_encoded, rgba_line, width * bpp); - } - - deflate_buf = (uint8_t*)malloc(encode_buf_size * 2); /* Just to be sure. */ - if (!deflate_buf) - GOTO_END_ERROR(); - - stream.next_in = encode_buf; - stream.avail_in = encode_buf_size; - stream.next_out = deflate_buf + 8; - stream.avail_out = encode_buf_size * 2; - - deflateInit(&stream, 9); - if (deflate(&stream, Z_FINISH) != Z_STREAM_END) - { - deflateEnd(&stream); - GOTO_END_ERROR(); - } - deflateEnd(&stream); - - memcpy(deflate_buf + 4, "IDAT", 4); - dword_write_be(deflate_buf + 0, stream.total_out); - if (!png_write_idat(file, deflate_buf, stream.total_out + 8)) - GOTO_END_ERROR(); - - if (!png_write_iend(file)) - GOTO_END_ERROR(); - -end: - if (file) - fclose(file); - free(encode_buf); - free(deflate_buf); - free(rgba_line); - free(prev_encoded); - free(up_filtered); - free(sub_filtered); - free(avg_filtered); - free(paeth_filtered); - return ret; -} - -bool rpng_save_image_argb(const char *path, const uint32_t *data, - unsigned width, unsigned height, unsigned pitch) -{ - return rpng_save_image(path, (const uint8_t*)data, - width, height, pitch, sizeof(uint32_t)); -} - -bool rpng_save_image_bgr24(const char *path, const uint8_t *data, - unsigned width, unsigned height, unsigned pitch) -{ - return rpng_save_image(path, (const uint8_t*)data, - width, height, pitch, 3); -} - -#endif diff --git a/libretro-common/formats/png/rpng_common.h b/libretro-common/formats/png/rpng_common.h index f0f5303793..80ade76ab9 100644 --- a/libretro-common/formats/png/rpng_common.h +++ b/libretro-common/formats/png/rpng_common.h @@ -25,6 +25,48 @@ #include +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +static const uint8_t png_magic[8] = { + 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a, +}; + +struct png_chunk +{ + uint32_t size; + char type[4]; + uint8_t *data; +}; + +struct png_ihdr +{ + uint32_t width; + uint32_t height; + uint8_t depth; + uint8_t color_type; + uint8_t compression; + uint8_t filter; + uint8_t interlace; +}; + +struct idat_buffer +{ + uint8_t *data; + size_t size; +}; + +enum png_chunk_type +{ + PNG_CHUNK_NOOP = 0, + PNG_CHUNK_ERROR, + PNG_CHUNK_IHDR, + PNG_CHUNK_IDAT, + PNG_CHUNK_PLTE, + PNG_CHUNK_IEND +}; + /* Paeth prediction filter. */ static INLINE int paeth(int a, int b, int c) { @@ -40,4 +82,147 @@ static INLINE int paeth(int a, int b, int c) return c; } +static INLINE uint32_t dword_be(const uint8_t *buf) +{ + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0); +} + +static INLINE enum png_chunk_type png_chunk_type(const struct png_chunk *chunk) +{ + unsigned i; + struct + { + const char *id; + enum png_chunk_type type; + } static const chunk_map[] = { + { "IHDR", PNG_CHUNK_IHDR }, + { "IDAT", PNG_CHUNK_IDAT }, + { "IEND", PNG_CHUNK_IEND }, + { "PLTE", PNG_CHUNK_PLTE }, + }; + + for (i = 0; i < ARRAY_SIZE(chunk_map); i++) + { + if (memcmp(chunk->type, chunk_map[i].id, 4) == 0) + return chunk_map[i].type; + } + + return PNG_CHUNK_NOOP; +} + +static INLINE void copy_line_rgb(uint32_t *data, + const uint8_t *decoded, unsigned width, unsigned bpp) +{ + unsigned i; + + bpp /= 8; + + for (i = 0; i < width; i++) + { + uint32_t r, g, b; + + r = *decoded; + decoded += bpp; + g = *decoded; + decoded += bpp; + b = *decoded; + decoded += bpp; + data[i] = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0); + } +} + +static INLINE void copy_line_rgba(uint32_t *data, + const uint8_t *decoded, unsigned width, unsigned bpp) +{ + unsigned i; + + bpp /= 8; + + for (i = 0; i < width; i++) + { + uint32_t r, g, b, a; + r = *decoded; + decoded += bpp; + g = *decoded; + decoded += bpp; + b = *decoded; + decoded += bpp; + a = *decoded; + decoded += bpp; + data[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0); + } +} + +static INLINE void copy_line_bw(uint32_t *data, + const uint8_t *decoded, unsigned width, unsigned depth) +{ + unsigned i, bit; + static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 }; + unsigned mul, mask; + + if (depth == 16) + { + for (i = 0; i < width; i++) + { + uint32_t val = decoded[i << 1]; + data[i] = (val * 0x010101) | (0xffu << 24); + } + return; + } + + mul = mul_table[depth]; + mask = (1 << depth) - 1; + bit = 0; + + for (i = 0; i < width; i++, bit += depth) + { + unsigned byte = bit >> 3; + unsigned val = decoded[byte] >> (8 - depth - (bit & 7)); + + val &= mask; + val *= mul; + data[i] = (val * 0x010101) | (0xffu << 24); + } +} + +static INLINE void copy_line_gray_alpha(uint32_t *data, + const uint8_t *decoded, unsigned width, + unsigned bpp) +{ + unsigned i; + + bpp /= 8; + + for (i = 0; i < width; i++) + { + uint32_t gray, alpha; + + gray = *decoded; + decoded += bpp; + alpha = *decoded; + decoded += bpp; + + data[i] = (gray * 0x010101) | (alpha << 24); + } +} + +static INLINE void copy_line_plt(uint32_t *data, + const uint8_t *decoded, unsigned width, + unsigned depth, const uint32_t *palette) +{ + unsigned i, bit; + unsigned mask = (1 << depth) - 1; + + bit = 0; + + for (i = 0; i < width; i++, bit += depth) + { + unsigned byte = bit >> 3; + unsigned val = decoded[byte] >> (8 - depth - (bit & 7)); + + val &= mask; + data[i] = palette[val]; + } +} + #endif diff --git a/libretro-common/formats/png/rpng_encode.c b/libretro-common/formats/png/rpng_encode.c index 1579d65ccd..4965716a8c 100644 --- a/libretro-common/formats/png/rpng_encode.c +++ b/libretro-common/formats/png/rpng_encode.c @@ -28,10 +28,6 @@ #include #include -#ifdef GEKKO -#include -#endif - #include "rpng_common.h" #undef GOTO_END_ERROR @@ -41,42 +37,6 @@ goto end; \ } while(0) -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -static const uint8_t png_magic[8] = { - 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a, -}; - -struct png_chunk -{ - uint32_t size; - char type[4]; - uint8_t *data; -}; - -struct png_ihdr -{ - uint32_t width; - uint32_t height; - uint8_t depth; - uint8_t color_type; - uint8_t compression; - uint8_t filter; - uint8_t interlace; -}; - -enum png_chunk_type -{ - PNG_CHUNK_NOOP = 0, - PNG_CHUNK_ERROR, - PNG_CHUNK_IHDR, - PNG_CHUNK_IDAT, - PNG_CHUNK_PLTE, - PNG_CHUNK_IEND -}; - #ifdef HAVE_ZLIB_DEFLATE static void dword_write_be(uint8_t *buf, uint32_t val) diff --git a/libretro-common/formats/png/rpng_nbio.c b/libretro-common/formats/png/rpng_nbio.c index 450ad248b9..f0e72d5698 100644 --- a/libretro-common/formats/png/rpng_nbio.c +++ b/libretro-common/formats/png/rpng_nbio.c @@ -47,43 +47,6 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif -static const uint8_t png_magic[8] = { - 0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a, -}; - -struct png_chunk -{ - uint32_t size; - char type[4]; - uint8_t *data; -}; - -struct png_ihdr -{ - uint32_t width; - uint32_t height; - uint8_t depth; - uint8_t color_type; - uint8_t compression; - uint8_t filter; - uint8_t interlace; -}; - -enum png_chunk_type -{ - PNG_CHUNK_NOOP = 0, - PNG_CHUNK_ERROR, - PNG_CHUNK_IHDR, - PNG_CHUNK_IDAT, - PNG_CHUNK_PLTE, - PNG_CHUNK_IEND -}; - -static uint32_t dword_be(const uint8_t *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0); -} - static bool read_chunk_header(uint8_t *buf, struct png_chunk *chunk) { unsigned i; @@ -104,36 +67,6 @@ static bool read_chunk_header(uint8_t *buf, struct png_chunk *chunk) return true; } -struct -{ - const char *id; - enum png_chunk_type type; -} static const chunk_map[] = { - { "IHDR", PNG_CHUNK_IHDR }, - { "IDAT", PNG_CHUNK_IDAT }, - { "IEND", PNG_CHUNK_IEND }, - { "PLTE", PNG_CHUNK_PLTE }, -}; - -struct idat_buffer -{ - uint8_t *data; - size_t size; -}; - -static enum png_chunk_type png_chunk_type(const struct png_chunk *chunk) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(chunk_map); i++) - { - if (memcmp(chunk->type, chunk_map[i].id, 4) == 0) - return chunk_map[i].type; - } - - return PNG_CHUNK_NOOP; -} - static bool png_parse_ihdr(uint8_t *buf, struct png_ihdr *ihdr) { @@ -217,121 +150,6 @@ end: return ret; } -static inline void copy_line_rgb(uint32_t *data, - const uint8_t *decoded, unsigned width, unsigned bpp) -{ - unsigned i; - - bpp /= 8; - - for (i = 0; i < width; i++) - { - uint32_t r, g, b; - - r = *decoded; - decoded += bpp; - g = *decoded; - decoded += bpp; - b = *decoded; - decoded += bpp; - data[i] = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0); - } -} - -static inline void copy_line_rgba(uint32_t *data, - const uint8_t *decoded, unsigned width, unsigned bpp) -{ - unsigned i; - - bpp /= 8; - - for (i = 0; i < width; i++) - { - uint32_t r, g, b, a; - r = *decoded; - decoded += bpp; - g = *decoded; - decoded += bpp; - b = *decoded; - decoded += bpp; - a = *decoded; - decoded += bpp; - data[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0); - } -} - -static inline void copy_line_bw(uint32_t *data, - const uint8_t *decoded, unsigned width, unsigned depth) -{ - unsigned i, bit; - static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 }; - unsigned mul, mask; - - if (depth == 16) - { - for (i = 0; i < width; i++) - { - uint32_t val = decoded[i << 1]; - data[i] = (val * 0x010101) | (0xffu << 24); - } - return; - } - - mul = mul_table[depth]; - mask = (1 << depth) - 1; - bit = 0; - - for (i = 0; i < width; i++, bit += depth) - { - unsigned byte = bit >> 3; - unsigned val = decoded[byte] >> (8 - depth - (bit & 7)); - - val &= mask; - val *= mul; - data[i] = (val * 0x010101) | (0xffu << 24); - } -} - -static inline void copy_line_gray_alpha(uint32_t *data, - const uint8_t *decoded, unsigned width, - unsigned bpp) -{ - unsigned i; - - bpp /= 8; - - for (i = 0; i < width; i++) - { - uint32_t gray, alpha; - - gray = *decoded; - decoded += bpp; - alpha = *decoded; - decoded += bpp; - - data[i] = (gray * 0x010101) | (alpha << 24); - } -} - -static inline void copy_line_plt(uint32_t *data, - const uint8_t *decoded, unsigned width, - unsigned depth, const uint32_t *palette) -{ - unsigned i, bit; - unsigned mask = (1 << depth) - 1; - - bit = 0; - - for (i = 0; i < width; i++, bit += depth) - { - unsigned byte = bit >> 3; - unsigned val = decoded[byte] >> (8 - depth - (bit & 7)); - - val &= mask; - data[i] = palette[val]; - } -} - static void png_pass_geom(const struct png_ihdr *ihdr, unsigned width, unsigned height, unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size) @@ -596,7 +414,7 @@ static bool png_read_plte_into_buf(uint32_t *buffer, unsigned entries) return true; } -bool rpng_load_image_argb_iterate(uint8_t *buf, +bool rpng_nbio_load_image_argb_iterate(uint8_t *buf, struct png_chunk *chunk, uint32_t *palette, struct png_ihdr *ihdr, struct idat_buffer *idat_buf, @@ -687,7 +505,7 @@ bool rpng_load_image_argb_iterate(uint8_t *buf, return true; } -bool rpng_load_image_argb_process(uint8_t *inflate_buf, +bool rpng_nbio_load_image_argb_process(uint8_t *inflate_buf, struct png_ihdr *ihdr, struct idat_buffer *idat_buf, uint32_t **data, uint32_t *palette, @@ -744,7 +562,7 @@ bool rpng_load_image_argb_process(uint8_t *inflate_buf, return true; } -bool rpng_load_image_argb(const char *path, uint32_t **data, +bool rpng_nbio_load_image_argb(const char *path, uint32_t **data, unsigned *width, unsigned *height) { size_t file_len; @@ -796,7 +614,7 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, if (!read_chunk_header(buff_data, &chunk)) GOTO_END_ERROR(); - if (!rpng_load_image_argb_iterate( + if (!rpng_nbio_load_image_argb_iterate( buff_data, &chunk, palette, &ihdr, &idat_buf, &has_ihdr, &has_idat, &has_iend, &has_plte, &increment)) @@ -814,7 +632,7 @@ bool rpng_load_image_argb(const char *path, uint32_t **data, if (!has_ihdr || !has_idat || !has_iend) GOTO_END_ERROR(); - rpng_load_image_argb_process(inflate_buf, + rpng_nbio_load_image_argb_process(inflate_buf, &ihdr, &idat_buf, data, palette, width, height);