From 66a35f28e63266970383d5e00185a0a63a465615 Mon Sep 17 00:00:00 2001 From: Tobi-D7 Date: Tue, 7 Mar 2023 18:09:48 +0100 Subject: [PATCH] FastColor/RemoveFPSCheat/LLVM-Style --- .vscode/settings.json | 11 +- cformat.sh | 7 + external/libnsbmp/source/libnsbmp.c | 2195 ++- external/source/fs.c | 481 +- external/source/lodepng.cpp | 6081 +++++--- include/rd7.hpp | 4 +- include/renderd7/Color.hpp | 2 +- include/renderd7/ResultDecoder.hpp | 44 +- include/renderd7/StealConsole.hpp | 1 - include/renderd7/external/fs.h | 16 +- include/renderd7/external/libnsbmp/libnsbmp.h | 161 +- include/renderd7/external/libnsbmp/log.h | 22 +- include/renderd7/external/lodepng.h | 1161 +- include/renderd7/external/stb_image.h | 12604 ++++++++-------- include/renderd7/external/stb_image_write.h | 2750 ++-- include/renderd7/external/stb_truetype.h | 7855 +++++----- source/Color.cpp | 34 +- source/FileSystem.cpp | 11 +- source/Image.cpp | 110 +- source/ResultDecoder.cpp | 6 +- source/renderd7.cpp | 16 +- tools/rd7cc/source/main.cpp | 13 +- 22 files changed, 18350 insertions(+), 15235 deletions(-) create mode 100755 cformat.sh diff --git a/.vscode/settings.json b/.vscode/settings.json index 6ca2c2f..cf3146d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -88,6 +88,15 @@ "xtree": "cpp", "xutility": "cpp", "queue": "cpp", - "semaphore": "cpp" + "semaphore": "cpp", + "hash_map": "cpp", + "set": "cpp", + "unordered_set": "cpp", + "source_location": "cpp", + "future": "cpp", + "cfenv": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "variant": "cpp" } } \ No newline at end of file diff --git a/cformat.sh b/cformat.sh new file mode 100755 index 0000000..0cd8c4d --- /dev/null +++ b/cformat.sh @@ -0,0 +1,7 @@ + +find . -type f \( -name '*.h' -o -name '*.hpp' -o -name '*.hh' -o -name '*.ino' -o -name '*.cpp' -o -name '*.c' -o -name '*.cxx' -o -name '*.inl' \) -and -not -path './build/*' -not -path './base/external/*' -not -path './DPP/*' | while read file; do + if [[ "$file" != *"json.hpp" ]]; then + echo "Formatting $file..." + clang-format -i --style=LLVM $file + fi +done \ No newline at end of file diff --git a/external/libnsbmp/source/libnsbmp.c b/external/libnsbmp/source/libnsbmp.c index ab286c0..662e14f 100644 --- a/external/libnsbmp/source/libnsbmp.c +++ b/external/libnsbmp/source/libnsbmp.c @@ -25,17 +25,17 @@ #include #include -#include -#include -#include #include +#include +#include +#include #include #include /* squashes unused variable compiler warnings */ -#define UNUSED(x) ((x)=(x)) +#define UNUSED(x) ((x) = (x)) /* BMP entry sizes */ #define BMP_FILE_HEADER_SIZE 14 @@ -47,320 +47,310 @@ #ifdef WE_NEED_INT8_READING_NOW static inline int8_t read_int8(uint8_t *data, unsigned int o) { - return (int8_t) data[o]; + return (int8_t)data[o]; } #endif static inline uint8_t read_uint8(uint8_t *data, unsigned int o) { - return (uint8_t) data[o]; + return (uint8_t)data[o]; } static inline int16_t read_int16(uint8_t *data, unsigned int o) { - return (int16_t) (data[o] | (data[o+1] << 8)); + return (int16_t)(data[o] | (data[o + 1] << 8)); } static inline uint16_t read_uint16(uint8_t *data, unsigned int o) { - return (uint16_t) (data[o] | (data[o+1] << 8)); + return (uint16_t)(data[o] | (data[o + 1] << 8)); } static inline int32_t read_int32(uint8_t *data, unsigned int o) { - return (int32_t) ((unsigned)data[o] | - ((unsigned)data[o+1] << 8) | - ((unsigned)data[o+2] << 16) | - ((unsigned)data[o+3] << 24)); + return (int32_t)((unsigned)data[o] | ((unsigned)data[o + 1] << 8) | + ((unsigned)data[o + 2] << 16) | + ((unsigned)data[o + 3] << 24)); } static inline uint32_t read_uint32(uint8_t *data, unsigned int o) { - return (uint32_t) ((unsigned)data[o] | - ((unsigned)data[o+1] << 8) | - ((unsigned)data[o+2] << 16) | - ((unsigned)data[o+3] << 24)); + return (uint32_t)((unsigned)data[o] | ((unsigned)data[o + 1] << 8) | + ((unsigned)data[o + 2] << 16) | + ((unsigned)data[o + 3] << 24)); } - /** * Parse the bitmap info header */ -static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) -{ - uint32_t header_size; - uint32_t i; - uint8_t j; - int32_t width, height; - uint8_t palette_size; - unsigned int flags = 0; +static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) { + uint32_t header_size; + uint32_t i; + uint8_t j; + int32_t width, height; + uint8_t palette_size; + unsigned int flags = 0; - /* must be at least enough data for a core header */ - if (bmp->buffer_size < (BMP_FILE_HEADER_SIZE + BITMAPCOREHEADER)) { - return BMP_INSUFFICIENT_DATA; - } + /* must be at least enough data for a core header */ + if (bmp->buffer_size < (BMP_FILE_HEADER_SIZE + BITMAPCOREHEADER)) { + return BMP_INSUFFICIENT_DATA; + } - header_size = read_uint32(data, 0); + header_size = read_uint32(data, 0); - /* ensure there is enough data for the declared header size*/ - if ((bmp->buffer_size - BMP_FILE_HEADER_SIZE) < header_size) { - return BMP_INSUFFICIENT_DATA; - } + /* ensure there is enough data for the declared header size*/ + if ((bmp->buffer_size - BMP_FILE_HEADER_SIZE) < header_size) { + return BMP_INSUFFICIENT_DATA; + } - /* a variety of different bitmap headers can follow, depending - * on the BMP variant. The header length field determines the type. - */ - if (header_size == BITMAPCOREHEADER) { - /* the following header is for os/2 and windows 2.x and consists of: - * - * +0 UINT32 size of this header (in bytes) - * +4 INT16 image width (in pixels) - * +6 INT16 image height (in pixels) - * +8 UINT16 number of colour planes (always 1) - * +10 UINT16 number of bits per pixel - */ - width = read_int16(data, 4); - height = read_int16(data, 6); - if ((width <= 0) || (height == 0)) - return BMP_DATA_ERROR; - if (height < 0) { - bmp->reversed = true; - height = -height; - } - /* ICOs only support 256*256 resolutions - * In the case of the ICO header, the height is actually the added - * height of XOR-Bitmap and AND-Bitmap (double the visible height) - * Technically we could remove this check and ICOs with bitmaps - * of any size could be processed; this is to conform to the spec. - */ - if (bmp->ico) { - if ((width > 256) || (height > 512)) { - return BMP_DATA_ERROR; - } else { - bmp->width = width; - bmp->height = height / 2; - } - } else { - bmp->width = width; - bmp->height = height; - } - if (read_uint16(data, 8) != 1) - return BMP_DATA_ERROR; - bmp->bpp = read_uint16(data, 10); - /** - * The bpp value should be in the range 1-32, but the only - * values considered legal are: - * RGB ENCODING: 1, 4, 8, 16, 24 and 32 - */ - if ((bmp->bpp != 1) && (bmp->bpp != 4) && - (bmp->bpp != 8) && - (bmp->bpp != 16) && - (bmp->bpp != 24) && - (bmp->bpp != 32)) - return BMP_DATA_ERROR; - if (bmp->bpp < 16) - bmp->colours = (1 << bmp->bpp); - palette_size = 3; - } else if (header_size < 40) { - return BMP_DATA_ERROR; - } else { - /* the following header is for windows 3.x and onwards. it is a - * minimum of 40 bytes and (as of Windows 95) a maximum of 108 bytes. - * - * +0 UINT32 size of this header (in bytes) - * +4 INT32 image width (in pixels) - * +8 INT32 image height (in pixels) - * +12 UINT16 number of colour planes (always 1) - * +14 UINT16 number of bits per pixel - * +16 UINT32 compression methods used - * +20 UINT32 size of bitmap (in bytes) - * +24 UINT32 horizontal resolution (in pixels per meter) - * +28 UINT32 vertical resolution (in pixels per meter) - * +32 UINT32 number of colours in the image - * +36 UINT32 number of important colours - * +40 UINT32 mask identifying bits of red component - * +44 UINT32 mask identifying bits of green component - * +48 UINT32 mask identifying bits of blue component - * +52 UINT32 mask identifying bits of alpha component - * +56 UINT32 color space type - * +60 UINT32 x coordinate of red endpoint - * +64 UINT32 y coordinate of red endpoint - * +68 UINT32 z coordinate of red endpoint - * +72 UINT32 x coordinate of green endpoint - * +76 UINT32 y coordinate of green endpoint - * +80 UINT32 z coordinate of green endpoint - * +84 UINT32 x coordinate of blue endpoint - * +88 UINT32 y coordinate of blue endpoint - * +92 UINT32 z coordinate of blue endpoint - * +96 UINT32 gamma red coordinate scale value - * +100 UINT32 gamma green coordinate scale value - * +104 UINT32 gamma blue coordinate scale value - */ - width = read_int32(data, 4); - height = read_int32(data, 8); - if ((width <= 0) || (height == 0)) - return BMP_DATA_ERROR; - if (height < 0) { - bmp->reversed = true; - if (height <= -INT32_MAX) { - height = INT32_MAX; - } else { - height = -height; - } - } - /* ICOs only support 256*256 resolutions - * In the case of the ICO header, the height is actually the added - * height of XOR-Bitmap and AND-Bitmap (double the visible height) - * Technically we could remove this check and ICOs with bitmaps - * of any size could be processed; this is to conform to the spec. - */ - if (bmp->ico) { - if ((width > 256) || (height > 512)) { - return BMP_DATA_ERROR; - } else { - bmp->width = width; - bmp->height = height / 2; - } - } else { - bmp->width = width; - bmp->height = height; - } - if (read_uint16(data, 12) != 1) - return BMP_DATA_ERROR; - bmp->bpp = read_uint16(data, 14); - if (bmp->bpp == 0) - bmp->bpp = 8; - bmp->encoding = read_uint32(data, 16); - /** - * The bpp value should be in the range 1-32, but the only - * values considered legal are: - * RGB ENCODING: 1, 4, 8, 16, 24 and 32 - * RLE4 ENCODING: 4 - * RLE8 ENCODING: 8 - * BITFIELD ENCODING: 16 and 32 - */ - switch (bmp->encoding) { - case BMP_ENCODING_RGB: - if ((bmp->bpp != 1) && (bmp->bpp != 4) && - (bmp->bpp != 8) && - (bmp->bpp != 16) && - (bmp->bpp != 24) && - (bmp->bpp != 32)) - return BMP_DATA_ERROR; - break; - case BMP_ENCODING_RLE8: - if (bmp->bpp != 8) - return BMP_DATA_ERROR; - break; - case BMP_ENCODING_RLE4: - if (bmp->bpp != 4) - return BMP_DATA_ERROR; - break; - case BMP_ENCODING_BITFIELDS: - if ((bmp->bpp != 16) && (bmp->bpp != 32)) - return BMP_DATA_ERROR; - break; - /* invalid encoding */ - default: - return BMP_DATA_ERROR; - break; - } - /* Bitfield encoding means we have red, green, blue, and alpha masks. - * Here we acquire the masks and determine the required bit shift to - * align them in our 24-bit color 8-bit alpha format. - */ - if (bmp->encoding == BMP_ENCODING_BITFIELDS) { - if (header_size == 40) { - header_size += 12; - if (bmp->buffer_size < (14 + header_size)) - return BMP_INSUFFICIENT_DATA; - for (i = 0; i < 3; i++) - bmp->mask[i] = read_uint32(data, 40 + (i << 2)); - } else { - if (header_size < 56) - return BMP_INSUFFICIENT_DATA; - for (i = 0; i < 4; i++) - bmp->mask[i] = read_uint32(data, 40 + (i << 2)); - } - for (i = 0; i < 4; i++) { - if (bmp->mask[i] == 0) - break; - for (j = 31; j > 0; j--) - if (bmp->mask[i] & ((unsigned)1 << j)) { - if ((j - 7) > 0) - bmp->mask[i] &= (unsigned)0xff << (j - 7); - else - bmp->mask[i] &= 0xff >> (-(j - 7)); - bmp->shift[i] = (i << 3) - (j - 7); - break; - } - } - } - bmp->colours = read_uint32(data, 32); - if (bmp->colours == 0 && bmp->bpp < 16) - bmp->colours = (1 << bmp->bpp); - palette_size = 4; - } - data += header_size; + /* a variety of different bitmap headers can follow, depending + * on the BMP variant. The header length field determines the type. + */ + if (header_size == BITMAPCOREHEADER) { + /* the following header is for os/2 and windows 2.x and consists of: + * + * +0 UINT32 size of this header (in bytes) + * +4 INT16 image width (in pixels) + * +6 INT16 image height (in pixels) + * +8 UINT16 number of colour planes (always 1) + * +10 UINT16 number of bits per pixel + */ + width = read_int16(data, 4); + height = read_int16(data, 6); + if ((width <= 0) || (height == 0)) + return BMP_DATA_ERROR; + if (height < 0) { + bmp->reversed = true; + height = -height; + } + /* ICOs only support 256*256 resolutions + * In the case of the ICO header, the height is actually the added + * height of XOR-Bitmap and AND-Bitmap (double the visible height) + * Technically we could remove this check and ICOs with bitmaps + * of any size could be processed; this is to conform to the spec. + */ + if (bmp->ico) { + if ((width > 256) || (height > 512)) { + return BMP_DATA_ERROR; + } else { + bmp->width = width; + bmp->height = height / 2; + } + } else { + bmp->width = width; + bmp->height = height; + } + if (read_uint16(data, 8) != 1) + return BMP_DATA_ERROR; + bmp->bpp = read_uint16(data, 10); + /** + * The bpp value should be in the range 1-32, but the only + * values considered legal are: + * RGB ENCODING: 1, 4, 8, 16, 24 and 32 + */ + if ((bmp->bpp != 1) && (bmp->bpp != 4) && (bmp->bpp != 8) && + (bmp->bpp != 16) && (bmp->bpp != 24) && (bmp->bpp != 32)) + return BMP_DATA_ERROR; + if (bmp->bpp < 16) + bmp->colours = (1 << bmp->bpp); + palette_size = 3; + } else if (header_size < 40) { + return BMP_DATA_ERROR; + } else { + /* the following header is for windows 3.x and onwards. it is a + * minimum of 40 bytes and (as of Windows 95) a maximum of 108 bytes. + * + * +0 UINT32 size of this header (in bytes) + * +4 INT32 image width (in pixels) + * +8 INT32 image height (in pixels) + * +12 UINT16 number of colour planes (always 1) + * +14 UINT16 number of bits per pixel + * +16 UINT32 compression methods used + * +20 UINT32 size of bitmap (in bytes) + * +24 UINT32 horizontal resolution (in pixels per meter) + * +28 UINT32 vertical resolution (in pixels per meter) + * +32 UINT32 number of colours in the image + * +36 UINT32 number of important colours + * +40 UINT32 mask identifying bits of red component + * +44 UINT32 mask identifying bits of green component + * +48 UINT32 mask identifying bits of blue component + * +52 UINT32 mask identifying bits of alpha component + * +56 UINT32 color space type + * +60 UINT32 x coordinate of red endpoint + * +64 UINT32 y coordinate of red endpoint + * +68 UINT32 z coordinate of red endpoint + * +72 UINT32 x coordinate of green endpoint + * +76 UINT32 y coordinate of green endpoint + * +80 UINT32 z coordinate of green endpoint + * +84 UINT32 x coordinate of blue endpoint + * +88 UINT32 y coordinate of blue endpoint + * +92 UINT32 z coordinate of blue endpoint + * +96 UINT32 gamma red coordinate scale value + * +100 UINT32 gamma green coordinate scale value + * +104 UINT32 gamma blue coordinate scale value + */ + width = read_int32(data, 4); + height = read_int32(data, 8); + if ((width <= 0) || (height == 0)) + return BMP_DATA_ERROR; + if (height < 0) { + bmp->reversed = true; + if (height <= -INT32_MAX) { + height = INT32_MAX; + } else { + height = -height; + } + } + /* ICOs only support 256*256 resolutions + * In the case of the ICO header, the height is actually the added + * height of XOR-Bitmap and AND-Bitmap (double the visible height) + * Technically we could remove this check and ICOs with bitmaps + * of any size could be processed; this is to conform to the spec. + */ + if (bmp->ico) { + if ((width > 256) || (height > 512)) { + return BMP_DATA_ERROR; + } else { + bmp->width = width; + bmp->height = height / 2; + } + } else { + bmp->width = width; + bmp->height = height; + } + if (read_uint16(data, 12) != 1) + return BMP_DATA_ERROR; + bmp->bpp = read_uint16(data, 14); + if (bmp->bpp == 0) + bmp->bpp = 8; + bmp->encoding = read_uint32(data, 16); + /** + * The bpp value should be in the range 1-32, but the only + * values considered legal are: + * RGB ENCODING: 1, 4, 8, 16, 24 and 32 + * RLE4 ENCODING: 4 + * RLE8 ENCODING: 8 + * BITFIELD ENCODING: 16 and 32 + */ + switch (bmp->encoding) { + case BMP_ENCODING_RGB: + if ((bmp->bpp != 1) && (bmp->bpp != 4) && (bmp->bpp != 8) && + (bmp->bpp != 16) && (bmp->bpp != 24) && (bmp->bpp != 32)) + return BMP_DATA_ERROR; + break; + case BMP_ENCODING_RLE8: + if (bmp->bpp != 8) + return BMP_DATA_ERROR; + break; + case BMP_ENCODING_RLE4: + if (bmp->bpp != 4) + return BMP_DATA_ERROR; + break; + case BMP_ENCODING_BITFIELDS: + if ((bmp->bpp != 16) && (bmp->bpp != 32)) + return BMP_DATA_ERROR; + break; + /* invalid encoding */ + default: + return BMP_DATA_ERROR; + break; + } + /* Bitfield encoding means we have red, green, blue, and alpha masks. + * Here we acquire the masks and determine the required bit shift to + * align them in our 24-bit color 8-bit alpha format. + */ + if (bmp->encoding == BMP_ENCODING_BITFIELDS) { + if (header_size == 40) { + header_size += 12; + if (bmp->buffer_size < (14 + header_size)) + return BMP_INSUFFICIENT_DATA; + for (i = 0; i < 3; i++) + bmp->mask[i] = read_uint32(data, 40 + (i << 2)); + } else { + if (header_size < 56) + return BMP_INSUFFICIENT_DATA; + for (i = 0; i < 4; i++) + bmp->mask[i] = read_uint32(data, 40 + (i << 2)); + } + for (i = 0; i < 4; i++) { + if (bmp->mask[i] == 0) + break; + for (j = 31; j > 0; j--) + if (bmp->mask[i] & ((unsigned)1 << j)) { + if ((j - 7) > 0) + bmp->mask[i] &= (unsigned)0xff << (j - 7); + else + bmp->mask[i] &= 0xff >> (-(j - 7)); + bmp->shift[i] = (i << 3) - (j - 7); + break; + } + } + } + bmp->colours = read_uint32(data, 32); + if (bmp->colours == 0 && bmp->bpp < 16) + bmp->colours = (1 << bmp->bpp); + palette_size = 4; + } + data += header_size; - /* if there's no alpha mask, flag the bmp opaque */ - if ((!bmp->ico) && (bmp->mask[3] == 0)) { - flags |= BMP_OPAQUE; - bmp->opaque = true; - } + /* if there's no alpha mask, flag the bmp opaque */ + if ((!bmp->ico) && (bmp->mask[3] == 0)) { + flags |= BMP_OPAQUE; + bmp->opaque = true; + } - /* we only have a palette for <16bpp */ - if (bmp->bpp < 16) { - /* we now have a series of palette entries of the format: - * - * +0 BYTE blue - * +1 BYTE green - * +2 BYTE red - * - * if the palette is from an OS/2 or Win2.x file then the entries - * are padded with an extra byte. - */ + /* we only have a palette for <16bpp */ + if (bmp->bpp < 16) { + /* we now have a series of palette entries of the format: + * + * +0 BYTE blue + * +1 BYTE green + * +2 BYTE red + * + * if the palette is from an OS/2 or Win2.x file then the entries + * are padded with an extra byte. + */ - /* boundary checking */ - if (bmp->buffer_size < (14 + header_size + ((uint64_t)4 * bmp->colours))) - return BMP_INSUFFICIENT_DATA; + /* boundary checking */ + if (bmp->buffer_size < (14 + header_size + ((uint64_t)4 * bmp->colours))) + return BMP_INSUFFICIENT_DATA; - /* create the colour table */ - bmp->colour_table = (uint32_t *)malloc(bmp->colours * 4); - if (!bmp->colour_table) - return BMP_INSUFFICIENT_MEMORY; - for (i = 0; i < bmp->colours; i++) { - uint32_t colour = data[2] | (data[1] << 8) | (data[0] << 16); - if (bmp->opaque) - colour |= ((uint32_t)0xff << 24); - data += palette_size; - bmp->colour_table[i] = read_uint32((uint8_t *)&colour,0); - } + /* create the colour table */ + bmp->colour_table = (uint32_t *)malloc(bmp->colours * 4); + if (!bmp->colour_table) + return BMP_INSUFFICIENT_MEMORY; + for (i = 0; i < bmp->colours; i++) { + uint32_t colour = data[2] | (data[1] << 8) | (data[0] << 16); + if (bmp->opaque) + colour |= ((uint32_t)0xff << 24); + data += palette_size; + bmp->colour_table[i] = read_uint32((uint8_t *)&colour, 0); + } - /* some bitmaps have a bad offset if there is a pallete, work - * round this by fixing up the data offset to after the palette - * but only if there is data following the palette as some - * bitmaps encode data in the palette! - */ - if ((bmp->bitmap_offset < (uint32_t)(data - bmp->bmp_data)) && - ((bmp->buffer_size - (data - bmp->bmp_data)) > 0)) { - bmp->bitmap_offset = data - bmp->bmp_data; - } - } + /* some bitmaps have a bad offset if there is a pallete, work + * round this by fixing up the data offset to after the palette + * but only if there is data following the palette as some + * bitmaps encode data in the palette! + */ + if ((bmp->bitmap_offset < (uint32_t)(data - bmp->bmp_data)) && + ((bmp->buffer_size - (data - bmp->bmp_data)) > 0)) { + bmp->bitmap_offset = data - bmp->bmp_data; + } + } - /* create our bitmap */ - flags |= BMP_NEW | BMP_CLEAR_MEMORY; - bmp->bitmap = bmp->bitmap_callbacks.bitmap_create(bmp->width, bmp->height, flags); - if (!bmp->bitmap) { - if (bmp->colour_table) - free(bmp->colour_table); - bmp->colour_table = NULL; - return BMP_INSUFFICIENT_MEMORY; - } - /* BMPs within ICOs don't have BMP file headers, so the image data should - * always be right after the colour table. - */ - if (bmp->ico) - bmp->bitmap_offset = (intptr_t)data - (intptr_t)bmp->bmp_data; - return BMP_OK; + /* create our bitmap */ + flags |= BMP_NEW | BMP_CLEAR_MEMORY; + bmp->bitmap = + bmp->bitmap_callbacks.bitmap_create(bmp->width, bmp->height, flags); + if (!bmp->bitmap) { + if (bmp->colour_table) + free(bmp->colour_table); + bmp->colour_table = NULL; + return BMP_INSUFFICIENT_MEMORY; + } + /* BMPs within ICOs don't have BMP file headers, so the image data should + * always be right after the colour table. + */ + if (bmp->ico) + bmp->bitmap_offset = (intptr_t)data - (intptr_t)bmp->bmp_data; + return BMP_OK; } - /** * Parse the bitmap file header * @@ -368,33 +358,31 @@ static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) * \param data The data for the file header * \return BMP_OK on success or error code on faliure */ -static bmp_result bmp_file_header_parse(bmp_image *bmp, uint8_t *data) -{ - /* standard 14-byte BMP file header is: - * - * +0 UINT16 File Type ('BM') - * +2 UINT32 Size of File (in bytes) - * +6 INT16 Reserved Field (1) - * +8 INT16 Reserved Field (2) - * +10 UINT32 Starting Position of Image Data (offset in bytes) - */ - if (bmp->buffer_size < BMP_FILE_HEADER_SIZE) - return BMP_INSUFFICIENT_DATA; +static bmp_result bmp_file_header_parse(bmp_image *bmp, uint8_t *data) { + /* standard 14-byte BMP file header is: + * + * +0 UINT16 File Type ('BM') + * +2 UINT32 Size of File (in bytes) + * +6 INT16 Reserved Field (1) + * +8 INT16 Reserved Field (2) + * +10 UINT32 Starting Position of Image Data (offset in bytes) + */ + if (bmp->buffer_size < BMP_FILE_HEADER_SIZE) + return BMP_INSUFFICIENT_DATA; - if ((data[0] != (uint8_t)'B') || (data[1] != (uint8_t)'M')) - return BMP_DATA_ERROR; + if ((data[0] != (uint8_t)'B') || (data[1] != (uint8_t)'M')) + return BMP_DATA_ERROR; - bmp->bitmap_offset = read_uint32(data, 10); + bmp->bitmap_offset = read_uint32(data, 10); - /* check the offset to data lies within the file */ - if (bmp->bitmap_offset >= bmp->buffer_size) { - return BMP_INSUFFICIENT_DATA; - } + /* check the offset to data lies within the file */ + if (bmp->bitmap_offset >= bmp->buffer_size) { + return BMP_INSUFFICIENT_DATA; + } - return BMP_OK; + return BMP_OK; } - /** * Allocates memory for the next BMP in an ICO collection * @@ -404,13 +392,12 @@ static bmp_result bmp_file_header_parse(bmp_image *bmp, uint8_t *data) * \param image a pointer to the ICO image to be initialised */ static bmp_result next_ico_image(ico_collection *ico, ico_image *image) { - bmp_create(&image->bmp, &ico->bitmap_callbacks); - image->next = ico->first; - ico->first = image; - return BMP_OK; + bmp_create(&image->bmp, &ico->bitmap_callbacks); + image->next = ico->first; + ico->first = image; + return BMP_OK; } - /** * Parse the icon file header * @@ -418,96 +405,94 @@ static bmp_result next_ico_image(ico_collection *ico, ico_image *image) { * \param data The header data to parse. * \return BMP_OK on successful parse else error code */ -static bmp_result ico_header_parse(ico_collection *ico, uint8_t *data) -{ - uint16_t count, i; - bmp_result result; - int area, max_area = 0; +static bmp_result ico_header_parse(ico_collection *ico, uint8_t *data) { + uint16_t count, i; + bmp_result result; + int area, max_area = 0; - /* 6-byte ICO file header is: - * - * +0 INT16 Reserved (should be 0) - * +2 UINT16 Type (1 for ICO, 2 for CUR) - * +4 UINT16 Number of BMPs to follow - */ - if (ico->buffer_size < ICO_FILE_HEADER_SIZE) - return BMP_INSUFFICIENT_DATA; - // if (read_int16(data, 2) != 0x0000) - // return BMP_DATA_ERROR; - if (read_uint16(data, 2) != 0x0001) - return BMP_DATA_ERROR; - count = read_uint16(data, 4); - if (count == 0) - return BMP_DATA_ERROR; - data += ICO_FILE_HEADER_SIZE; + /* 6-byte ICO file header is: + * + * +0 INT16 Reserved (should be 0) + * +2 UINT16 Type (1 for ICO, 2 for CUR) + * +4 UINT16 Number of BMPs to follow + */ + if (ico->buffer_size < ICO_FILE_HEADER_SIZE) + return BMP_INSUFFICIENT_DATA; + // if (read_int16(data, 2) != 0x0000) + // return BMP_DATA_ERROR; + if (read_uint16(data, 2) != 0x0001) + return BMP_DATA_ERROR; + count = read_uint16(data, 4); + if (count == 0) + return BMP_DATA_ERROR; + data += ICO_FILE_HEADER_SIZE; - /* check if we have enough data for the directory */ - if (ico->buffer_size < (uint32_t)(ICO_FILE_HEADER_SIZE + (ICO_DIR_ENTRY_SIZE * count))) - return BMP_INSUFFICIENT_DATA; + /* check if we have enough data for the directory */ + if (ico->buffer_size < + (uint32_t)(ICO_FILE_HEADER_SIZE + (ICO_DIR_ENTRY_SIZE * count))) + return BMP_INSUFFICIENT_DATA; - /* Decode the BMP files. - * - * 16-byte ICO directory entry is: - * - * +0 UINT8 Width (0 for 256 pixels) - * +1 UINT8 Height (0 for 256 pixels) - * +2 UINT8 Colour count (0 if more than 256 colours) - * +3 INT8 Reserved (should be 0, but may not be) - * +4 UINT16 Colour Planes (should be 0 or 1) - * +6 UINT16 Bits Per Pixel - * +8 UINT32 Size of BMP info header + bitmap data in bytes - * +12 UINT32 Offset (points to the BMP info header, not the bitmap data) - */ - for (i = 0; i < count; i++) { - ico_image *image; - image = calloc(1, sizeof(ico_image)); - if (!image) - return BMP_INSUFFICIENT_MEMORY; - result = next_ico_image(ico, image); - if (result != BMP_OK) - return result; - image->bmp.width = read_uint8(data, 0); - if (image->bmp.width == 0) - image->bmp.width = 256; - image->bmp.height = read_uint8(data, 1); - if (image->bmp.height == 0) - image->bmp.height = 256; - image->bmp.buffer_size = read_uint32(data, 8); - image->bmp.bmp_data = ico->ico_data + read_uint32(data, 12); - if (image->bmp.bmp_data + image->bmp.buffer_size > - ico->ico_data + ico->buffer_size) - return BMP_INSUFFICIENT_DATA; - image->bmp.ico = true; - data += ICO_DIR_ENTRY_SIZE; + /* Decode the BMP files. + * + * 16-byte ICO directory entry is: + * + * +0 UINT8 Width (0 for 256 pixels) + * +1 UINT8 Height (0 for 256 pixels) + * +2 UINT8 Colour count (0 if more than 256 colours) + * +3 INT8 Reserved (should be 0, but may not be) + * +4 UINT16 Colour Planes (should be 0 or 1) + * +6 UINT16 Bits Per Pixel + * +8 UINT32 Size of BMP info header + bitmap data in bytes + * +12 UINT32 Offset (points to the BMP info header, not the bitmap + *data) + */ + for (i = 0; i < count; i++) { + ico_image *image; + image = calloc(1, sizeof(ico_image)); + if (!image) + return BMP_INSUFFICIENT_MEMORY; + result = next_ico_image(ico, image); + if (result != BMP_OK) + return result; + image->bmp.width = read_uint8(data, 0); + if (image->bmp.width == 0) + image->bmp.width = 256; + image->bmp.height = read_uint8(data, 1); + if (image->bmp.height == 0) + image->bmp.height = 256; + image->bmp.buffer_size = read_uint32(data, 8); + image->bmp.bmp_data = ico->ico_data + read_uint32(data, 12); + if (image->bmp.bmp_data + image->bmp.buffer_size > + ico->ico_data + ico->buffer_size) + return BMP_INSUFFICIENT_DATA; + image->bmp.ico = true; + data += ICO_DIR_ENTRY_SIZE; - /* Ensure that the bitmap data resides in the buffer */ - if (image->bmp.bmp_data - ico->ico_data >= 0 && - (uint32_t)(image->bmp.bmp_data - - ico->ico_data) >= ico->buffer_size) - return BMP_DATA_ERROR; + /* Ensure that the bitmap data resides in the buffer */ + if (image->bmp.bmp_data - ico->ico_data >= 0 && + (uint32_t)(image->bmp.bmp_data - ico->ico_data) >= ico->buffer_size) + return BMP_DATA_ERROR; - /* Ensure that we have sufficient data to read the bitmap */ - if (image->bmp.buffer_size - ICO_DIR_ENTRY_SIZE >= - ico->buffer_size - (ico->ico_data - data)) - return BMP_INSUFFICIENT_DATA; + /* Ensure that we have sufficient data to read the bitmap */ + if (image->bmp.buffer_size - ICO_DIR_ENTRY_SIZE >= + ico->buffer_size - (ico->ico_data - data)) + return BMP_INSUFFICIENT_DATA; - result = bmp_info_header_parse(&image->bmp, - image->bmp.bmp_data); - if (result != BMP_OK) - return result; + result = bmp_info_header_parse(&image->bmp, image->bmp.bmp_data); + if (result != BMP_OK) + return result; - /* adjust the size based on the images available */ - area = image->bmp.width * image->bmp.height; - if (area > max_area) { - ico->width = image->bmp.width; - ico->height = image->bmp.height; - max_area = area; - } - } - return BMP_OK; + /* adjust the size based on the images available */ + area = image->bmp.width * image->bmp.height; + if (area > max_area) { + ico->width = image->bmp.width; + ico->height = image->bmp.height; + max_area = area; + } + } + return BMP_OK; } - /** * Decode BMP data stored in 32bpp colour. * @@ -518,78 +503,76 @@ static bmp_result ico_header_parse(ico_collection *ico, uint8_t *data) * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly; * in this case, the image may be partially viewable */ -static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes) -{ - uint8_t *top, *bottom, *end, *data; - uint32_t *scanline; - uint32_t x, y; - uint32_t swidth; - uint8_t i; - uint32_t word; +static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes) { + uint8_t *top, *bottom, *end, *data; + uint32_t *scanline; + uint32_t x, y; + uint32_t swidth; + uint8_t i; + uint32_t word; - assert(bmp->bpp == 32); + assert(bmp->bpp == 32); - data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); - if (!top) - return BMP_INSUFFICIENT_MEMORY; - bottom = top + (uint64_t)swidth * (bmp->height - 1); - end = data + bytes; - bmp->decoded = true; + data = *start; + swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); + if (!top) + return BMP_INSUFFICIENT_MEMORY; + bottom = top + (uint64_t)swidth * (bmp->height - 1); + end = data + bytes; + bmp->decoded = true; - /* Determine transparent index */ - if (bmp->limited_trans) { - if ((data + 4) > end) - return BMP_INSUFFICIENT_DATA; - if (bmp->encoding == BMP_ENCODING_BITFIELDS) - bmp->transparent_index = read_uint32(data, 0); - else - bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16); + /* Determine transparent index */ + if (bmp->limited_trans) { + if ((data + 4) > end) + return BMP_INSUFFICIENT_DATA; + if (bmp->encoding == BMP_ENCODING_BITFIELDS) + bmp->transparent_index = read_uint32(data, 0); + else + bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16); + } + + for (y = 0; y < bmp->height; y++) { + if ((data + (4 * bmp->width)) > end) + return BMP_INSUFFICIENT_DATA; + if (bmp->reversed) + scanline = (void *)(top + (y * swidth)); + else + scanline = (void *)(bottom - (y * swidth)); + if (bmp->encoding == BMP_ENCODING_BITFIELDS) { + for (x = 0; x < bmp->width; x++) { + word = read_uint32(data, 0); + for (i = 0; i < 4; i++) + if (bmp->shift[i] > 0) + scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]); + else + scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i])); + /* 32-bit BMPs have alpha masks, but sometimes they're not utilized */ + if (bmp->opaque) + scanline[x] |= ((unsigned)0xff << 24); + data += 4; + scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); + } + } else { + for (x = 0; x < bmp->width; x++) { + scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16); + if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) { + scanline[x] = bmp->trans_colour; } - - for (y = 0; y < bmp->height; y++) { - if ((data + (4 * bmp->width)) > end) - return BMP_INSUFFICIENT_DATA; - if (bmp->reversed) - scanline = (void *)(top + (y * swidth)); - else - scanline = (void *)(bottom - (y * swidth)); - if (bmp->encoding == BMP_ENCODING_BITFIELDS) { - for (x = 0; x < bmp->width; x++) { - word = read_uint32(data, 0); - for (i = 0; i < 4; i++) - if (bmp->shift[i] > 0) - scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]); - else - scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i])); - /* 32-bit BMPs have alpha masks, but sometimes they're not utilized */ - if (bmp->opaque) - scanline[x] |= ((unsigned)0xff << 24); - data += 4; - scanline[x] = read_uint32((uint8_t *)&scanline[x],0); - } - } else { - for (x = 0; x < bmp->width; x++) { - scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16); - if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) { - scanline[x] = bmp->trans_colour; - } - if (bmp->opaque) { - scanline[x] |= ((unsigned)0xff << 24); - } else { - scanline[x] |= (unsigned)data[3] << 24; - } - data += 4; - scanline[x] = read_uint32((uint8_t *)&scanline[x],0); - } - } + if (bmp->opaque) { + scanline[x] |= ((unsigned)0xff << 24); + } else { + scanline[x] |= (unsigned)data[3] << 24; } - *start = data; - return BMP_OK; + data += 4; + scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); + } + } + } + *start = data; + return BMP_OK; } - /** * Decode BMP data stored in 24bpp colour. * @@ -600,69 +583,67 @@ static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes) * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly; * in this case, the image may be partially viewable */ -static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes) -{ - uint8_t *top, *bottom, *end, *data; - uint32_t *scanline; - uint32_t x, y; - uint32_t swidth; - intptr_t addr; +static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes) { + uint8_t *top, *bottom, *end, *data; + uint32_t *scanline; + uint32_t x, y; + uint32_t swidth; + intptr_t addr; - assert(bmp->encoding == BMP_ENCODING_RGB); - assert(bmp->bpp == 24); + assert(bmp->encoding == BMP_ENCODING_RGB); + assert(bmp->bpp == 24); - data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); - if (!top) { - return BMP_INSUFFICIENT_MEMORY; - } + data = *start; + swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); + if (!top) { + return BMP_INSUFFICIENT_MEMORY; + } - bottom = top + (uint64_t)swidth * (bmp->height - 1); - end = data + bytes; - addr = ((intptr_t)data) & 3; - bmp->decoded = true; + bottom = top + (uint64_t)swidth * (bmp->height - 1); + end = data + bytes; + addr = ((intptr_t)data) & 3; + bmp->decoded = true; - /* Determine transparent index */ - if (bmp->limited_trans) { - if ((data + 3) > end) { - return BMP_INSUFFICIENT_DATA; - } + /* Determine transparent index */ + if (bmp->limited_trans) { + if ((data + 3) > end) { + return BMP_INSUFFICIENT_DATA; + } - bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16); - } + bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16); + } - for (y = 0; y < bmp->height; y++) { - if ((data + (3 * bmp->width)) > end) { - return BMP_INSUFFICIENT_DATA; - } + for (y = 0; y < bmp->height; y++) { + if ((data + (3 * bmp->width)) > end) { + return BMP_INSUFFICIENT_DATA; + } - if (bmp->reversed) { - scanline = (void *)(top + (y * swidth)); - } else { - scanline = (void *)(bottom - (y * swidth)); - } + if (bmp->reversed) { + scanline = (void *)(top + (y * swidth)); + } else { + scanline = (void *)(bottom - (y * swidth)); + } - for (x = 0; x < bmp->width; x++) { - scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16); - if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) { - scanline[x] = bmp->trans_colour; - } else { - scanline[x] |= ((uint32_t)0xff << 24); - } - data += 3; - scanline[x] = read_uint32((uint8_t *)&scanline[x],0); - } + for (x = 0; x < bmp->width; x++) { + scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16); + if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) { + scanline[x] = bmp->trans_colour; + } else { + scanline[x] |= ((uint32_t)0xff << 24); + } + data += 3; + scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); + } - while (addr != (((intptr_t)data) & 3)) { - data++; - } - } - *start = data; - return BMP_OK; + while (addr != (((intptr_t)data) & 3)) { + data++; + } + } + *start = data; + return BMP_OK; } - /** * Decode BMP data stored in 16bpp colour. * @@ -673,82 +654,79 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes) * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly; * in this case, the image may be partially viewable */ -static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes) -{ - uint8_t *top, *bottom, *end, *data; - uint32_t *scanline; - uint32_t x, y, swidth; - intptr_t addr; - uint8_t i; - uint16_t word; +static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes) { + uint8_t *top, *bottom, *end, *data; + uint32_t *scanline; + uint32_t x, y, swidth; + intptr_t addr; + uint8_t i; + uint16_t word; - data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); - if (!top) - return BMP_INSUFFICIENT_MEMORY; - bottom = top + (uint64_t)swidth * (bmp->height - 1); - end = data + bytes; - addr = ((intptr_t)data) & 3; - bmp->decoded = true; + data = *start; + swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); + if (!top) + return BMP_INSUFFICIENT_MEMORY; + bottom = top + (uint64_t)swidth * (bmp->height - 1); + end = data + bytes; + addr = ((intptr_t)data) & 3; + bmp->decoded = true; - /* Determine transparent index */ - if (bmp->limited_trans) { - if ((data + 2) > end) - return BMP_INSUFFICIENT_DATA; - bmp->transparent_index = read_uint16(data, 0); + /* Determine transparent index */ + if (bmp->limited_trans) { + if ((data + 2) > end) + return BMP_INSUFFICIENT_DATA; + bmp->transparent_index = read_uint16(data, 0); + } + + for (y = 0; y < bmp->height; y++) { + if ((data + (2 * bmp->width)) > end) + return BMP_INSUFFICIENT_DATA; + if (bmp->reversed) + scanline = (void *)(top + (y * swidth)); + else + scanline = (void *)(bottom - (y * swidth)); + if (bmp->encoding == BMP_ENCODING_BITFIELDS) { + for (x = 0; x < bmp->width; x++) { + word = read_uint16(data, 0); + if ((bmp->limited_trans) && (word == bmp->transparent_index)) + scanline[x] = bmp->trans_colour; + else { + scanline[x] = 0; + for (i = 0; i < 4; i++) + if (bmp->shift[i] > 0) + scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]); + else + scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i])); + if (bmp->opaque) + scanline[x] |= ((unsigned)0xff << 24); } - - for (y = 0; y < bmp->height; y++) { - if ((data + (2 * bmp->width)) > end) - return BMP_INSUFFICIENT_DATA; - if (bmp->reversed) - scanline = (void *)(top + (y * swidth)); - else - scanline = (void *)(bottom - (y * swidth)); - if (bmp->encoding == BMP_ENCODING_BITFIELDS) { - for (x = 0; x < bmp->width; x++) { - word = read_uint16(data, 0); - if ((bmp->limited_trans) && (word == bmp->transparent_index)) - scanline[x] = bmp->trans_colour; - else { - scanline[x] = 0; - for (i = 0; i < 4; i++) - if (bmp->shift[i] > 0) - scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]); - else - scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i])); - if (bmp->opaque) - scanline[x] |= ((unsigned)0xff << 24); - } - data += 2; - scanline[x] = read_uint32((uint8_t *)&scanline[x],0); - } - } else { - for (x = 0; x < bmp->width; x++) { - word = read_uint16(data, 0); - if ((bmp->limited_trans) && (word == bmp->transparent_index)) - scanline[x] = bmp->trans_colour; - else { - /* 16-bit RGB defaults to RGB555 */ - scanline[x] = ((word & (31 << 0)) << 19) | - ((word & (31 << 5)) << 6) | - ((word & (31 << 10)) >> 7); - } - if (bmp->opaque) - scanline[x] |= ((unsigned)0xff << 24); - data += 2; - scanline[x] = read_uint32((uint8_t *)&scanline[x],0); - } - } - while (addr != (((intptr_t)data) & 3)) - data += 2; + data += 2; + scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); + } + } else { + for (x = 0; x < bmp->width; x++) { + word = read_uint16(data, 0); + if ((bmp->limited_trans) && (word == bmp->transparent_index)) + scanline[x] = bmp->trans_colour; + else { + /* 16-bit RGB defaults to RGB555 */ + scanline[x] = ((word & (31 << 0)) << 19) | ((word & (31 << 5)) << 6) | + ((word & (31 << 10)) >> 7); } - *start = data; - return BMP_OK; + if (bmp->opaque) + scanline[x] |= ((unsigned)0xff << 24); + data += 2; + scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); + } + } + while (addr != (((intptr_t)data) & 3)) + data += 2; + } + *start = data; + return BMP_OK; } - /** * Decode BMP data stored with a palette and in 8bpp colour or less. * @@ -759,73 +737,70 @@ static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes) * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly; * in this case, the image may be partially viewable */ -static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t **start, int bytes) -{ - uint8_t *top, *bottom, *end, *data; - uint32_t *scanline; - intptr_t addr; - uint32_t x, y, swidth; - uint8_t bit_shifts[8]; - uint8_t ppb = 8 / bmp->bpp; - uint8_t bit_mask = (1 << bmp->bpp) - 1; - uint8_t cur_byte = 0, bit, i; +static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t **start, int bytes) { + uint8_t *top, *bottom, *end, *data; + uint32_t *scanline; + intptr_t addr; + uint32_t x, y, swidth; + uint8_t bit_shifts[8]; + uint8_t ppb = 8 / bmp->bpp; + uint8_t bit_mask = (1 << bmp->bpp) - 1; + uint8_t cur_byte = 0, bit, i; - /* Belt and braces, we shouldn't get here unless this holds */ - assert(ppb >= 1); + /* Belt and braces, we shouldn't get here unless this holds */ + assert(ppb >= 1); - for (i = 0; i < ppb; i++) - bit_shifts[i] = 8 - ((i + 1) * bmp->bpp); + for (i = 0; i < ppb; i++) + bit_shifts[i] = 8 - ((i + 1) * bmp->bpp); - data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); - if (!top) - return BMP_INSUFFICIENT_MEMORY; - bottom = top + (uint64_t)swidth * (bmp->height - 1); - end = data + bytes; - addr = ((intptr_t)data) & 3; - bmp->decoded = true; + data = *start; + swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); + if (!top) + return BMP_INSUFFICIENT_MEMORY; + bottom = top + (uint64_t)swidth * (bmp->height - 1); + end = data + bytes; + addr = ((intptr_t)data) & 3; + bmp->decoded = true; - /* Determine transparent index */ - if (bmp->limited_trans) { - uint32_t idx = (*data >> bit_shifts[0]) & bit_mask; - if (idx >= bmp->colours) - return BMP_DATA_ERROR; - bmp->transparent_index = bmp->colour_table[idx]; + /* Determine transparent index */ + if (bmp->limited_trans) { + uint32_t idx = (*data >> bit_shifts[0]) & bit_mask; + if (idx >= bmp->colours) + return BMP_DATA_ERROR; + bmp->transparent_index = bmp->colour_table[idx]; + } + + for (y = 0; y < bmp->height; y++) { + bit = 8; + if ((data + ((bmp->width + ppb - 1) / ppb)) > end) + return BMP_INSUFFICIENT_DATA; + if (bmp->reversed) + scanline = (void *)(top + (y * swidth)); + else + scanline = (void *)(bottom - (y * swidth)); + for (x = 0; x < bmp->width; x++) { + uint32_t idx; + if (bit >= ppb) { + bit = 0; + cur_byte = *data++; + } + idx = (cur_byte >> bit_shifts[bit++]) & bit_mask; + if (idx < bmp->colours) { + /* ensure colour table index is in bounds */ + scanline[x] = bmp->colour_table[idx]; + if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) { + scanline[x] = bmp->trans_colour; } - - for (y = 0; y < bmp->height; y++) { - bit = 8; - if ((data + ((bmp->width + ppb - 1) / ppb)) > end) - return BMP_INSUFFICIENT_DATA; - if (bmp->reversed) - scanline = (void *)(top + (y * swidth)); - else - scanline = (void *)(bottom - (y * swidth)); - for (x = 0; x < bmp->width; x++) { - uint32_t idx; - if (bit >= ppb) { - bit = 0; - cur_byte = *data++; - } - idx = (cur_byte >> bit_shifts[bit++]) & bit_mask; - if (idx < bmp->colours) { - /* ensure colour table index is in bounds */ - scanline[x] = bmp->colour_table[idx]; - if ((bmp->limited_trans) && - (scanline[x] == bmp->transparent_index)) { - scanline[x] = bmp->trans_colour; - } - } - } - while (addr != (((intptr_t)data) & 3)) - data++; - } - *start = data; - return BMP_OK; + } + } + while (addr != (((intptr_t)data) & 3)) + data++; + } + *start = data; + return BMP_OK; } - /** * Decode a 1bpp mask for an ICO * @@ -834,46 +809,44 @@ static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t **start, int bytes) * \param bytes the number of bytes of data available * \return BMP_OK on success */ -static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t *data, int bytes) -{ - uint8_t *top, *bottom, *end; - uint32_t *scanline; - intptr_t addr; - uint32_t x, y, swidth; - uint32_t cur_byte = 0; +static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t *data, int bytes) { + uint8_t *top, *bottom, *end; + uint32_t *scanline; + intptr_t addr; + uint32_t x, y, swidth; + uint32_t cur_byte = 0; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); - if (!top) - return BMP_INSUFFICIENT_MEMORY; - bottom = top + (uint64_t)swidth * (bmp->height - 1); - end = data + bytes; + swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); + if (!top) + return BMP_INSUFFICIENT_MEMORY; + bottom = top + (uint64_t)swidth * (bmp->height - 1); + end = data + bytes; - addr = ((intptr_t)data) & 3; + addr = ((intptr_t)data) & 3; - for (y = 0; y < bmp->height; y++) { - if ((data + (bmp->width >> 3)) > end) - return BMP_INSUFFICIENT_DATA; - scanline = (void *)(bottom - (y * swidth)); - for (x = 0; x < bmp->width; x++) { - if ((x & 7) == 0) - cur_byte = *data++; - scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); - if ((cur_byte & 128) == 0) { - scanline[x] |= ((unsigned)0xff << 24); - } else { - scanline[x] &= 0xffffff; - } - scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); - cur_byte = cur_byte << 1; - } - while (addr != (((intptr_t)data) & 3)) - data++; - } - return BMP_OK; + for (y = 0; y < bmp->height; y++) { + if ((data + (bmp->width >> 3)) > end) + return BMP_INSUFFICIENT_DATA; + scanline = (void *)(bottom - (y * swidth)); + for (x = 0; x < bmp->width; x++) { + if ((x & 7) == 0) + cur_byte = *data++; + scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); + if ((cur_byte & 128) == 0) { + scanline[x] |= ((unsigned)0xff << 24); + } else { + scanline[x] &= 0xffffff; + } + scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); + cur_byte = cur_byte << 1; + } + while (addr != (((intptr_t)data) & 3)) + data++; + } + return BMP_OK; } - /** * Decode BMP data stored encoded in RLE8. * @@ -884,149 +857,146 @@ static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t *data, int bytes) * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly; * in this case, the image may be partially viewable */ -static bmp_result -bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes) -{ - uint8_t *top, *bottom, *end; - uint32_t *scanline; - uint32_t swidth; - uint32_t i, length, pixels_left; - uint32_t x = 0, y = 0, last_y = 0; - uint32_t pixel = 0; +static bmp_result bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes) { + uint8_t *top, *bottom, *end; + uint32_t *scanline; + uint32_t swidth; + uint32_t i, length, pixels_left; + uint32_t x = 0, y = 0, last_y = 0; + uint32_t pixel = 0; - if (bmp->ico) - return BMP_DATA_ERROR; + if (bmp->ico) + return BMP_DATA_ERROR; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); - if (!top) - return BMP_INSUFFICIENT_MEMORY; - bottom = top + (uint64_t)swidth * (bmp->height - 1); - end = data + bytes; - bmp->decoded = true; + swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); + if (!top) + return BMP_INSUFFICIENT_MEMORY; + bottom = top + (uint64_t)swidth * (bmp->height - 1); + end = data + bytes; + bmp->decoded = true; - do { - if (data + 2 > end) - return BMP_INSUFFICIENT_DATA; - length = *data++; - if (length == 0) { - length = *data++; - switch (length) { - case 0: - /* 00 - 00 means end of scanline */ - x = 0; - if (last_y == y) { - y++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - } - last_y = y; - break; - - case 1: - /* 00 - 01 means end of RLE data */ - return BMP_OK; - - case 2: - /* 00 - 02 - XX - YY means move cursor */ - if (data + 2 > end) - return BMP_INSUFFICIENT_DATA; - x += *data++; - if (x >= bmp->width) - return BMP_DATA_ERROR; - y += *data++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - break; - - default: - /* 00 - NN means escape NN pixels */ - if (bmp->reversed) { - pixels_left = (bmp->height - y) * bmp->width - x; - scanline = (void *)(top + (y * swidth)); - } else { - pixels_left = (y + 1) * bmp->width - x; - scanline = (void *)(bottom - (y * swidth)); - } - if (length > pixels_left) - length = pixels_left; - if (data + length > end) - return BMP_INSUFFICIENT_DATA; - - /* the following code could be easily optimised - * by simply checking the bounds on entry and - * using some simple copying routines if so - */ - for (i = 0; i < length; i++) { - uint32_t idx = (uint32_t) *data++; - if (x >= bmp->width) { - x = 0; - y++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - if (bmp->reversed) { - scanline += bmp->width; - } else { - scanline -= bmp->width; - } - } - if (idx >= bmp->colours) - return BMP_DATA_ERROR; - scanline[x++] = bmp->colour_table[idx]; - } - - if ((length & 1) && (*data++ != 0x00)) - return BMP_DATA_ERROR; - - break; - } - } else { - uint32_t idx; - - /* NN means perform RLE for NN pixels */ - if (bmp->reversed) { - pixels_left = (bmp->height - y) * bmp->width - x; - scanline = (void *)(top + (y * swidth)); - } else { - pixels_left = (y + 1) * bmp->width - x; - scanline = (void *)(bottom - (y * swidth)); - } - if (length > pixels_left) - length = pixels_left; - - /* boundary checking */ - if (data + 1 > end) - return BMP_INSUFFICIENT_DATA; - - /* the following code could be easily optimised by - * simply checking the bounds on entry and using some - * simply copying routines if so - */ - idx = (uint32_t) *data++; - if (idx >= bmp->colours) - return BMP_DATA_ERROR; - - pixel = bmp->colour_table[idx]; - for (i = 0; i < length; i++) { - if (x >= bmp->width) { - x = 0; - y++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - if (bmp->reversed) { - scanline += bmp->width; - } else { - scanline -= bmp->width; - } - } - scanline[x++] = pixel; - } - } - } while (data < end); + do { + if (data + 2 > end) + return BMP_INSUFFICIENT_DATA; + length = *data++; + if (length == 0) { + length = *data++; + switch (length) { + case 0: + /* 00 - 00 means end of scanline */ + x = 0; + if (last_y == y) { + y++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + } + last_y = y; + break; + case 1: + /* 00 - 01 means end of RLE data */ return BMP_OK; -} + case 2: + /* 00 - 02 - XX - YY means move cursor */ + if (data + 2 > end) + return BMP_INSUFFICIENT_DATA; + x += *data++; + if (x >= bmp->width) + return BMP_DATA_ERROR; + y += *data++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + break; + + default: + /* 00 - NN means escape NN pixels */ + if (bmp->reversed) { + pixels_left = (bmp->height - y) * bmp->width - x; + scanline = (void *)(top + (y * swidth)); + } else { + pixels_left = (y + 1) * bmp->width - x; + scanline = (void *)(bottom - (y * swidth)); + } + if (length > pixels_left) + length = pixels_left; + if (data + length > end) + return BMP_INSUFFICIENT_DATA; + + /* the following code could be easily optimised + * by simply checking the bounds on entry and + * using some simple copying routines if so + */ + for (i = 0; i < length; i++) { + uint32_t idx = (uint32_t)*data++; + if (x >= bmp->width) { + x = 0; + y++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + if (bmp->reversed) { + scanline += bmp->width; + } else { + scanline -= bmp->width; + } + } + if (idx >= bmp->colours) + return BMP_DATA_ERROR; + scanline[x++] = bmp->colour_table[idx]; + } + + if ((length & 1) && (*data++ != 0x00)) + return BMP_DATA_ERROR; + + break; + } + } else { + uint32_t idx; + + /* NN means perform RLE for NN pixels */ + if (bmp->reversed) { + pixels_left = (bmp->height - y) * bmp->width - x; + scanline = (void *)(top + (y * swidth)); + } else { + pixels_left = (y + 1) * bmp->width - x; + scanline = (void *)(bottom - (y * swidth)); + } + if (length > pixels_left) + length = pixels_left; + + /* boundary checking */ + if (data + 1 > end) + return BMP_INSUFFICIENT_DATA; + + /* the following code could be easily optimised by + * simply checking the bounds on entry and using some + * simply copying routines if so + */ + idx = (uint32_t)*data++; + if (idx >= bmp->colours) + return BMP_DATA_ERROR; + + pixel = bmp->colour_table[idx]; + for (i = 0; i < length; i++) { + if (x >= bmp->width) { + x = 0; + y++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + if (bmp->reversed) { + scanline += bmp->width; + } else { + scanline -= bmp->width; + } + } + scanline[x++] = pixel; + } + } + } while (data < end); + + return BMP_OK; +} /** * Decode BMP data stored encoded in RLE4. @@ -1038,351 +1008,324 @@ bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes) * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly; * in this case, the image may be partially viewable */ -static bmp_result -bmp_decode_rle4(bmp_image *bmp, uint8_t *data, int bytes) -{ - uint8_t *top, *bottom, *end; - uint32_t *scanline; - uint32_t swidth; - uint32_t i, length, pixels_left; - uint32_t x = 0, y = 0, last_y = 0; - uint32_t pixel = 0, pixel2; +static bmp_result bmp_decode_rle4(bmp_image *bmp, uint8_t *data, int bytes) { + uint8_t *top, *bottom, *end; + uint32_t *scanline; + uint32_t swidth; + uint32_t i, length, pixels_left; + uint32_t x = 0, y = 0, last_y = 0; + uint32_t pixel = 0, pixel2; - if (bmp->ico) - return BMP_DATA_ERROR; + if (bmp->ico) + return BMP_DATA_ERROR; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; - top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); - if (!top) - return BMP_INSUFFICIENT_MEMORY; - bottom = top + (uint64_t)swidth * (bmp->height - 1); - end = data + bytes; - bmp->decoded = true; + swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); + if (!top) + return BMP_INSUFFICIENT_MEMORY; + bottom = top + (uint64_t)swidth * (bmp->height - 1); + end = data + bytes; + bmp->decoded = true; - do { - if (data + 2 > end) - return BMP_INSUFFICIENT_DATA; - length = *data++; - if (length == 0) { - length = *data++; - switch (length) { - case 0: - /* 00 - 00 means end of scanline */ - x = 0; - if (last_y == y) { - y++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - } - last_y = y; - break; - - case 1: - /* 00 - 01 means end of RLE data */ - return BMP_OK; - - case 2: - /* 00 - 02 - XX - YY means move cursor */ - if (data + 2 > end) - return BMP_INSUFFICIENT_DATA; - x += *data++; - if (x >= bmp->width) - return BMP_DATA_ERROR; - y += *data++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - break; - - default: - /* 00 - NN means escape NN pixels */ - if (bmp->reversed) { - pixels_left = (bmp->height - y) * bmp->width - x; - scanline = (void *)(top + (y * swidth)); - } else { - pixels_left = (y + 1) * bmp->width - x; - scanline = (void *)(bottom - (y * swidth)); - } - if (length > pixels_left) - length = pixels_left; - if (data + ((length + 1) / 2) > end) - return BMP_INSUFFICIENT_DATA; - - /* the following code could be easily optimised - * by simply checking the bounds on entry and - * using some simple copying routines - */ - - for (i = 0; i < length; i++) { - if (x >= bmp->width) { - x = 0; - y++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - if (bmp->reversed) { - scanline += bmp->width; - } else { - scanline -= bmp->width; - } - - } - if ((i & 1) == 0) { - pixel = *data++; - if ((pixel >> 4) >= bmp->colours) - return BMP_DATA_ERROR; - scanline[x++] = bmp->colour_table - [pixel >> 4]; - } else { - if ((pixel & 0xf) >= bmp->colours) - return BMP_DATA_ERROR; - scanline[x++] = bmp->colour_table - [pixel & 0xf]; - } - } - length = (length + 1) >> 1; - - if ((length & 1) && (*data++ != 0x00)) - return BMP_DATA_ERROR; - - break; - } - } else { - /* NN means perform RLE for NN pixels */ - if (bmp->reversed) { - pixels_left = (bmp->height - y) * bmp->width - x; - scanline = (void *)(top + (y * swidth)); - } else { - pixels_left = (y + 1) * bmp->width - x; - scanline = (void *)(bottom - (y * swidth)); - } - if (length > pixels_left) - length = pixels_left; - - /* boundary checking */ - if (data + 1 > end) - return BMP_INSUFFICIENT_DATA; - - /* the following code could be easily optimised by - * simply checking the bounds on entry and using some - * simple copying routines - */ - - pixel2 = *data++; - if ((pixel2 >> 4) >= bmp->colours || - (pixel2 & 0xf) >= bmp->colours) - return BMP_DATA_ERROR; - pixel = bmp->colour_table[pixel2 >> 4]; - pixel2 = bmp->colour_table[pixel2 & 0xf]; - for (i = 0; i < length; i++) { - if (x >= bmp->width) { - x = 0; - y++; - if (y >= bmp->height) - return BMP_DATA_ERROR; - if (bmp->reversed) { - scanline += bmp->width; - } else { - scanline -= bmp->width; - } - } - if ((i & 1) == 0) - scanline[x++] = pixel; - else - scanline[x++] = pixel2; - } - - } - } while (data < end); + do { + if (data + 2 > end) + return BMP_INSUFFICIENT_DATA; + length = *data++; + if (length == 0) { + length = *data++; + switch (length) { + case 0: + /* 00 - 00 means end of scanline */ + x = 0; + if (last_y == y) { + y++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + } + last_y = y; + break; + case 1: + /* 00 - 01 means end of RLE data */ return BMP_OK; -} + case 2: + /* 00 - 02 - XX - YY means move cursor */ + if (data + 2 > end) + return BMP_INSUFFICIENT_DATA; + x += *data++; + if (x >= bmp->width) + return BMP_DATA_ERROR; + y += *data++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + break; -/* exported interface documented in libnsbmp.h */ -bmp_result -bmp_create(bmp_image *bmp, - bmp_bitmap_callback_vt *bitmap_callbacks) -{ - memset(bmp, 0, sizeof(bmp_image)); - bmp->bitmap_callbacks = *bitmap_callbacks; - - return BMP_OK; -} - - -/* exported interface documented in libnsbmp.h */ -bmp_result -ico_collection_create(ico_collection *ico, - bmp_bitmap_callback_vt *bitmap_callbacks) -{ - - memset(ico, 0, sizeof(ico_collection)); - ico->bitmap_callbacks = *bitmap_callbacks; - - return BMP_OK; -} - - -/* exported interface documented in libnsbmp.h */ -bmp_result bmp_analyse(bmp_image *bmp, size_t size, uint8_t *data) -{ - bmp_result res; - - /* ensure we aren't already initialised */ - if (bmp->bitmap) { - return BMP_OK; + default: + /* 00 - NN means escape NN pixels */ + if (bmp->reversed) { + pixels_left = (bmp->height - y) * bmp->width - x; + scanline = (void *)(top + (y * swidth)); + } else { + pixels_left = (y + 1) * bmp->width - x; + scanline = (void *)(bottom - (y * swidth)); } + if (length > pixels_left) + length = pixels_left; + if (data + ((length + 1) / 2) > end) + return BMP_INSUFFICIENT_DATA; - /* initialize source data values */ - bmp->buffer_size = size; - bmp->bmp_data = data; + /* the following code could be easily optimised + * by simply checking the bounds on entry and + * using some simple copying routines + */ - res = bmp_file_header_parse(bmp, data); - if (res == BMP_OK) { - res = bmp_info_header_parse(bmp, data + BMP_FILE_HEADER_SIZE); + for (i = 0; i < length; i++) { + if (x >= bmp->width) { + x = 0; + y++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + if (bmp->reversed) { + scanline += bmp->width; + } else { + scanline -= bmp->width; + } + } + if ((i & 1) == 0) { + pixel = *data++; + if ((pixel >> 4) >= bmp->colours) + return BMP_DATA_ERROR; + scanline[x++] = bmp->colour_table[pixel >> 4]; + } else { + if ((pixel & 0xf) >= bmp->colours) + return BMP_DATA_ERROR; + scanline[x++] = bmp->colour_table[pixel & 0xf]; + } } - return res; -} + length = (length + 1) >> 1; + if ((length & 1) && (*data++ != 0x00)) + return BMP_DATA_ERROR; -/* exported interface documented in libnsbmp.h */ -bmp_result ico_analyse(ico_collection *ico, size_t size, uint8_t *data) -{ - /* ensure we aren't already initialised */ - if (ico->first) - return BMP_OK; + break; + } + } else { + /* NN means perform RLE for NN pixels */ + if (bmp->reversed) { + pixels_left = (bmp->height - y) * bmp->width - x; + scanline = (void *)(top + (y * swidth)); + } else { + pixels_left = (y + 1) * bmp->width - x; + scanline = (void *)(bottom - (y * swidth)); + } + if (length > pixels_left) + length = pixels_left; - /* initialize values */ - ico->buffer_size = size; - ico->ico_data = data; + /* boundary checking */ + if (data + 1 > end) + return BMP_INSUFFICIENT_DATA; - return ico_header_parse(ico, data); -} + /* the following code could be easily optimised by + * simply checking the bounds on entry and using some + * simple copying routines + */ - -/* exported interface documented in libnsbmp.h */ -bmp_result bmp_decode(bmp_image *bmp) -{ - uint8_t *data; - uint32_t bytes; - bmp_result result = BMP_OK; - - assert(bmp->bitmap); - - data = bmp->bmp_data + bmp->bitmap_offset; - bytes = bmp->buffer_size - bmp->bitmap_offset; - - switch (bmp->encoding) { - case BMP_ENCODING_RGB: - switch (bmp->bpp) { - case 32: - result = bmp_decode_rgb32(bmp, &data, bytes); - break; - - case 24: - result = bmp_decode_rgb24(bmp, &data, bytes); - break; - - case 16: - result = bmp_decode_rgb16(bmp, &data, bytes); - break; - - default: - result = bmp_decode_rgb(bmp, &data, bytes); - break; - } - break; - - case BMP_ENCODING_RLE8: - result = bmp_decode_rle8(bmp, data, bytes); - break; - - case BMP_ENCODING_RLE4: - result = bmp_decode_rle4(bmp, data, bytes); - break; - - case BMP_ENCODING_BITFIELDS: - switch (bmp->bpp) { - case 32: - result = bmp_decode_rgb32(bmp, &data, bytes); - break; - - case 16: - result = bmp_decode_rgb16(bmp, &data, bytes); - break; - - default: - result = BMP_DATA_ERROR; - break; - } - break; + pixel2 = *data++; + if ((pixel2 >> 4) >= bmp->colours || (pixel2 & 0xf) >= bmp->colours) + return BMP_DATA_ERROR; + pixel = bmp->colour_table[pixel2 >> 4]; + pixel2 = bmp->colour_table[pixel2 & 0xf]; + for (i = 0; i < length; i++) { + if (x >= bmp->width) { + x = 0; + y++; + if (y >= bmp->height) + return BMP_DATA_ERROR; + if (bmp->reversed) { + scanline += bmp->width; + } else { + scanline -= bmp->width; + } } + if ((i & 1) == 0) + scanline[x++] = pixel; + else + scanline[x++] = pixel2; + } + } + } while (data < end); - /* icons with less than 32bpp have a 1bpp alpha mask */ - if ((result == BMP_OK) && (bmp->ico) && (bmp->bpp != 32)) { - bytes = (uintptr_t)bmp->bmp_data + bmp->buffer_size - (uintptr_t)data; - result = bmp_decode_mask(bmp, data, bytes); - } - return result; + return BMP_OK; } - /* exported interface documented in libnsbmp.h */ -bmp_result bmp_decode_trans(bmp_image *bmp, uint32_t colour) -{ - bmp->limited_trans = true; - bmp->trans_colour = colour; - return bmp_decode(bmp); -} +bmp_result bmp_create(bmp_image *bmp, + bmp_bitmap_callback_vt *bitmap_callbacks) { + memset(bmp, 0, sizeof(bmp_image)); + bmp->bitmap_callbacks = *bitmap_callbacks; + return BMP_OK; +} /* exported interface documented in libnsbmp.h */ -bmp_image *ico_find(ico_collection *ico, uint16_t width, uint16_t height) -{ - bmp_image *bmp = NULL; - ico_image *image; - int x, y, cur, distance = (1 << 24); +bmp_result ico_collection_create(ico_collection *ico, + bmp_bitmap_callback_vt *bitmap_callbacks) { - if (width == 0) - width = ico->width; - if (height == 0) - height = ico->height; - for (image = ico->first; image; image = image->next) { - if ((image->bmp.width == width) && (image->bmp.height == height)) - return &image->bmp; - x = image->bmp.width - width; - y = image->bmp.height - height; - cur = (x * x) + (y * y); - if (cur < distance) { - distance = cur; - bmp = &image->bmp; - } - } - return bmp; + memset(ico, 0, sizeof(ico_collection)); + ico->bitmap_callbacks = *bitmap_callbacks; + + return BMP_OK; } - /* exported interface documented in libnsbmp.h */ -void bmp_finalise(bmp_image *bmp) -{ - if (bmp->bitmap) - bmp->bitmap_callbacks.bitmap_destroy(bmp->bitmap); - bmp->bitmap = NULL; - if (bmp->colour_table) - free(bmp->colour_table); - bmp->colour_table = NULL; -} +bmp_result bmp_analyse(bmp_image *bmp, size_t size, uint8_t *data) { + bmp_result res; + /* ensure we aren't already initialised */ + if (bmp->bitmap) { + return BMP_OK; + } + + /* initialize source data values */ + bmp->buffer_size = size; + bmp->bmp_data = data; + + res = bmp_file_header_parse(bmp, data); + if (res == BMP_OK) { + res = bmp_info_header_parse(bmp, data + BMP_FILE_HEADER_SIZE); + } + return res; +} /* exported interface documented in libnsbmp.h */ -void ico_finalise(ico_collection *ico) -{ - ico_image *image; +bmp_result ico_analyse(ico_collection *ico, size_t size, uint8_t *data) { + /* ensure we aren't already initialised */ + if (ico->first) + return BMP_OK; - for (image = ico->first; image; image = image->next) - bmp_finalise(&image->bmp); - while (ico->first) { - image = ico->first; - ico->first = image->next; - free(image); - } + /* initialize values */ + ico->buffer_size = size; + ico->ico_data = data; + + return ico_header_parse(ico, data); +} + +/* exported interface documented in libnsbmp.h */ +bmp_result bmp_decode(bmp_image *bmp) { + uint8_t *data; + uint32_t bytes; + bmp_result result = BMP_OK; + + assert(bmp->bitmap); + + data = bmp->bmp_data + bmp->bitmap_offset; + bytes = bmp->buffer_size - bmp->bitmap_offset; + + switch (bmp->encoding) { + case BMP_ENCODING_RGB: + switch (bmp->bpp) { + case 32: + result = bmp_decode_rgb32(bmp, &data, bytes); + break; + + case 24: + result = bmp_decode_rgb24(bmp, &data, bytes); + break; + + case 16: + result = bmp_decode_rgb16(bmp, &data, bytes); + break; + + default: + result = bmp_decode_rgb(bmp, &data, bytes); + break; + } + break; + + case BMP_ENCODING_RLE8: + result = bmp_decode_rle8(bmp, data, bytes); + break; + + case BMP_ENCODING_RLE4: + result = bmp_decode_rle4(bmp, data, bytes); + break; + + case BMP_ENCODING_BITFIELDS: + switch (bmp->bpp) { + case 32: + result = bmp_decode_rgb32(bmp, &data, bytes); + break; + + case 16: + result = bmp_decode_rgb16(bmp, &data, bytes); + break; + + default: + result = BMP_DATA_ERROR; + break; + } + break; + } + + /* icons with less than 32bpp have a 1bpp alpha mask */ + if ((result == BMP_OK) && (bmp->ico) && (bmp->bpp != 32)) { + bytes = (uintptr_t)bmp->bmp_data + bmp->buffer_size - (uintptr_t)data; + result = bmp_decode_mask(bmp, data, bytes); + } + return result; +} + +/* exported interface documented in libnsbmp.h */ +bmp_result bmp_decode_trans(bmp_image *bmp, uint32_t colour) { + bmp->limited_trans = true; + bmp->trans_colour = colour; + return bmp_decode(bmp); +} + +/* exported interface documented in libnsbmp.h */ +bmp_image *ico_find(ico_collection *ico, uint16_t width, uint16_t height) { + bmp_image *bmp = NULL; + ico_image *image; + int x, y, cur, distance = (1 << 24); + + if (width == 0) + width = ico->width; + if (height == 0) + height = ico->height; + for (image = ico->first; image; image = image->next) { + if ((image->bmp.width == width) && (image->bmp.height == height)) + return &image->bmp; + x = image->bmp.width - width; + y = image->bmp.height - height; + cur = (x * x) + (y * y); + if (cur < distance) { + distance = cur; + bmp = &image->bmp; + } + } + return bmp; +} + +/* exported interface documented in libnsbmp.h */ +void bmp_finalise(bmp_image *bmp) { + if (bmp->bitmap) + bmp->bitmap_callbacks.bitmap_destroy(bmp->bitmap); + bmp->bitmap = NULL; + if (bmp->colour_table) + free(bmp->colour_table); + bmp->colour_table = NULL; +} + +/* exported interface documented in libnsbmp.h */ +void ico_finalise(ico_collection *ico) { + ico_image *image; + + for (image = ico->first; image; image = image->next) + bmp_finalise(&image->bmp); + while (ico->first) { + image = ico->first; + ico->first = image->next; + free(image); + } } diff --git a/external/source/fs.c b/external/source/fs.c index 9f153df..d3c4ec3 100644 --- a/external/source/fs.c +++ b/external/source/fs.c @@ -3,384 +3,421 @@ #include #include +#include #include #include -#include -#define WORKING_DIR "/" +#define WORKING_DIR "/" void Utils_U8_To_U16(u16 *buf, const u8 *input, size_t bufsize) { - ssize_t units = utf8_to_utf16(buf, input, bufsize); + ssize_t units = utf8_to_utf16(buf, input, bufsize); - if (units < 0) - units = 0; + if (units < 0) + units = 0; - buf[units] = 0; + buf[units] = 0; } FS_Archive archive, sdmc_archive, nand_archive; Result FS_OpenArchive(FS_Archive *archive, FS_ArchiveID archiveID) { - Result ret = 0; + Result ret = 0; - if (R_FAILED(ret = FSUSER_OpenArchive(archive, archiveID, fsMakePath(PATH_EMPTY, "")))) - return ret; + if (R_FAILED(ret = FSUSER_OpenArchive(archive, archiveID, + fsMakePath(PATH_EMPTY, "")))) + return ret; - return 0; + return 0; } Result FS_CloseArchive(FS_Archive archive) { - Result ret = 0; + Result ret = 0; - if (R_FAILED(ret = FSUSER_CloseArchive(archive))) - return ret; + if (R_FAILED(ret = FSUSER_CloseArchive(archive))) + return ret; - return 0; + return 0; } Result FS_OpenDir(Handle *handle, FS_Archive archive, const char *path) { - Result ret = 0; + Result ret = 0; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_OpenDirectory(handle, archive, fsMakePath(PATH_UTF16, path_u16)))) - return ret; + if (R_FAILED(ret = FSUSER_OpenDirectory(handle, archive, + fsMakePath(PATH_UTF16, path_u16)))) + return ret; - return 0; + return 0; } -Result FS_OpenFile(Handle *handle, FS_Archive archive, const char *path, u32 flags, u32 attributes) { - Result ret = 0; +Result FS_OpenFile(Handle *handle, FS_Archive archive, const char *path, + u32 flags, u32 attributes) { + Result ret = 0; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_OpenFile(handle, archive, fsMakePath(PATH_UTF16, path_u16), flags, attributes))) - return ret; + if (R_FAILED(ret = FSUSER_OpenFile(handle, archive, + fsMakePath(PATH_UTF16, path_u16), flags, + attributes))) + return ret; - return 0; + return 0; } Result FS_MakeDir(FS_Archive archive, const char *path) { - Result ret = 0; + Result ret = 0; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_CreateDirectory(archive, fsMakePath(PATH_UTF16, path_u16), 0))) - return ret; + if (R_FAILED(ret = FSUSER_CreateDirectory( + archive, fsMakePath(PATH_UTF16, path_u16), 0))) + return ret; - return 0; + return 0; } Result FS_CreateFile(FS_Archive archive, const char *path, u64 size) { - Result ret = 0; + Result ret = 0; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_CreateFile(archive, fsMakePath(PATH_UTF16, path_u16), 0, size))) - return ret; + if (R_FAILED(ret = FSUSER_CreateFile( + archive, fsMakePath(PATH_UTF16, path_u16), 0, size))) + return ret; - return 0; + return 0; } Result FS_RecursiveMakeDir(FS_Archive archive, const char *path) { - Result ret = 0; - char buf[256]; - char *p = NULL; - size_t len; + Result ret = 0; + char buf[256]; + char *p = NULL; + size_t len; - snprintf(buf, sizeof(buf), "%s", path); - len = strlen(buf); + snprintf(buf, sizeof(buf), "%s", path); + len = strlen(buf); - if (buf[len - 1] == '/') - buf[len - 1] = 0; + if (buf[len - 1] == '/') + buf[len - 1] = 0; - for (p = buf + 1; *p; p++) { - if (*p == '/') { - *p = 0; + for (p = buf + 1; *p; p++) { + if (*p == '/') { + *p = 0; - if (!FS_DirExists(archive, buf)) - ret = FS_MakeDir(archive, buf); + if (!FS_DirExists(archive, buf)) + ret = FS_MakeDir(archive, buf); - *p = '/'; - } + *p = '/'; + } - if (!FS_DirExists(archive, buf)) - ret = FS_MakeDir(archive, buf); - } + if (!FS_DirExists(archive, buf)) + ret = FS_MakeDir(archive, buf); + } - return ret; + return ret; } bool FS_FileExists(FS_Archive archive, const char *path) { - Handle handle; + Handle handle; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(FSUSER_OpenFile(&handle, archive, fsMakePath(PATH_UTF16, path_u16), FS_OPEN_READ, 0))) - return false; + if (R_FAILED(FSUSER_OpenFile( + &handle, archive, fsMakePath(PATH_UTF16, path_u16), FS_OPEN_READ, 0))) + return false; - if (R_FAILED(FSFILE_Close(handle))) - return false; + if (R_FAILED(FSFILE_Close(handle))) + return false; - return true; + return true; } bool FS_DirExists(FS_Archive archive, const char *path) { - Handle handle; + Handle handle; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(FSUSER_OpenDirectory(&handle, archive, fsMakePath(PATH_UTF16, path_u16)))) - return false; + if (R_FAILED(FSUSER_OpenDirectory(&handle, archive, + fsMakePath(PATH_UTF16, path_u16)))) + return false; - if (R_FAILED(FSDIR_Close(handle))) - return false; + if (R_FAILED(FSDIR_Close(handle))) + return false; - return true; + return true; } Result FS_GetFileSize(FS_Archive archive, const char *path, u64 *size) { - Result ret = 0; - Handle handle; + Result ret = 0; + Handle handle; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_OpenFile(&handle, archive, fsMakePath(PATH_UTF16, path_u16), FS_OPEN_READ, 0))) - return ret; + if (R_FAILED(ret = FSUSER_OpenFile(&handle, archive, + fsMakePath(PATH_UTF16, path_u16), + FS_OPEN_READ, 0))) + return ret; - if (R_FAILED(ret = FSFILE_GetSize(handle, size))) { - FSFILE_Close(handle); - return ret; - } + if (R_FAILED(ret = FSFILE_GetSize(handle, size))) { + FSFILE_Close(handle); + return ret; + } - if (R_FAILED(ret = FSFILE_Close(handle))) - return ret; + if (R_FAILED(ret = FSFILE_Close(handle))) + return ret; - return 0; + return 0; } u64 FS_GetFreeStorage(FS_SystemMediaType media_type) { - FS_ArchiveResource resource = {0}; + FS_ArchiveResource resource = {0}; - if (R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, media_type))) - return (((u64)resource.freeClusters * (u64)resource.clusterSize)); + if (R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, media_type))) + return (((u64)resource.freeClusters * (u64)resource.clusterSize)); - return 0; + return 0; } u64 FS_GetTotalStorage(FS_SystemMediaType media_type) { - FS_ArchiveResource resource = {0}; + FS_ArchiveResource resource = {0}; - if (R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, media_type))) - return (((u64)resource.totalClusters * (u64)resource.clusterSize)); + if (R_SUCCEEDED(FSUSER_GetArchiveResource(&resource, media_type))) + return (((u64)resource.totalClusters * (u64)resource.clusterSize)); - return 0; + return 0; } u64 FS_GetUsedStorage(FS_SystemMediaType media_type) { - return 0;//(FS_GetTotalStorage(media_type) - FS_GetUsedStorage(media_type)); + return 0; //(FS_GetTotalStorage(media_type) - FS_GetUsedStorage(media_type)); } Result FS_RemoveFile(FS_Archive archive, const char *path) { - Result ret = 0; + Result ret = 0; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_DeleteFile(archive, fsMakePath(PATH_UTF16, path_u16)))) - return ret; + if (R_FAILED( + ret = FSUSER_DeleteFile(archive, fsMakePath(PATH_UTF16, path_u16)))) + return ret; - return 0; + return 0; } Result FS_RemoveDir(FS_Archive archive, const char *path) { - Result ret = 0; + Result ret = 0; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_DeleteDirectory(archive, fsMakePath(PATH_UTF16, path_u16)))) - return ret; + if (R_FAILED(ret = FSUSER_DeleteDirectory(archive, + fsMakePath(PATH_UTF16, path_u16)))) + return ret; - return 0; + return 0; } Result FS_RemoveDirRecursive(FS_Archive archive, const char *path) { - Result ret = 0; + Result ret = 0; - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_DeleteDirectoryRecursively(archive, fsMakePath(PATH_UTF16, path_u16)))) - return ret; + if (R_FAILED(ret = FSUSER_DeleteDirectoryRecursively( + archive, fsMakePath(PATH_UTF16, path_u16)))) + return ret; - return 0; + return 0; } -Result FS_RenameFile(FS_Archive archive, const char *old_filename, const char *new_filename) { - Result ret = 0; +Result FS_RenameFile(FS_Archive archive, const char *old_filename, + const char *new_filename) { + Result ret = 0; - u16 old_filename_u16[strlen(old_filename) + 1]; - Utils_U8_To_U16(old_filename_u16, (const u8 *)old_filename, strlen(old_filename) + 1); + u16 old_filename_u16[strlen(old_filename) + 1]; + Utils_U8_To_U16(old_filename_u16, (const u8 *)old_filename, + strlen(old_filename) + 1); - u16 new_filename_u16[strlen(new_filename) + 1]; - Utils_U8_To_U16(new_filename_u16, (const u8 *)new_filename, strlen(new_filename) + 1); + u16 new_filename_u16[strlen(new_filename) + 1]; + Utils_U8_To_U16(new_filename_u16, (const u8 *)new_filename, + strlen(new_filename) + 1); - if (R_FAILED(ret = FSUSER_RenameFile(archive, fsMakePath(PATH_UTF16, old_filename_u16), archive, fsMakePath(PATH_UTF16, new_filename_u16)))) - return ret; + if (R_FAILED(ret = FSUSER_RenameFile( + archive, fsMakePath(PATH_UTF16, old_filename_u16), archive, + fsMakePath(PATH_UTF16, new_filename_u16)))) + return ret; - return 0; + return 0; } -Result FS_RenameDir(FS_Archive archive, const char *old_dirname, const char *new_dirname) { - Result ret = 0; +Result FS_RenameDir(FS_Archive archive, const char *old_dirname, + const char *new_dirname) { + Result ret = 0; - u16 old_dirname_u16[strlen(old_dirname) + 1]; - Utils_U8_To_U16(old_dirname_u16, (const u8 *)old_dirname, strlen(old_dirname) + 1); + u16 old_dirname_u16[strlen(old_dirname) + 1]; + Utils_U8_To_U16(old_dirname_u16, (const u8 *)old_dirname, + strlen(old_dirname) + 1); - u16 new_dirname_u16[strlen(new_dirname) + 1]; - Utils_U8_To_U16(new_dirname_u16, (const u8 *)new_dirname, strlen(new_dirname) + 1); + u16 new_dirname_u16[strlen(new_dirname) + 1]; + Utils_U8_To_U16(new_dirname_u16, (const u8 *)new_dirname, + strlen(new_dirname) + 1); - if (R_FAILED(ret = FSUSER_RenameDirectory(archive, fsMakePath(PATH_UTF16, old_dirname_u16), archive, fsMakePath(PATH_UTF16, new_dirname_u16)))) - return ret; + if (R_FAILED(ret = FSUSER_RenameDirectory( + archive, fsMakePath(PATH_UTF16, old_dirname_u16), archive, + fsMakePath(PATH_UTF16, new_dirname_u16)))) + return ret; - return 0; + return 0; } Result FS_Read(FS_Archive archive, const char *path, u64 size, void *buf) { - Result ret = 0; - Handle handle; + Result ret = 0; + Handle handle; - u32 bytes_read = 0; + u32 bytes_read = 0; - if (R_FAILED(ret = FS_OpenFile(&handle, archive, path, FS_OPEN_READ, 0))) - return ret; + if (R_FAILED(ret = FS_OpenFile(&handle, archive, path, FS_OPEN_READ, 0))) + return ret; - if (R_FAILED(ret = FSFILE_Read(handle, &bytes_read, 0, buf, size))) { - FSFILE_Close(handle); - return ret; - } + if (R_FAILED(ret = FSFILE_Read(handle, &bytes_read, 0, buf, size))) { + FSFILE_Close(handle); + return ret; + } - if (R_FAILED(ret = FSFILE_Close(handle))) - return ret; + if (R_FAILED(ret = FSFILE_Close(handle))) + return ret; - return 0; + return 0; } -Result FS_Write(FS_Archive archive, const char *path, const void *buf, u32 size) { - Result ret = 0; - Handle handle; - u32 bytes_written = 0; +Result FS_Write(FS_Archive archive, const char *path, const void *buf, + u32 size) { + Result ret = 0; + Handle handle; + u32 bytes_written = 0; - if (FS_FileExists(archive, path)) - FS_RemoveFile(archive, path); + if (FS_FileExists(archive, path)) + FS_RemoveFile(archive, path); - u16 path_u16[strlen(path) + 1]; - Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); + u16 path_u16[strlen(path) + 1]; + Utils_U8_To_U16(path_u16, (const u8 *)path, strlen(path) + 1); - if (R_FAILED(ret = FSUSER_CreateFile(archive, fsMakePath(PATH_UTF16, path_u16), 0, size))) - return ret; + if (R_FAILED(ret = FSUSER_CreateFile( + archive, fsMakePath(PATH_UTF16, path_u16), 0, size))) + return ret; - if (R_FAILED(ret = FSUSER_OpenFile(&handle, archive, fsMakePath(PATH_UTF16, path_u16), FS_OPEN_WRITE, 0))) - return ret; + if (R_FAILED(ret = FSUSER_OpenFile(&handle, archive, + fsMakePath(PATH_UTF16, path_u16), + FS_OPEN_WRITE, 0))) + return ret; - if (R_FAILED(ret = FSFILE_Write(handle, &bytes_written, 0, buf, size, FS_WRITE_FLUSH))) { - FSFILE_Close(handle); - return ret; - } + if (R_FAILED(ret = FSFILE_Write(handle, &bytes_written, 0, buf, size, + FS_WRITE_FLUSH))) { + FSFILE_Close(handle); + return ret; + } - if (R_FAILED(ret = FSFILE_Close(handle))) - return ret; + if (R_FAILED(ret = FSFILE_Close(handle))) + return ret; - return 0; + return 0; } char *FS_GetFileTimestamp(const char *path) { - static char timeStr[60]; - u64 mtime = 0; + static char timeStr[60]; + u64 mtime = 0; - if (R_SUCCEEDED(archive_getmtime(path, &mtime))) { - time_t mt = mtime; - struct tm *timeStruct = gmtime(&mt); + if (R_SUCCEEDED(archive_getmtime(path, &mtime))) { + time_t mt = mtime; + struct tm *timeStruct = gmtime(&mt); - int hours = timeStruct->tm_hour; - int minutes = timeStruct->tm_min; + int hours = timeStruct->tm_hour; + int minutes = timeStruct->tm_min; - int day = timeStruct->tm_mday; - int month = timeStruct->tm_mon + 1; // January being 0 - int year = timeStruct->tm_year + 1900; + int day = timeStruct->tm_mday; + int month = timeStruct->tm_mon + 1; // January being 0 + int year = timeStruct->tm_year + 1900; - snprintf(timeStr, 60, "%d/%d/%d %2i:%02i", year, month, day, hours, minutes); - } - else - return NULL; + snprintf(timeStr, 60, "%d/%d/%d %2i:%02i", year, month, day, hours, + minutes); + } else + return NULL; - return timeStr; + return timeStr; } -FS_Path getPathInfo(const char * path, FS_ArchiveID * archive) { - *archive = ARCHIVE_SDMC; - FS_Path filePath = {0}; - unsigned int prefixlen = 0; +FS_Path getPathInfo(const char *path, FS_ArchiveID *archive) { + *archive = ARCHIVE_SDMC; + FS_Path filePath = {0}; + unsigned int prefixlen = 0; - if (!strncmp(path, "sdmc:/", 6)) { - prefixlen = 5; - } else if (*path != '/') { - //if the path is local (doesnt start with a slash), it needs to be appended to the working dir to be valid - char * actualPath = NULL; - asprintf(&actualPath, "%s%s", WORKING_DIR, path); - filePath = fsMakePath(PATH_ASCII, actualPath); - free(actualPath); - } + if (!strncmp(path, "sdmc:/", 6)) { + prefixlen = 5; + } else if (*path != '/') { + // if the path is local (doesnt start with a slash), it needs to be appended + // to the working dir to be valid + char *actualPath = NULL; + asprintf(&actualPath, "%s%s", WORKING_DIR, path); + filePath = fsMakePath(PATH_ASCII, actualPath); + free(actualPath); + } - //if the filePath wasnt set above, set it - if (filePath.size == 0) { - filePath = fsMakePath(PATH_ASCII, path+prefixlen); - } + // if the filePath wasnt set above, set it + if (filePath.size == 0) { + filePath = fsMakePath(PATH_ASCII, path + prefixlen); + } - return filePath; + return filePath; } -Result makeDirs(const char * path) { - Result ret = 0; - FS_ArchiveID archiveID; - FS_Path filePath = getPathInfo(path, &archiveID); - FS_Archive archive; +Result makeDirs(const char *path) { + Result ret = 0; + FS_ArchiveID archiveID; + FS_Path filePath = getPathInfo(path, &archiveID); + FS_Archive archive; - ret = FSUSER_OpenArchive(&archive, archiveID, fsMakePath(PATH_EMPTY, "")); + ret = FSUSER_OpenArchive(&archive, archiveID, fsMakePath(PATH_EMPTY, "")); - for (char * slashpos = strchr(path+1, '/'); slashpos != NULL; slashpos = strchr(slashpos+1, '/')) { - char bak = *(slashpos); - *(slashpos) = '\0'; - Handle dirHandle; + for (char *slashpos = strchr(path + 1, '/'); slashpos != NULL; + slashpos = strchr(slashpos + 1, '/')) { + char bak = *(slashpos); + *(slashpos) = '\0'; + Handle dirHandle; - ret = FSUSER_OpenDirectory(&dirHandle, archive, filePath); - if (R_SUCCEEDED(ret)) FSDIR_Close(dirHandle); - else ret = FSUSER_CreateDirectory(archive, filePath, FS_ATTRIBUTE_DIRECTORY); + ret = FSUSER_OpenDirectory(&dirHandle, archive, filePath); + if (R_SUCCEEDED(ret)) + FSDIR_Close(dirHandle); + else + ret = FSUSER_CreateDirectory(archive, filePath, FS_ATTRIBUTE_DIRECTORY); - *(slashpos) = bak; - } + *(slashpos) = bak; + } - FSUSER_CloseArchive(archive); + FSUSER_CloseArchive(archive); - return ret; + return ret; } -Result openFile(Handle* fileHandle, const char * path, bool write) { - FS_ArchiveID archive; - FS_Path filePath = getPathInfo(path, &archive); - u32 flags = (write ? (FS_OPEN_CREATE | FS_OPEN_WRITE) : FS_OPEN_READ); +Result openFile(Handle *fileHandle, const char *path, bool write) { + FS_ArchiveID archive; + FS_Path filePath = getPathInfo(path, &archive); + u32 flags = (write ? (FS_OPEN_CREATE | FS_OPEN_WRITE) : FS_OPEN_READ); - Result ret = 0; - ret = makeDirs(strdup(path)); - ret = FSUSER_OpenFileDirectly(fileHandle, archive, fsMakePath(PATH_EMPTY, ""), filePath, flags, 0); - if (write) ret = FSFILE_SetSize(*fileHandle, 0); //truncate the file to remove previous contents before writing + Result ret = 0; + ret = makeDirs(strdup(path)); + ret = FSUSER_OpenFileDirectly(fileHandle, archive, fsMakePath(PATH_EMPTY, ""), + filePath, flags, 0); + if (write) + ret = FSFILE_SetSize( + *fileHandle, + 0); // truncate the file to remove previous contents before writing - return ret; + return ret; } \ No newline at end of file diff --git a/external/source/lodepng.cpp b/external/source/lodepng.cpp index 30bece2..311c829 100644 --- a/external/source/lodepng.cpp +++ b/external/source/lodepng.cpp @@ -25,34 +25,38 @@ freely, subject to the following restrictions: /* The manual and changelog are in the header file "lodepng.h" -Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for +C. */ #include #ifdef LODEPNG_COMPILE_DISK #include /* LONG_MAX */ -#include /* file handling */ -#endif /* LODEPNG_COMPILE_DISK */ +#include /* file handling */ +#endif /* LODEPNG_COMPILE_DISK */ #ifdef LODEPNG_COMPILE_ALLOCATORS #include /* allocations */ -#endif /* LODEPNG_COMPILE_ALLOCATORS */ +#endif /* LODEPNG_COMPILE_ALLOCATORS */ -#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ -#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ -#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ -#endif /*_MSC_VER */ +#if defined(_MSC_VER) && \ + (_MSC_VER >= \ + 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning(disable : 4244) /*implicit conversions: not warned by gcc \ + -Wall -Wextra and requires too much casts*/ +#pragma warning(disable : 4996) /*VS does not like fopen, but fopen_s is not \ + standard C so unusable here*/ +#endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20201017"; +const char *LODEPNG_VERSION_STRING = "20201017"; /* This source file is built up in the following large parts. The code sections -with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. --Tools for C and common code for PNG and Zlib --C Code for Zlib (huffman, deflate, ...) --C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) --The C++ wrapper around all of the above +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed +way. -Tools for C and common code for PNG and Zlib -C Code for Zlib (huffman, +deflate, ...) -C Code for PNG (file format chunks, adam7, PNG filters, color +conversions, ...) -The C++ wrapper around all of the above */ /* ////////////////////////////////////////////////////////////////////////// */ @@ -71,70 +75,77 @@ lodepng source code. Don't forget to remove "static" if you copypaste them from here.*/ #ifdef LODEPNG_COMPILE_ALLOCATORS -static void* lodepng_malloc(size_t size) { +static void *lodepng_malloc(size_t size) { #ifdef LODEPNG_MAX_ALLOC - if(size > LODEPNG_MAX_ALLOC) return 0; + if (size > LODEPNG_MAX_ALLOC) + return 0; #endif return malloc(size); } /* NOTE: when realloc returns NULL, it leaves the original memory untouched */ -static void* lodepng_realloc(void* ptr, size_t new_size) { +static void *lodepng_realloc(void *ptr, size_t new_size) { #ifdef LODEPNG_MAX_ALLOC - if(new_size > LODEPNG_MAX_ALLOC) return 0; + if (new_size > LODEPNG_MAX_ALLOC) + return 0; #endif return realloc(ptr, new_size); } -static void lodepng_free(void* ptr) { - free(ptr); -} -#else /*LODEPNG_COMPILE_ALLOCATORS*/ +static void lodepng_free(void *ptr) { free(ptr); } +#else /*LODEPNG_COMPILE_ALLOCATORS*/ /* TODO: support giving additional void* payload to the custom allocators */ -void* lodepng_malloc(size_t size); -void* lodepng_realloc(void* ptr, size_t new_size); -void lodepng_free(void* ptr); +void *lodepng_malloc(size_t size); +void *lodepng_realloc(void *ptr, size_t new_size); +void lodepng_free(void *ptr); #endif /*LODEPNG_COMPILE_ALLOCATORS*/ -/* convince the compiler to inline a function, for use when this measurably improves performance */ +/* convince the compiler to inline a function, for use when this measurably + * improves performance */ /* inline is not available in C90, but use it when supported by the compiler */ -#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L)) +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) #define LODEPNG_INLINE inline #else #define LODEPNG_INLINE /* not available */ #endif -/* restrict is not available in C90, but use it when supported by the compiler */ -#if (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) ||\ - (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \ +/* restrict is not available in C90, but use it when supported by the compiler + */ +#if (defined(__GNUC__) && \ + (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) || \ + (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \ (defined(__WATCOMC__) && (__WATCOMC__ >= 1250) && !defined(__cplusplus)) #define LODEPNG_RESTRICT __restrict #else #define LODEPNG_RESTRICT /* not available */ #endif -/* Replacements for C library functions such as memcpy and strlen, to support platforms -where a full C library is not available. The compiler can recognize them and compile -to something as fast. */ +/* Replacements for C library functions such as memcpy and strlen, to support +platforms where a full C library is not available. The compiler can recognize +them and compile to something as fast. */ -static void lodepng_memcpy(void* LODEPNG_RESTRICT dst, - const void* LODEPNG_RESTRICT src, size_t size) { +static void lodepng_memcpy(void *LODEPNG_RESTRICT dst, + const void *LODEPNG_RESTRICT src, size_t size) { size_t i; - for(i = 0; i < size; i++) ((char*)dst)[i] = ((const char*)src)[i]; + for (i = 0; i < size; i++) + ((char *)dst)[i] = ((const char *)src)[i]; } -static void lodepng_memset(void* LODEPNG_RESTRICT dst, - int value, size_t num) { +static void lodepng_memset(void *LODEPNG_RESTRICT dst, int value, size_t num) { size_t i; - for(i = 0; i < num; i++) ((char*)dst)[i] = (char)value; + for (i = 0; i < num; i++) + ((char *)dst)[i] = (char)value; } /* does not check memory out of bounds, do not use on untrusted data */ -static size_t lodepng_strlen(const char* a) { - const char* orig = a; - /* avoid warning about unused function in case of disabled COMPILE... macros */ +static size_t lodepng_strlen(const char *a) { + const char *orig = a; + /* avoid warning about unused function in case of disabled COMPILE... macros + */ (void)(&lodepng_strlen); - while(*a) a++; + while (*a) + a++; return (size_t)(a - orig); } @@ -145,7 +156,7 @@ static size_t lodepng_strlen(const char* a) { #if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER) /* Safely check if adding two integers will overflow (no undefined behavior, compiler removing the code, etc...) and output result. */ -static int lodepng_addofl(size_t a, size_t b, size_t* result) { +static int lodepng_addofl(size_t a, size_t b, size_t *result) { *result = a + b; /* Unsigned addition is well defined and safe in C90 */ return *result < a; } @@ -154,7 +165,7 @@ static int lodepng_addofl(size_t a, size_t b, size_t* result) { #ifdef LODEPNG_COMPILE_DECODER /* Safely check if multiplying two integers will overflow (no undefined behavior, compiler removing the code, etc...) and output result. */ -static int lodepng_mulofl(size_t a, size_t b, size_t* result) { +static int lodepng_mulofl(size_t a, size_t b, size_t *result) { *result = a * b; /* Unsigned multiplication is well defined and safe in C90 */ return (a != 0 && *result / a != b); } @@ -163,13 +174,13 @@ static int lodepng_mulofl(size_t a, size_t b, size_t* result) { /* Safely check if a + b > c, even if overflow could happen. */ static int lodepng_gtofl(size_t a, size_t b, size_t c) { size_t d; - if(lodepng_addofl(a, b, &d)) return 1; + if (lodepng_addofl(a, b, &d)) + return 1; return d > c; } #endif /*LODEPNG_COMPILE_ZLIB*/ #endif /*LODEPNG_COMPILE_DECODER*/ - /* Often in case of an error a value is assigned to a variable and then it breaks out of a loop (to go to the cleanup phase of a function). This macro does that. @@ -177,111 +188,121 @@ It makes the error handling code shorter and more readable. Example: if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83); */ -#define CERROR_BREAK(errorvar, code){\ - errorvar = code;\ - break;\ -} +#define CERROR_BREAK(errorvar, code) \ + { \ + errorvar = code; \ + break; \ + } -/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +/*version of CERROR_BREAK that assumes the common case where the error variable + * is named "error"*/ #define ERROR_BREAK(code) CERROR_BREAK(error, code) /*Set error var to the error code, and return it.*/ -#define CERROR_RETURN_ERROR(errorvar, code){\ - errorvar = code;\ - return code;\ -} +#define CERROR_RETURN_ERROR(errorvar, code) \ + { \ + errorvar = code; \ + return code; \ + } /*Try the code, if it returns error, also return the error.*/ -#define CERROR_TRY_RETURN(call){\ - unsigned error = call;\ - if(error) return error;\ -} +#define CERROR_TRY_RETURN(call) \ + { \ + unsigned error = call; \ + if (error) \ + return error; \ + } /*Set error var to the error code, and return from the void function.*/ -#define CERROR_RETURN(errorvar, code){\ - errorvar = code;\ - return;\ -} +#define CERROR_RETURN(errorvar, code) \ + { \ + errorvar = code; \ + return; \ + } /* About uivector, ucvector and string: -All of them wrap dynamic arrays or text strings in a similar way. --LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. --The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. --They're not used in the interface, only internally in this file as static functions. --As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +-LodePNG was originally written in C++. The vectors replace the std::vectors +that were used in the C++ version. -The string tools are made to avoid problems +with compilers that declare things like strncat as deprecated. -They're not used +in the interface, only internally in this file as static functions. -As with +many other structs in this file, the init and cleanup functions serve as ctor +and dtor. */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_ENCODER /*dynamic vector of unsigned ints*/ typedef struct uivector { - unsigned* data; - size_t size; /*size in number of unsigned longs*/ + unsigned *data; + size_t size; /*size in number of unsigned longs*/ size_t allocsize; /*allocated size in bytes*/ } uivector; -static void uivector_cleanup(void* p) { - ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; - lodepng_free(((uivector*)p)->data); - ((uivector*)p)->data = NULL; +static void uivector_cleanup(void *p) { + ((uivector *)p)->size = ((uivector *)p)->allocsize = 0; + lodepng_free(((uivector *)p)->data); + ((uivector *)p)->data = NULL; } /*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned uivector_resize(uivector* p, size_t size) { +static unsigned uivector_resize(uivector *p, size_t size) { size_t allocsize = size * sizeof(unsigned); - if(allocsize > p->allocsize) { + if (allocsize > p->allocsize) { size_t newsize = allocsize + (p->allocsize >> 1u); - void* data = lodepng_realloc(p->data, newsize); - if(data) { + void *data = lodepng_realloc(p->data, newsize); + if (data) { p->allocsize = newsize; - p->data = (unsigned*)data; - } - else return 0; /*error: not enough memory*/ + p->data = (unsigned *)data; + } else + return 0; /*error: not enough memory*/ } p->size = size; return 1; /*success*/ } -static void uivector_init(uivector* p) { +static void uivector_init(uivector *p) { p->data = NULL; p->size = p->allocsize = 0; } /*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned uivector_push_back(uivector* p, unsigned c) { - if(!uivector_resize(p, p->size + 1)) return 0; +static unsigned uivector_push_back(uivector *p, unsigned c) { + if (!uivector_resize(p, p->size + 1)) + return 0; p->data[p->size - 1] = c; return 1; } #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ -/* /////////////////////////////////////////////////////////////////////////// */ +/* /////////////////////////////////////////////////////////////////////////// + */ /*dynamic vector of unsigned chars*/ typedef struct ucvector { - unsigned char* data; - size_t size; /*used size*/ + unsigned char *data; + size_t size; /*used size*/ size_t allocsize; /*allocated size*/ } ucvector; /*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned ucvector_resize(ucvector* p, size_t size) { - if(size > p->allocsize) { +static unsigned ucvector_resize(ucvector *p, size_t size) { + if (size > p->allocsize) { size_t newsize = size + (p->allocsize >> 1u); - void* data = lodepng_realloc(p->data, newsize); - if(data) { + void *data = lodepng_realloc(p->data, newsize); + if (data) { p->allocsize = newsize; - p->data = (unsigned char*)data; - } - else return 0; /*error: not enough memory*/ + p->data = (unsigned char *)data; + } else + return 0; /*error: not enough memory*/ } p->size = size; return 1; /*success*/ } -static ucvector ucvector_init(unsigned char* buffer, size_t size) { +static ucvector ucvector_init(unsigned char *buffer, size_t size) { ucvector v; v.data = buffer; v.allocsize = v.size = size; @@ -294,23 +315,24 @@ static ucvector ucvector_init(unsigned char* buffer, size_t size) { #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*free string pointer and set it to NULL*/ -static void string_cleanup(char** out) { +static void string_cleanup(char **out) { lodepng_free(*out); *out = NULL; } /*also appends null termination character*/ -static char* alloc_string_sized(const char* in, size_t insize) { - char* out = (char*)lodepng_malloc(insize + 1); - if(out) { +static char *alloc_string_sized(const char *in, size_t insize) { + char *out = (char *)lodepng_malloc(insize + 1); + if (out) { lodepng_memcpy(out, in, insize); out[insize] = 0; } return out; } -/* dynamically allocates a new string with a copy of the null terminated input text */ -static char* alloc_string(const char* in) { +/* dynamically allocates a new string with a copy of the null terminated input + * text */ +static char *alloc_string(const char *in) { return alloc_string_sized(in, lodepng_strlen(in)); } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ @@ -319,19 +341,19 @@ static char* alloc_string(const char* in) { /* ////////////////////////////////////////////////////////////////////////// */ #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG) -static unsigned lodepng_read32bitInt(const unsigned char* buffer) { +static unsigned lodepng_read32bitInt(const unsigned char *buffer) { return (((unsigned)buffer[0] << 24u) | ((unsigned)buffer[1] << 16u) | - ((unsigned)buffer[2] << 8u) | (unsigned)buffer[3]); + ((unsigned)buffer[2] << 8u) | (unsigned)buffer[3]); } #endif /*defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG)*/ #if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) /*buffer must have at least 4 allocated bytes available*/ -static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) { +static void lodepng_set32bitInt(unsigned char *buffer, unsigned value) { buffer[0] = (unsigned char)((value >> 24) & 0xff); buffer[1] = (unsigned char)((value >> 16) & 0xff); - buffer[2] = (unsigned char)((value >> 8) & 0xff); - buffer[3] = (unsigned char)((value ) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value)&0xff); } #endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ @@ -341,56 +363,69 @@ static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) { #ifdef LODEPNG_COMPILE_DISK -/* returns negative value on error. This should be pure C compatible, so no fstat. */ -static long lodepng_filesize(const char* filename) { - FILE* file; +/* returns negative value on error. This should be pure C compatible, so no + * fstat. */ +static long lodepng_filesize(const char *filename) { + FILE *file; long size; file = fopen(filename, "rb"); - if(!file) return -1; + if (!file) + return -1; - if(fseek(file, 0, SEEK_END) != 0) { + if (fseek(file, 0, SEEK_END) != 0) { fclose(file); return -1; } size = ftell(file); /* It may give LONG_MAX as directory size, this is invalid for us. */ - if(size == LONG_MAX) size = -1; + if (size == LONG_MAX) + size = -1; fclose(file); return size; } -/* load file into buffer that already has the correct allocated size. Returns error code.*/ -static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename) { - FILE* file; +/* load file into buffer that already has the correct allocated size. Returns + * error code.*/ +static unsigned lodepng_buffer_file(unsigned char *out, size_t size, + const char *filename) { + FILE *file; size_t readsize; file = fopen(filename, "rb"); - if(!file) return 78; + if (!file) + return 78; readsize = fread(out, 1, size, file); fclose(file); - if(readsize != size) return 78; + if (readsize != size) + return 78; return 0; } -unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) { +unsigned lodepng_load_file(unsigned char **out, size_t *outsize, + const char *filename) { long size = lodepng_filesize(filename); - if(size < 0) return 78; + if (size < 0) + return 78; *outsize = (size_t)size; - *out = (unsigned char*)lodepng_malloc((size_t)size); - if(!(*out) && size > 0) return 83; /*the above malloc failed*/ + *out = (unsigned char *)lodepng_malloc((size_t)size); + if (!(*out) && size > 0) + return 83; /*the above malloc failed*/ return lodepng_buffer_file(*out, (size_t)size, filename); } -/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ -unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) { - FILE* file; - file = fopen(filename, "wb" ); - if(!file) return 79; +/*write given buffer to the file, overwriting the file, it doesn't append to + * it.*/ +unsigned lodepng_save_file(const unsigned char *buffer, size_t buffersize, + const char *filename) { + FILE *file; + file = fopen(filename, "wb"); + if (!file) + return 79; fwrite(buffer, 1, buffersize, file); fclose(file); return 0; @@ -408,43 +443,49 @@ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const #ifdef LODEPNG_COMPILE_ENCODER typedef struct { - ucvector* data; + ucvector *data; unsigned char bp; /*ok to overflow, indicates bit pos inside byte*/ } LodePNGBitWriter; -static void LodePNGBitWriter_init(LodePNGBitWriter* writer, ucvector* data) { +static void LodePNGBitWriter_init(LodePNGBitWriter *writer, ucvector *data) { writer->data = data; writer->bp = 0; } /*TODO: this ignores potential out of memory errors*/ -#define WRITEBIT(writer, bit){\ - /* append new byte */\ - if(((writer->bp) & 7u) == 0) {\ - if(!ucvector_resize(writer->data, writer->data->size + 1)) return;\ - writer->data->data[writer->data->size - 1] = 0;\ - }\ - (writer->data->data[writer->data->size - 1]) |= (bit << ((writer->bp) & 7u));\ - ++writer->bp;\ -} +#define WRITEBIT(writer, bit) \ + { \ + /* append new byte */ \ + if (((writer->bp) & 7u) == 0) { \ + if (!ucvector_resize(writer->data, writer->data->size + 1)) \ + return; \ + writer->data->data[writer->data->size - 1] = 0; \ + } \ + (writer->data->data[writer->data->size - 1]) |= \ + (bit << ((writer->bp) & 7u)); \ + ++writer->bp; \ + } /* LSB of value is written first, and LSB of bytes is used first */ -static void writeBits(LodePNGBitWriter* writer, unsigned value, size_t nbits) { - if(nbits == 1) { /* compiler should statically compile this case if nbits == 1 */ +static void writeBits(LodePNGBitWriter *writer, unsigned value, size_t nbits) { + if (nbits == + 1) { /* compiler should statically compile this case if nbits == 1 */ WRITEBIT(writer, value); } else { /* TODO: increase output size only once here rather than in each WRITEBIT */ size_t i; - for(i = 0; i != nbits; ++i) { + for (i = 0; i != nbits; ++i) { WRITEBIT(writer, (unsigned char)((value >> i) & 1)); } } } -/* This one is to use for adding huffman symbol, the value bits are written MSB first */ -static void writeBitsReversed(LodePNGBitWriter* writer, unsigned value, size_t nbits) { +/* This one is to use for adding huffman symbol, the value bits are written MSB + * first */ +static void writeBitsReversed(LodePNGBitWriter *writer, unsigned value, + size_t nbits) { size_t i; - for(i = 0; i != nbits; ++i) { + for (i = 0; i != nbits; ++i) { /* TODO: increase output size only once here rather than in each WRITEBIT */ WRITEBIT(writer, (unsigned char)((value >> (nbits - 1u - i)) & 1u)); } @@ -454,23 +495,30 @@ static void writeBitsReversed(LodePNGBitWriter* writer, unsigned value, size_t n #ifdef LODEPNG_COMPILE_DECODER typedef struct { - const unsigned char* data; - size_t size; /*size of data in bytes*/ - size_t bitsize; /*size of data in bits, end of valid bp values, should be 8*size*/ + const unsigned char *data; + size_t size; /*size of data in bytes*/ + size_t bitsize; /*size of data in bits, end of valid bp values, should be + 8*size*/ size_t bp; - unsigned buffer; /*buffer for reading bits. NOTE: 'unsigned' must support at least 32 bits*/ + unsigned buffer; /*buffer for reading bits. NOTE: 'unsigned' must support at + least 32 bits*/ } LodePNGBitReader; -/* data size argument is in bytes. Returns error if size too large causing overflow */ -static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned char* data, size_t size) { +/* data size argument is in bytes. Returns error if size too large causing + * overflow */ +static unsigned LodePNGBitReader_init(LodePNGBitReader *reader, + const unsigned char *data, size_t size) { size_t temp; reader->data = data; reader->size = size; - /* size in bits, return error if overflow (if size_t is 32 bit this supports up to 500MB) */ - if(lodepng_mulofl(size, 8u, &reader->bitsize)) return 105; - /*ensure incremented bp can be compared to bitsize without overflow even when it would be incremented 32 too much and - trying to ensure 32 more bits*/ - if(lodepng_addofl(reader->bitsize, 64u, &temp)) return 105; + /* size in bits, return error if overflow (if size_t is 32 bit this supports + * up to 500MB) */ + if (lodepng_mulofl(size, 8u, &reader->bitsize)) + return 105; + /*ensure incremented bp can be compared to bitsize without overflow even when + it would be incremented 32 too much and trying to ensure 32 more bits*/ + if (lodepng_addofl(reader->bitsize, 64u, &temp)) + return 105; reader->bp = 0; reader->buffer = 0; return 0; /*ok*/ @@ -486,118 +534,145 @@ Returns 1 if there are enough bits available, 0 if not. /*See ensureBits documentation above. This one ensures exactly 1 bit */ /*static unsigned ensureBits1(LodePNGBitReader* reader) { if(reader->bp >= reader->bitsize) return 0; - reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & 7u); - return 1; + reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & +7u); return 1; }*/ /*See ensureBits documentation above. This one ensures up to 9 bits */ -static unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits) { +static unsigned ensureBits9(LodePNGBitReader *reader, size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; - if(start + 1u < size) { - reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u); + if (start + 1u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | + ((unsigned)reader->data[start + 1] << 8u); reader->buffer >>= (reader->bp & 7u); return 1; } else { reader->buffer = 0; - if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if (start + 0u < size) + reader->buffer |= reader->data[start + 0]; reader->buffer >>= (reader->bp & 7u); return reader->bp + nbits <= reader->bitsize; } } /*See ensureBits documentation above. This one ensures up to 17 bits */ -static unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits) { +static unsigned ensureBits17(LodePNGBitReader *reader, size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; - if(start + 2u < size) { - reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | + if (start + 2u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | + ((unsigned)reader->data[start + 1] << 8u) | ((unsigned)reader->data[start + 2] << 16u); reader->buffer >>= (reader->bp & 7u); return 1; } else { reader->buffer = 0; - if(start + 0u < size) reader->buffer |= reader->data[start + 0]; - if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + if (start + 0u < size) + reader->buffer |= reader->data[start + 0]; + if (start + 1u < size) + reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); reader->buffer >>= (reader->bp & 7u); return reader->bp + nbits <= reader->bitsize; } } /*See ensureBits documentation above. This one ensures up to 25 bits */ -static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader *reader, + size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; - if(start + 3u < size) { - reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | - ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); + if (start + 3u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | + ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u) | + ((unsigned)reader->data[start + 3] << 24u); reader->buffer >>= (reader->bp & 7u); return 1; } else { reader->buffer = 0; - if(start + 0u < size) reader->buffer |= reader->data[start + 0]; - if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); - if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); + if (start + 0u < size) + reader->buffer |= reader->data[start + 0]; + if (start + 1u < size) + reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + if (start + 2u < size) + reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); reader->buffer >>= (reader->bp & 7u); return reader->bp + nbits <= reader->bitsize; } } /*See ensureBits documentation above. This one ensures up to 32 bits */ -static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits) { +static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader *reader, + size_t nbits) { size_t start = reader->bp >> 3u; size_t size = reader->size; - if(start + 4u < size) { - reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | - ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); + if (start + 4u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | + ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u) | + ((unsigned)reader->data[start + 3] << 24u); reader->buffer >>= (reader->bp & 7u); - reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u))); + reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) + << (8u - (reader->bp & 7u))); return 1; } else { reader->buffer = 0; - if(start + 0u < size) reader->buffer |= reader->data[start + 0]; - if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); - if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); - if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u); + if (start + 0u < size) + reader->buffer |= reader->data[start + 0]; + if (start + 1u < size) + reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + if (start + 2u < size) + reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); + if (start + 3u < size) + reader->buffer |= ((unsigned)reader->data[start + 3] << 24u); reader->buffer >>= (reader->bp & 7u); return reader->bp + nbits <= reader->bitsize; } } -/* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */ -static unsigned peekBits(LodePNGBitReader* reader, size_t nbits) { +/* Get bits without advancing the bit pointer. Must have enough bits available + * with ensureBits. Max nbits is 31. */ +static unsigned peekBits(LodePNGBitReader *reader, size_t nbits) { /* The shift allows nbits to be only up to 31. */ return reader->buffer & ((1u << nbits) - 1u); } /* Must have enough bits available with ensureBits */ -static void advanceBits(LodePNGBitReader* reader, size_t nbits) { +static void advanceBits(LodePNGBitReader *reader, size_t nbits) { reader->buffer >>= nbits; reader->bp += nbits; } /* Must have enough bits available with ensureBits */ -static unsigned readBits(LodePNGBitReader* reader, size_t nbits) { +static unsigned readBits(LodePNGBitReader *reader, size_t nbits) { unsigned result = peekBits(reader, nbits); advanceBits(reader, nbits); return result; } /* Public for testing only. steps and result must have numsteps values. */ -unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, - size_t numsteps, const size_t* steps, unsigned* result) { +unsigned lode_png_test_bitreader(const unsigned char *data, size_t size, + size_t numsteps, const size_t *steps, + unsigned *result) { size_t i; LodePNGBitReader reader; unsigned error = LodePNGBitReader_init(&reader, data, size); - if(error) return 0; - for(i = 0; i < numsteps; i++) { + if (error) + return 0; + for (i = 0; i < numsteps; i++) { size_t step = steps[i]; unsigned ok; - if(step > 25) ok = ensureBits32(&reader, step); - else if(step > 17) ok = ensureBits25(&reader, step); - else if(step > 9) ok = ensureBits17(&reader, step); - else ok = ensureBits9(&reader, step); - if(!ok) return 0; + if (step > 25) + ok = ensureBits32(&reader, step); + else if (step > 17) + ok = ensureBits25(&reader, step); + else if (step > 9) + ok = ensureBits17(&reader, step); + else + ok = ensureBits9(&reader, step); + if (!ok) + return 0; result[i] = readBits(&reader, step); } return 1; @@ -607,7 +682,8 @@ unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, static unsigned reverseBits(unsigned bits, unsigned num) { /*TODO: implement faster lookup table based version when needed*/ unsigned i, result = 0; - for(i = 0; i < num; i++) result |= ((bits >> (num - i - 1u)) & 1u) << i; + for (i = 0; i < num; i++) + result |= ((bits >> (num - i - 1u)) & 1u) << i; return result; } @@ -621,33 +697,37 @@ static unsigned reverseBits(unsigned bits, unsigned num) { #define NUM_DEFLATE_CODE_SYMBOLS 288 /*the distance codes have their own symbols, 30 used, 2 unused*/ #define NUM_DISTANCE_SYMBOLS 32 -/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: + * 3-10 zeros, 18: 11-138 zeros*/ #define NUM_CODE_LENGTH_CODES 19 /*the base lengths represented by codes 257-285*/ -static const unsigned LENGTHBASE[29] - = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, - 67, 83, 99, 115, 131, 163, 195, 227, 258}; +static const unsigned LENGTHBASE[29] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, + 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; /*the extra bits used by codes 257-285 (added to base length)*/ -static const unsigned LENGTHEXTRA[29] - = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 5, 5, 5, 5, 0}; +static const unsigned LENGTHEXTRA[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; -/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ -static const unsigned DISTANCEBASE[30] - = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, - 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; +/*the base backwards distances (the bits of distance codes appear after length + * codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, + 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, + 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; /*the extra bits of backwards distances (added to base)*/ -static const unsigned DISTANCEEXTRA[30] - = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, - 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; +static const unsigned DISTANCEEXTRA[30] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; -/*the order in which "code length alphabet code lengths" are stored as specified by deflate, out of this the huffman -tree of the dynamic huffman tree lengths is generated*/ -static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] - = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +/*the order in which "code length alphabet code lengths" are stored as specified +by deflate, out of this the huffman tree of the dynamic huffman tree lengths is +generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* ////////////////////////////////////////////////////////////////////////// */ @@ -655,116 +735,145 @@ static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] Huffman tree struct, containing multiple representations of the tree */ typedef struct HuffmanTree { - unsigned* codes; /*the huffman codes (bit patterns representing the symbols)*/ - unsigned* lengths; /*the lengths of the huffman codes*/ + unsigned *codes; /*the huffman codes (bit patterns representing the symbols)*/ + unsigned *lengths; /*the lengths of the huffman codes*/ unsigned maxbitlen; /*maximum number of bits a single code can get*/ - unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ /* for reading only */ - unsigned char* table_len; /*length of symbol from lookup table, or max length if secondary lookup needed*/ - unsigned short* table_value; /*value of symbol from lookup table, or pointer to secondary table if needed*/ + unsigned char *table_len; /*length of symbol from lookup table, or max length + if secondary lookup needed*/ + unsigned short *table_value; /*value of symbol from lookup table, or pointer + to secondary table if needed*/ } HuffmanTree; -static void HuffmanTree_init(HuffmanTree* tree) { +static void HuffmanTree_init(HuffmanTree *tree) { tree->codes = 0; tree->lengths = 0; tree->table_len = 0; tree->table_value = 0; } -static void HuffmanTree_cleanup(HuffmanTree* tree) { +static void HuffmanTree_cleanup(HuffmanTree *tree) { lodepng_free(tree->codes); lodepng_free(tree->lengths); lodepng_free(tree->table_len); lodepng_free(tree->table_value); } -/* amount of bits for first huffman table lookup (aka root bits), see HuffmanTree_makeTable and huffmanDecodeSymbol.*/ +/* amount of bits for first huffman table lookup (aka root bits), see + * HuffmanTree_makeTable and huffmanDecodeSymbol.*/ /* values 8u and 9u work the fastest */ #define FIRSTBITS 9u -/* a symbol value too big to represent any valid symbol, to indicate reading disallowed huffman bits combination, -which is possible in case of only 0 or 1 present symbols. */ +/* a symbol value too big to represent any valid symbol, to indicate reading +disallowed huffman bits combination, which is possible in case of only 0 or 1 +present symbols. */ #define INVALIDSYMBOL 65535u /* make table for huffman decoding */ -static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { +static unsigned HuffmanTree_makeTable(HuffmanTree *tree) { static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/ static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u; size_t i, numpresent, pointer, size; /*total table size*/ - unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned)); - if(!maxlens) return 83; /*alloc fail*/ + unsigned *maxlens = (unsigned *)lodepng_malloc(headsize * sizeof(unsigned)); + if (!maxlens) + return 83; /*alloc fail*/ - /* compute maxlens: max total bit length of symbols sharing prefix in the first table*/ + /* compute maxlens: max total bit length of symbols sharing prefix in the + * first table*/ lodepng_memset(maxlens, 0, headsize * sizeof(*maxlens)); - for(i = 0; i < tree->numcodes; i++) { + for (i = 0; i < tree->numcodes; i++) { unsigned symbol = tree->codes[i]; unsigned l = tree->lengths[i]; unsigned index; - if(l <= FIRSTBITS) continue; /*symbols that fit in first table don't increase secondary table size*/ - /*get the FIRSTBITS MSBs, the MSBs of the symbol are encoded first. See later comment about the reversing*/ + if (l <= FIRSTBITS) + continue; /*symbols that fit in first table don't increase secondary table + size*/ + /*get the FIRSTBITS MSBs, the MSBs of the symbol are encoded first. See + * later comment about the reversing*/ index = reverseBits(symbol >> (l - FIRSTBITS), FIRSTBITS); maxlens[index] = LODEPNG_MAX(maxlens[index], l); } - /* compute total table size: size of first table plus all secondary tables for symbols longer than FIRSTBITS */ + /* compute total table size: size of first table plus all secondary tables for + * symbols longer than FIRSTBITS */ size = headsize; - for(i = 0; i < headsize; ++i) { + for (i = 0; i < headsize; ++i) { unsigned l = maxlens[i]; - if(l > FIRSTBITS) size += (1u << (l - FIRSTBITS)); + if (l > FIRSTBITS) + size += (1u << (l - FIRSTBITS)); } - tree->table_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len)); - tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value)); - if(!tree->table_len || !tree->table_value) { + tree->table_len = + (unsigned char *)lodepng_malloc(size * sizeof(*tree->table_len)); + tree->table_value = + (unsigned short *)lodepng_malloc(size * sizeof(*tree->table_value)); + if (!tree->table_len || !tree->table_value) { lodepng_free(maxlens); /* freeing tree->table values is done at a higher scope */ return 83; /*alloc fail*/ } /*initialize with an invalid length to indicate unused entries*/ - for(i = 0; i < size; ++i) tree->table_len[i] = 16; + for (i = 0; i < size; ++i) + tree->table_len[i] = 16; - /*fill in the first table for long symbols: max prefix size and pointer to secondary tables*/ + /*fill in the first table for long symbols: max prefix size and pointer to + * secondary tables*/ pointer = headsize; - for(i = 0; i < headsize; ++i) { + for (i = 0; i < headsize; ++i) { unsigned l = maxlens[i]; - if(l <= FIRSTBITS) continue; + if (l <= FIRSTBITS) + continue; tree->table_len[i] = l; tree->table_value[i] = pointer; pointer += (1u << (l - FIRSTBITS)); } lodepng_free(maxlens); - /*fill in the first table for short symbols, or secondary table for long symbols*/ + /*fill in the first table for short symbols, or secondary table for long + * symbols*/ numpresent = 0; - for(i = 0; i < tree->numcodes; ++i) { + for (i = 0; i < tree->numcodes; ++i) { unsigned l = tree->lengths[i]; - unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/ - /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/ + unsigned symbol = + tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/ + /*reverse bits, because the huffman bits are given in MSB first order but + * the bit reader reads LSB first*/ unsigned reverse = reverseBits(symbol, l); - if(l == 0) continue; + if (l == 0) + continue; numpresent++; - if(l <= FIRSTBITS) { - /*short symbol, fully in first table, replicated num times if l < FIRSTBITS*/ + if (l <= FIRSTBITS) { + /*short symbol, fully in first table, replicated num times if l < + * FIRSTBITS*/ unsigned num = 1u << (FIRSTBITS - l); unsigned j; - for(j = 0; j < num; ++j) { - /*bit reader will read the l bits of symbol first, the remaining FIRSTBITS - l bits go to the MSB's*/ + for (j = 0; j < num; ++j) { + /*bit reader will read the l bits of symbol first, the remaining + * FIRSTBITS - l bits go to the MSB's*/ unsigned index = reverse | (j << l); - if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/ + if (tree->table_len[index] != 16) + return 55; /*invalid tree: long symbol shares prefix with short + symbol*/ tree->table_len[index] = l; tree->table_value[index] = i; } } else { - /*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/ + /*long symbol, shares prefix with other long symbols in first lookup + * table, needs second lookup*/ /*the FIRSTBITS MSBs of the symbol are the first table index*/ unsigned index = reverse & mask; unsigned maxlen = tree->table_len[index]; /*log2 of secondary table length, should be >= l - FIRSTBITS*/ unsigned tablelen = maxlen - FIRSTBITS; - unsigned start = tree->table_value[index]; /*starting index in secondary table*/ - unsigned num = 1u << (tablelen - (l - FIRSTBITS)); /*amount of entries of this symbol in secondary table*/ + unsigned start = + tree->table_value[index]; /*starting index in secondary table*/ + unsigned num = + 1u << (tablelen - (l - FIRSTBITS)); /*amount of entries of this symbol + in secondary table*/ unsigned j; - if(maxlen < l) return 55; /*invalid tree: long symbol shares prefix with short symbol*/ - for(j = 0; j < num; ++j) { + if (maxlen < l) + return 55; /*invalid tree: long symbol shares prefix with short symbol*/ + for (j = 0; j < num; ++j) { unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */ unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS))); tree->table_len[index2] = l; @@ -773,15 +882,15 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { } } - if(numpresent < 2) { + if (numpresent < 2) { /* In case of exactly 1 symbol, in theory the huffman symbol needs 0 bits, but deflate uses 1 bit instead. In case of 0 symbols, no symbols can appear at all, but such huffman tree could still exist (e.g. if distance codes are never used). In both cases, not all symbols of the table will be filled in. Fill them in with an invalid symbol value so returning them from huffmanDecodeSymbol will cause error. */ - for(i = 0; i < size; ++i) { - if(tree->table_len[i] == 16) { + for (i = 0; i < size; ++i) { + if (tree->table_len[i] == 16) { /* As length, use a value smaller than FIRSTBITS for the head table, and a value larger than FIRSTBITS for the secondary table, to ensure valid behavior for advanceBits when reading this symbol. */ @@ -790,12 +899,14 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { } } } else { - /* A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. - If that is not the case (due to too long length codes), the table will not - have been fully used, and this is an error (not all bit combinations can be - decoded): an oversubscribed huffman tree, indicated by error 55. */ - for(i = 0; i < size; ++i) { - if(tree->table_len[i] == 16) return 55; + /* A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal + nodes. If that is not the case (due to too long length codes), the table + will not have been fully used, and this is an error (not all bit + combinations can be decoded): an oversubscribed huffman tree, indicated by + error 55. */ + for (i = 0; i < size; ++i) { + if (tree->table_len[i] == 16) + return 55; } } @@ -807,28 +918,33 @@ Second step for the ...makeFromLengths and ...makeFromFrequencies functions. numcodes, lengths and maxbitlen must already be filled in correctly. return value is error. */ -static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) { - unsigned* blcount; - unsigned* nextcode; +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree *tree) { + unsigned *blcount; + unsigned *nextcode; unsigned error = 0; unsigned bits, n; - tree->codes = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); - blcount = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); - nextcode = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); - if(!tree->codes || !blcount || !nextcode) error = 83; /*alloc fail*/ + tree->codes = (unsigned *)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + blcount = + (unsigned *)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); + nextcode = + (unsigned *)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); + if (!tree->codes || !blcount || !nextcode) + error = 83; /*alloc fail*/ - if(!error) { - for(n = 0; n != tree->maxbitlen + 1; n++) blcount[n] = nextcode[n] = 0; + if (!error) { + for (n = 0; n != tree->maxbitlen + 1; n++) + blcount[n] = nextcode[n] = 0; /*step 1: count number of instances of each code length*/ - for(bits = 0; bits != tree->numcodes; ++bits) ++blcount[tree->lengths[bits]]; + for (bits = 0; bits != tree->numcodes; ++bits) + ++blcount[tree->lengths[bits]]; /*step 2: generate the nextcode values*/ - for(bits = 1; bits <= tree->maxbitlen; ++bits) { + for (bits = 1; bits <= tree->maxbitlen; ++bits) { nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1u; } /*step 3: generate all the codes*/ - for(n = 0; n != tree->numcodes; ++n) { - if(tree->lengths[n] != 0) { + for (n = 0; n != tree->numcodes; ++n) { + if (tree->lengths[n] != 0) { tree->codes[n] = nextcode[tree->lengths[n]]++; /*remove superfluous bits from the code*/ tree->codes[n] &= ((1u << tree->lengths[n]) - 1u); @@ -839,7 +955,8 @@ static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) { lodepng_free(blcount); lodepng_free(nextcode); - if(!error) error = HuffmanTree_makeTable(tree); + if (!error) + error = HuffmanTree_makeTable(tree); return error; } @@ -848,12 +965,16 @@ given the code lengths (as stored in the PNG file), generate the tree as defined by Deflate. maxbitlen is the maximum bits that a code in the tree can have. return value is error. */ -static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, - size_t numcodes, unsigned maxbitlen) { +static unsigned HuffmanTree_makeFromLengths(HuffmanTree *tree, + const unsigned *bitlen, + size_t numcodes, + unsigned maxbitlen) { unsigned i; - tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); - if(!tree->lengths) return 83; /*alloc fail*/ - for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; + tree->lengths = (unsigned *)lodepng_malloc(numcodes * sizeof(unsigned)); + if (!tree->lengths) + return 83; /*alloc fail*/ + for (i = 0; i != numcodes; ++i) + tree->lengths[i] = bitlen[i]; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ tree->maxbitlen = maxbitlen; return HuffmanTree_makeFromLengths2(tree); @@ -861,14 +982,15 @@ static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* b #ifdef LODEPNG_COMPILE_ENCODER -/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", -Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ +/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for +Length-Limited Coding", Jyrki Katajainen, Alistair Moffat, Andrew Turpin, +1995.*/ /*chain node for boundary package merge*/ typedef struct BPMNode { - int weight; /*the sum of all weights in this chain*/ + int weight; /*the sum of all weights in this chain*/ unsigned index; /*index of this leaf node (called "count" in the paper)*/ - struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ + struct BPMNode *tail; /*the next nodes in this chain (null if last)*/ int in_use; } BPMNode; @@ -876,34 +998,40 @@ typedef struct BPMNode { typedef struct BPMLists { /*memory pool*/ unsigned memsize; - BPMNode* memory; + BPMNode *memory; unsigned numfree; unsigned nextfree; - BPMNode** freelist; + BPMNode **freelist; /*two heads of lookahead chains per list*/ unsigned listsize; - BPMNode** chains0; - BPMNode** chains1; + BPMNode **chains0; + BPMNode **chains1; } BPMLists; -/*creates a new chain node with the given parameters, from the memory in the lists */ -static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) { +/*creates a new chain node with the given parameters, from the memory in the + * lists */ +static BPMNode *bpmnode_create(BPMLists *lists, int weight, unsigned index, + BPMNode *tail) { unsigned i; - BPMNode* result; + BPMNode *result; /*memory full, so garbage collect*/ - if(lists->nextfree >= lists->numfree) { + if (lists->nextfree >= lists->numfree) { /*mark only those that are in use*/ - for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; - for(i = 0; i != lists->listsize; ++i) { - BPMNode* node; - for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; - for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; + for (i = 0; i != lists->memsize; ++i) + lists->memory[i].in_use = 0; + for (i = 0; i != lists->listsize; ++i) { + BPMNode *node; + for (node = lists->chains0[i]; node != 0; node = node->tail) + node->in_use = 1; + for (node = lists->chains1[i]; node != 0; node = node->tail) + node->in_use = 1; } /*collect those that are free*/ lists->numfree = 0; - for(i = 0; i != lists->memsize; ++i) { - if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; + for (i = 0; i != lists->memsize; ++i) { + if (!lists->memory[i].in_use) + lists->freelist[lists->numfree++] = &lists->memory[i]; } lists->nextfree = 0; } @@ -916,69 +1044,83 @@ static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMN } /*sort the leaves with stable mergesort*/ -static void bpmnode_sort(BPMNode* leaves, size_t num) { - BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num); +static void bpmnode_sort(BPMNode *leaves, size_t num) { + BPMNode *mem = (BPMNode *)lodepng_malloc(sizeof(*leaves) * num); size_t width, counter = 0; - for(width = 1; width < num; width *= 2) { - BPMNode* a = (counter & 1) ? mem : leaves; - BPMNode* b = (counter & 1) ? leaves : mem; + for (width = 1; width < num; width *= 2) { + BPMNode *a = (counter & 1) ? mem : leaves; + BPMNode *b = (counter & 1) ? leaves : mem; size_t p; - for(p = 0; p < num; p += 2 * width) { + for (p = 0; p < num; p += 2 * width) { size_t q = (p + width > num) ? num : (p + width); size_t r = (p + 2 * width > num) ? num : (p + 2 * width); size_t i = p, j = q, k; - for(k = p; k < r; k++) { - if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++]; - else b[k] = a[j++]; + for (k = p; k < r; k++) { + if (i < q && (j >= r || a[i].weight <= a[j].weight)) + b[k] = a[i++]; + else + b[k] = a[j++]; } } counter++; } - if(counter & 1) lodepng_memcpy(leaves, mem, sizeof(*leaves) * num); + if (counter & 1) + lodepng_memcpy(leaves, mem, sizeof(*leaves) * num); lodepng_free(mem); } -/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ -static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) { +/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the + * current chain.*/ +static void boundaryPM(BPMLists *lists, BPMNode *leaves, size_t numpresent, + int c, int num) { unsigned lastindex = lists->chains1[c]->index; - if(c == 0) { - if(lastindex >= numpresent) return; + if (c == 0) { + if (lastindex >= numpresent) + return; lists->chains0[c] = lists->chains1[c]; - lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); + lists->chains1[c] = + bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); } else { /*sum of the weights of the head nodes of the previous lookahead chains.*/ int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; lists->chains0[c] = lists->chains1[c]; - if(lastindex < numpresent && sum > leaves[lastindex].weight) { - lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); + if (lastindex < numpresent && sum > leaves[lastindex].weight) { + lists->chains1[c] = + bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, + lists->chains1[c]->tail); return; } - lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); + lists->chains1[c] = + bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); /*in the end we are only interested in the chain of the last list, so no need to recurse if we're at the last one (this gives measurable speedup)*/ - if(num + 1 < (int)(2 * numpresent - 2)) { + if (num + 1 < (int)(2 * numpresent - 2)) { boundaryPM(lists, leaves, numpresent, c - 1, num); boundaryPM(lists, leaves, numpresent, c - 1, num); } } } -unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, +unsigned lodepng_huffman_code_lengths(unsigned *lengths, + const unsigned *frequencies, size_t numcodes, unsigned maxbitlen) { unsigned error = 0; unsigned i; size_t numpresent = 0; /*number of symbols with non-zero frequency*/ - BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ + BPMNode *leaves; /*the symbols, only those with > 0 frequency*/ - if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ - if((1u << maxbitlen) < (unsigned)numcodes) return 80; /*error: represent all symbols*/ + if (numcodes == 0) + return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + if ((1u << maxbitlen) < (unsigned)numcodes) + return 80; /*error: represent all symbols*/ - leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); - if(!leaves) return 83; /*alloc fail*/ + leaves = (BPMNode *)lodepng_malloc(numcodes * sizeof(*leaves)); + if (!leaves) + return 83; /*alloc fail*/ - for(i = 0; i != numcodes; ++i) { - if(frequencies[i] > 0) { + for (i = 0; i != numcodes; ++i) { + if (frequencies[i] > 0) { leaves[numpresent].weight = (int)frequencies[i]; leaves[numpresent].index = i; ++numpresent; @@ -992,14 +1134,15 @@ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequen make these work as well ensure there are at least two symbols. The Package-Merge code below also doesn't work correctly if there's only one symbol, it'd give it the theoretical 0 bits but in practice zlib wants 1 bit*/ - if(numpresent == 0) { - lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ - } else if(numpresent == 1) { + if (numpresent == 0) { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only + lengths[0] = 1 is needed*/ + } else if (numpresent == 1) { lengths[leaves[0].index] = 1; lengths[leaves[0].index == 0 ? 1 : 0] = 1; } else { BPMLists lists; - BPMNode* node; + BPMNode *node; bpmnode_sort(leaves, numpresent); @@ -1007,28 +1150,37 @@ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequen lists.memsize = 2 * maxbitlen * (maxbitlen + 1); lists.nextfree = 0; lists.numfree = lists.memsize; - lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); - lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); - lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); - lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); - if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ + lists.memory = + (BPMNode *)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); + lists.freelist = + (BPMNode **)lodepng_malloc(lists.memsize * sizeof(BPMNode *)); + lists.chains0 = + (BPMNode **)lodepng_malloc(lists.listsize * sizeof(BPMNode *)); + lists.chains1 = + (BPMNode **)lodepng_malloc(lists.listsize * sizeof(BPMNode *)); + if (!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) + error = 83; /*alloc fail*/ - if(!error) { - for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; + if (!error) { + for (i = 0; i != lists.memsize; ++i) + lists.freelist[i] = &lists.memory[i]; bpmnode_create(&lists, leaves[0].weight, 1, 0); bpmnode_create(&lists, leaves[1].weight, 2, 0); - for(i = 0; i != lists.listsize; ++i) { + for (i = 0; i != lists.listsize; ++i) { lists.chains0[i] = &lists.memory[0]; lists.chains1[i] = &lists.memory[1]; } - /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ - for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); + /*each boundaryPM call adds one chain to the last list, and we need 2 * + * numpresent - 2 chains.*/ + for (i = 2; i != 2 * numpresent - 2; ++i) + boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); - for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) { - for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; + for (node = lists.chains1[maxbitlen - 1]; node; node = node->tail) { + for (i = 0; i != node->index; ++i) + ++lengths[leaves[i].index]; } } @@ -1043,47 +1195,67 @@ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequen } /*Create the Huffman tree given the symbol frequencies*/ -static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, - size_t mincodes, size_t numcodes, unsigned maxbitlen) { +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree *tree, + const unsigned *frequencies, + size_t mincodes, + size_t numcodes, + unsigned maxbitlen) { unsigned error = 0; - while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ - tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); - if(!tree->lengths) return 83; /*alloc fail*/ + while (!frequencies[numcodes - 1] && numcodes > mincodes) + --numcodes; /*trim zeroes*/ + tree->lengths = (unsigned *)lodepng_malloc(numcodes * sizeof(unsigned)); + if (!tree->lengths) + return 83; /*alloc fail*/ tree->maxbitlen = maxbitlen; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ - error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); - if(!error) error = HuffmanTree_makeFromLengths2(tree); + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, + maxbitlen); + if (!error) + error = HuffmanTree_makeFromLengths2(tree); return error; } #endif /*LODEPNG_COMPILE_ENCODER*/ -/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ -static unsigned generateFixedLitLenTree(HuffmanTree* tree) { +/*get the literal and length code tree of a deflated block with fixed tree, as + * per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree *tree) { unsigned i, error = 0; - unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); - if(!bitlen) return 83; /*alloc fail*/ + unsigned *bitlen = + (unsigned *)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if (!bitlen) + return 83; /*alloc fail*/ - /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ - for(i = 0; i <= 143; ++i) bitlen[i] = 8; - for(i = 144; i <= 255; ++i) bitlen[i] = 9; - for(i = 256; i <= 279; ++i) bitlen[i] = 7; - for(i = 280; i <= 287; ++i) bitlen[i] = 8; + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, + * 286-287=unused*/ + for (i = 0; i <= 143; ++i) + bitlen[i] = 8; + for (i = 144; i <= 255; ++i) + bitlen[i] = 9; + for (i = 256; i <= 279; ++i) + bitlen[i] = 7; + for (i = 280; i <= 287; ++i) + bitlen[i] = 8; - error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + error = + HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); lodepng_free(bitlen); return error; } -/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ -static unsigned generateFixedDistanceTree(HuffmanTree* tree) { +/*get the distance code tree of a deflated block with fixed tree, as specified + * in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree *tree) { unsigned i, error = 0; - unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); - if(!bitlen) return 83; /*alloc fail*/ + unsigned *bitlen = + (unsigned *)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if (!bitlen) + return 83; /*alloc fail*/ /*there are 32 distance codes, but 30-31 are unused*/ - for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; + for (i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) + bitlen[i] = 5; error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); lodepng_free(bitlen); @@ -1095,11 +1267,12 @@ static unsigned generateFixedDistanceTree(HuffmanTree* tree) { /* returns the code. The bit reader must already have been ensured at least 15 bits */ -static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree* codetree) { +static unsigned huffmanDecodeSymbol(LodePNGBitReader *reader, + const HuffmanTree *codetree) { unsigned short code = peekBits(reader, FIRSTBITS); unsigned short l = codetree->table_len[code]; unsigned short value = codetree->table_value[code]; - if(l <= FIRSTBITS) { + if (l <= FIRSTBITS) { advanceBits(reader, l); return value; } else { @@ -1118,135 +1291,179 @@ static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree* /* / Inflator (Decompressor) / */ /* ////////////////////////////////////////////////////////////////////////// */ -/*get the tree of a deflated block with fixed tree, as specified in the deflate specification -Returns error code.*/ -static unsigned getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) { +/*get the tree of a deflated block with fixed tree, as specified in the deflate +specification Returns error code.*/ +static unsigned getTreeInflateFixed(HuffmanTree *tree_ll, HuffmanTree *tree_d) { unsigned error = generateFixedLitLenTree(tree_ll); - if(error) return error; + if (error) + return error; return generateFixedDistanceTree(tree_d); } -/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ -static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, - LodePNGBitReader* reader) { - /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ +/*get the tree of a deflated block with dynamic tree, the tree itself is also + * Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree *tree_ll, HuffmanTree *tree_d, + LodePNGBitReader *reader) { + /*make sure that length values that aren't filled in will be 0, or a wrong + * tree will be generated*/ unsigned error = 0; unsigned n, HLIT, HDIST, HCLEN, i; - /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ - unsigned* bitlen_ll = 0; /*lit,len code lengths*/ - unsigned* bitlen_d = 0; /*dist code lengths*/ - /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ - unsigned* bitlen_cl = 0; - HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + /*see comments in deflateDynamic for explanation of the context and these + * variables, it is analogous*/ + unsigned *bitlen_ll = 0; /*lit,len code lengths*/ + unsigned *bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used + * to compress bitlen_ll and bitlen_d*/ + unsigned *bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree + for compressed huffman trees)*/ - if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/ + if (!ensureBits17(reader, 14)) + return 49; /*error: the bit pointer is or will go past the memory*/ - /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ - HLIT = readBits(reader, 5) + 257; - /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + /*number of literal/length codes + 257. Unlike the spec, the value 257 is + * added to it here already*/ + HLIT = readBits(reader, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here + * already*/ HDIST = readBits(reader, 5) + 1; - /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + /*number of code length codes. Unlike the spec, the value 4 is added to it + * here already*/ HCLEN = readBits(reader, 4) + 4; - bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); - if(!bitlen_cl) return 83 /*alloc fail*/; + bitlen_cl = + (unsigned *)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if (!bitlen_cl) + return 83 /*alloc fail*/; HuffmanTree_init(&tree_cl); - while(!error) { + while (!error) { /*read the code length codes out of 3 * (amount of code length codes) bits*/ - if(lodepng_gtofl(reader->bp, HCLEN * 3, reader->bitsize)) { + if (lodepng_gtofl(reader->bp, HCLEN * 3, reader->bitsize)) { ERROR_BREAK(50); /*error: the bit pointer is or will go past the memory*/ } - for(i = 0; i != HCLEN; ++i) { + for (i = 0; i != HCLEN; ++i) { ensureBits9(reader, 3); /*out of bounds already checked above */ bitlen_cl[CLCL_ORDER[i]] = readBits(reader, 3); } - for(i = HCLEN; i != NUM_CODE_LENGTH_CODES; ++i) { + for (i = HCLEN; i != NUM_CODE_LENGTH_CODES; ++i) { bitlen_cl[CLCL_ORDER[i]] = 0; } - error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); - if(error) break; + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, + NUM_CODE_LENGTH_CODES, 7); + if (error) + break; - /*now we can use this tree to read the lengths for the tree that this function will return*/ - bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); - bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); - if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + /*now we can use this tree to read the lengths for the tree that this + * function will return*/ + bitlen_ll = + (unsigned *)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = + (unsigned *)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if (!bitlen_ll || !bitlen_d) + ERROR_BREAK(83 /*alloc fail*/); lodepng_memset(bitlen_ll, 0, NUM_DEFLATE_CODE_SYMBOLS * sizeof(*bitlen_ll)); lodepng_memset(bitlen_d, 0, NUM_DISTANCE_SYMBOLS * sizeof(*bitlen_d)); - /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + /*i is the current symbol we're reading in the part that contains the code + * lengths of lit/len and dist codes*/ i = 0; - while(i < HLIT + HDIST) { + while (i < HLIT + HDIST) { unsigned code; - ensureBits25(reader, 22); /* up to 15 bits for huffman code, up to 7 extra bits below*/ + ensureBits25( + reader, + 22); /* up to 15 bits for huffman code, up to 7 extra bits below*/ code = huffmanDecodeSymbol(reader, &tree_cl); - if(code <= 15) /*a length code*/ { - if(i < HLIT) bitlen_ll[i] = code; - else bitlen_d[i - HLIT] = code; + if (code <= 15) /*a length code*/ { + if (i < HLIT) + bitlen_ll[i] = code; + else + bitlen_d[i - HLIT] = code; ++i; - } else if(code == 16) /*repeat previous*/ { - unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + } else if (code == 16) /*repeat previous*/ { + unsigned replength = + 3; /*read in the 2 bits that indicate repeat length (3-6)*/ unsigned value; /*set value to the previous code*/ - if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + if (i == 0) + ERROR_BREAK(54); /*can't repeat previous if i is 0*/ replength += readBits(reader, 2); - if(i < HLIT + 1) value = bitlen_ll[i - 1]; - else value = bitlen_d[i - HLIT - 1]; + if (i < HLIT + 1) + value = bitlen_ll[i - 1]; + else + value = bitlen_d[i - HLIT - 1]; /*repeat this value in the next lengths*/ - for(n = 0; n < replength; ++n) { - if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ - if(i < HLIT) bitlen_ll[i] = value; - else bitlen_d[i - HLIT] = value; + for (n = 0; n < replength; ++n) { + if (i >= HLIT + HDIST) + ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if (i < HLIT) + bitlen_ll[i] = value; + else + bitlen_d[i - HLIT] = value; ++i; } - } else if(code == 17) /*repeat "0" 3-10 times*/ { + } else if (code == 17) /*repeat "0" 3-10 times*/ { unsigned replength = 3; /*read in the bits that indicate repeat length*/ replength += readBits(reader, 3); /*repeat this value in the next lengths*/ - for(n = 0; n < replength; ++n) { - if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + for (n = 0; n < replength; ++n) { + if (i >= HLIT + HDIST) + ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ - if(i < HLIT) bitlen_ll[i] = 0; - else bitlen_d[i - HLIT] = 0; + if (i < HLIT) + bitlen_ll[i] = 0; + else + bitlen_d[i - HLIT] = 0; ++i; } - } else if(code == 18) /*repeat "0" 11-138 times*/ { - unsigned replength = 11; /*read in the bits that indicate repeat length*/ + } else if (code == 18) /*repeat "0" 11-138 times*/ { + unsigned replength = + 11; /*read in the bits that indicate repeat length*/ replength += readBits(reader, 7); /*repeat this value in the next lengths*/ - for(n = 0; n < replength; ++n) { - if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + for (n = 0; n < replength; ++n) { + if (i >= HLIT + HDIST) + ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ - if(i < HLIT) bitlen_ll[i] = 0; - else bitlen_d[i - HLIT] = 0; + if (i < HLIT) + bitlen_ll[i] = 0; + else + bitlen_d[i - HLIT] = 0; ++i; } } else /*if(code == INVALIDSYMBOL)*/ { ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ } /*check if any of the ensureBits above went out of bounds*/ - if(reader->bp > reader->bitsize) { - /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol - (10=no endcode, 11=wrong jump outside of tree)*/ - /* TODO: revise error codes 10,11,50: the above comment is no longer valid */ + if (reader->bp > reader->bitsize) { + /*return error code 10 or 11 depending on the situation that happened in + huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ + /* TODO: revise error codes 10,11,50: the above comment is no longer + * valid */ ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ } } - if(error) break; + if (error) + break; - if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + if (bitlen_ll[256] == 0) + ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ - /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ - error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); - if(error) break; - error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + /*now we've finally got HLIT and HDIST, so generate the code trees, and the + * function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, + NUM_DEFLATE_CODE_SYMBOLS, 15); + if (error) + break; + error = + HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); break; /*end of error-while*/ } @@ -1260,29 +1477,35 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, } /*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/ -static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, +static unsigned inflateHuffmanBlock(ucvector *out, LodePNGBitReader *reader, unsigned btype, size_t max_output_size) { unsigned error = 0; HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ - HuffmanTree tree_d; /*the huffman tree for distance codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ HuffmanTree_init(&tree_ll); HuffmanTree_init(&tree_d); - if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d); - else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader); + if (btype == 1) + error = getTreeInflateFixed(&tree_ll, &tree_d); + else /*if(btype == 2)*/ + error = getTreeInflateDynamic(&tree_ll, &tree_d, reader); - while(!error) /*decode all symbols until end reached, breaks at end code*/ { + while (!error) /*decode all symbols until end reached, breaks at end code*/ { /*code_ll is literal, length or end code*/ unsigned code_ll; - ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */ + ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for + the length extra bits */ code_ll = huffmanDecodeSymbol(reader, &tree_ll); - if(code_ll <= 255) /*literal symbol*/ { - if(!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/); + if (code_ll <= 255) /*literal symbol*/ { + if (!ucvector_resize(out, out->size + 1)) + ERROR_BREAK(83 /*alloc fail*/); out->data[out->size - 1] = (unsigned char)code_ll; - } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { + } else if (code_ll >= FIRST_LENGTH_CODE_INDEX && + code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { unsigned code_d, distance; - unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + unsigned numextrabits_l, + numextrabits_d; /*extra bits for length and distance*/ size_t start, backward, length; /*part 1: get length base*/ @@ -1290,18 +1513,20 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, /*part 2: get extra bits and add the value of that to length*/ numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; - if(numextrabits_l != 0) { + if (numextrabits_l != 0) { /* bits already ensured above */ length += readBits(reader, numextrabits_l); } /*part 3: get distance code*/ - ensureBits32(reader, 28); /* up to 15 for the huffman symbol, up to 13 for the extra bits */ + ensureBits32(reader, 28); /* up to 15 for the huffman symbol, up to 13 for + the extra bits */ code_d = huffmanDecodeSymbol(reader, &tree_d); - if(code_d > 29) { - if(code_d <= 31) { - ERROR_BREAK(18); /*error: invalid distance code (30-31 are never used)*/ - } else /* if(code_d == INVALIDSYMBOL) */{ + if (code_d > 29) { + if (code_d <= 31) { + ERROR_BREAK( + 18); /*error: invalid distance code (30-31 are never used)*/ + } else /* if(code_d == INVALIDSYMBOL) */ { ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ } } @@ -1309,40 +1534,43 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, /*part 4: get extra bits from distance*/ numextrabits_d = DISTANCEEXTRA[code_d]; - if(numextrabits_d != 0) { + if (numextrabits_d != 0) { /* bits already ensured above */ distance += readBits(reader, numextrabits_d); } /*part 5: fill in all the out[n] values based on the length and dist*/ start = out->size; - if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + if (distance > start) + ERROR_BREAK(52); /*too long backward distance*/ backward = start - distance; - if(!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/); - if(distance < length) { + if (!ucvector_resize(out, out->size + length)) + ERROR_BREAK(83 /*alloc fail*/); + if (distance < length) { size_t forward; lodepng_memcpy(out->data + start, out->data + backward, distance); start += distance; - for(forward = distance; forward < length; ++forward) { + for (forward = distance; forward < length; ++forward) { out->data[start++] = out->data[backward++]; } } else { lodepng_memcpy(out->data + start, out->data + backward, length); } - } else if(code_ll == 256) { + } else if (code_ll == 256) { break; /*end code, break the loop*/ } else /*if(code_ll == INVALIDSYMBOL)*/ { ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ } /*check if any of the ensureBits above went out of bounds*/ - if(reader->bp > reader->bitsize) { - /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol - (10=no endcode, 11=wrong jump outside of tree)*/ - /* TODO: revise error codes 10,11,50: the above comment is no longer valid */ + if (reader->bp > reader->bitsize) { + /*return error code 10 or 11 depending on the situation that happened in + huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ + /* TODO: revise error codes 10,11,50: the above comment is no longer valid + */ ERROR_BREAK(51); /*error, bit pointer jumps past memory*/ } - if(max_output_size && out->size > max_output_size) { + if (max_output_size && out->size > max_output_size) { ERROR_BREAK(109); /*error, larger than max size*/ } } @@ -1353,8 +1581,9 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, return error; } -static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, - const LodePNGDecompressSettings* settings) { +static unsigned +inflateNoCompression(ucvector *out, LodePNGBitReader *reader, + const LodePNGDecompressSettings *settings) { size_t bytepos; size_t size = reader->size; unsigned LEN, NLEN, error = 0; @@ -1363,19 +1592,26 @@ static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, bytepos = (reader->bp + 7u) >> 3u; /*read LEN (2 bytes) and NLEN (2 bytes)*/ - if(bytepos + 4 >= size) return 52; /*error, bit pointer will jump past memory*/ - LEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2; - NLEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2; + if (bytepos + 4 >= size) + return 52; /*error, bit pointer will jump past memory*/ + LEN = (unsigned)reader->data[bytepos] + + ((unsigned)reader->data[bytepos + 1] << 8u); + bytepos += 2; + NLEN = (unsigned)reader->data[bytepos] + + ((unsigned)reader->data[bytepos + 1] << 8u); + bytepos += 2; /*check if 16-bit NLEN is really the one's complement of LEN*/ - if(!settings->ignore_nlen && LEN + NLEN != 65535) { + if (!settings->ignore_nlen && LEN + NLEN != 65535) { return 21; /*error: NLEN is not one's complement of LEN*/ } - if(!ucvector_resize(out, out->size + LEN)) return 83; /*alloc fail*/ + if (!ucvector_resize(out, out->size + LEN)) + return 83; /*alloc fail*/ /*read the literal data: LEN bytes are now stored in the out buffer*/ - if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/ + if (bytepos + LEN > size) + return 23; /*error: reading outside of in buffer*/ lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN); bytepos += LEN; @@ -1385,34 +1621,44 @@ static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, return error; } -static unsigned lodepng_inflatev(ucvector* out, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings) { +static unsigned lodepng_inflatev(ucvector *out, const unsigned char *in, + size_t insize, + const LodePNGDecompressSettings *settings) { unsigned BFINAL = 0; LodePNGBitReader reader; unsigned error = LodePNGBitReader_init(&reader, in, insize); - if(error) return error; + if (error) + return error; - while(!BFINAL) { + while (!BFINAL) { unsigned BTYPE; - if(!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/ + if (!ensureBits9(&reader, 3)) + return 52; /*error, bit pointer will jump past memory*/ BFINAL = readBits(&reader, 1); BTYPE = readBits(&reader, 2); - if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ - else if(BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/ - else error = inflateHuffmanBlock(out, &reader, BTYPE, settings->max_output_size); /*compression, BTYPE 01 or 10*/ - if(!error && settings->max_output_size && out->size > settings->max_output_size) error = 109; - if(error) break; + if (BTYPE == 3) + return 20; /*error: invalid BTYPE*/ + else if (BTYPE == 0) + error = inflateNoCompression(out, &reader, settings); /*no compression*/ + else + error = inflateHuffmanBlock( + out, &reader, BTYPE, + settings->max_output_size); /*compression, BTYPE 01 or 10*/ + if (!error && settings->max_output_size && + out->size > settings->max_output_size) + error = 109; + if (error) + break; } return error; } -unsigned lodepng_inflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings) { +unsigned lodepng_inflate(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGDecompressSettings *settings) { ucvector v = ucvector_init(*out, *outsize); unsigned error = lodepng_inflatev(&v, in, insize, settings); *out = v.data; @@ -1420,16 +1666,20 @@ unsigned lodepng_inflate(unsigned char** out, size_t* outsize, return error; } -static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings) { - if(settings->custom_inflate) { - unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings); +static unsigned inflatev(ucvector *out, const unsigned char *in, size_t insize, + const LodePNGDecompressSettings *settings) { + if (settings->custom_inflate) { + unsigned error = + settings->custom_inflate(&out->data, &out->size, in, insize, settings); out->allocsize = out->size; - if(error) { - /*the custom inflate is allowed to have its own error codes, however, we translate it to code 110*/ + if (error) { + /*the custom inflate is allowed to have its own error codes, however, we + * translate it to code 110*/ error = 110; - /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ - if(settings->max_output_size && out->size > settings->max_output_size) error = 109; + /*if there's a max output size, and the custom zlib returned error, then + * indicate that error instead*/ + if (settings->max_output_size && out->size > settings->max_output_size) + error = 109; } return error; } else { @@ -1447,28 +1697,35 @@ static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize, static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; -/*search the index in the array, that has the largest value smaller than or equal to the given value, -given array must be sorted (if no value is smaller, it returns the size of the given array)*/ -static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) { - /*binary search (only small gain over linear). TODO: use CPU log2 instruction for getting symbols instead*/ +/*search the index in the array, that has the largest value smaller than or +equal to the given value, given array must be sorted (if no value is smaller, it +returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned *array, size_t array_size, + size_t value) { + /*binary search (only small gain over linear). TODO: use CPU log2 instruction + * for getting symbols instead*/ size_t left = 1; size_t right = array_size - 1; - while(left <= right) { + while (left <= right) { size_t mid = (left + right) >> 1; - if(array[mid] >= value) right = mid - 1; - else left = mid + 1; + if (array[mid] >= value) + right = mid - 1; + else + left = mid + 1; } - if(left >= array_size || array[left] > value) left--; + if (left >= array_size || array[left] > value) + left--; return left; } -static void addLengthDistance(uivector* values, size_t length, size_t distance) { +static void addLengthDistance(uivector *values, size_t length, + size_t distance) { /*values in encoded vector are those used by deflate: 0-255: literal bytes 256: end - 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) - 286-287: invalid*/ + 257-285: length/distance pair (length code, followed by extra length bits, + distance code, extra distance bits) 286-287: invalid*/ unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); @@ -1478,7 +1735,7 @@ static void addLengthDistance(uivector* values, size_t length, size_t distance) size_t pos = values->size; /*TODO: return error when this fails (out of memory)*/ unsigned ok = uivector_resize(values, values->size + 4); - if(ok) { + if (ok) { values->data[pos + 0] = length_code + FIRST_LENGTH_CODE_INDEX; values->data[pos + 1] = extra_length; values->data[pos + 2] = dist_code; @@ -1489,47 +1746,59 @@ static void addLengthDistance(uivector* values, size_t length, size_t distance) /*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 bytes as input because 3 is the minimum match length for deflate*/ static const unsigned HASH_NUM_VALUES = 65536; -static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ +static const unsigned HASH_BIT_MASK = + 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ typedef struct Hash { - int* head; /*hash value to head circular pos - can be outdated if went around window*/ + int *head; /*hash value to head circular pos - can be outdated if went around + window*/ /*circular pos to prev circular pos*/ - unsigned short* chain; - int* val; /*circular pos to hash value*/ + unsigned short *chain; + int *val; /*circular pos to hash value*/ /*TODO: do this not only for zeros but for any repeated byte. However for PNG it's always going to be the zeros that dominate, so not important for PNG*/ - int* headz; /*similar to head, but for chainz*/ - unsigned short* chainz; /*those with same amount of zeros*/ - unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ + int *headz; /*similar to head, but for chainz*/ + unsigned short *chainz; /*those with same amount of zeros*/ + unsigned short *zeros; /*length of zeros streak, used as a second hash chain*/ } Hash; -static unsigned hash_init(Hash* hash, unsigned windowsize) { +static unsigned hash_init(Hash *hash, unsigned windowsize) { unsigned i; - hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); - hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); - hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->head = (int *)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int *)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = + (unsigned short *)lodepng_malloc(sizeof(unsigned short) * windowsize); - hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); - hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); - hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->zeros = + (unsigned short *)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = + (int *)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = + (unsigned short *)lodepng_malloc(sizeof(unsigned short) * windowsize); - if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) { + if (!hash->head || !hash->chain || !hash->val || !hash->headz || + !hash->chainz || !hash->zeros) { return 83; /*alloc fail*/ } /*initialize hash table*/ - for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; - for(i = 0; i != windowsize; ++i) hash->val[i] = -1; - for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + for (i = 0; i != HASH_NUM_VALUES; ++i) + hash->head[i] = -1; + for (i = 0; i != windowsize; ++i) + hash->val[i] = -1; + for (i = 0; i != windowsize; ++i) + hash->chain[i] = i; /*same value as index indicates uninitialized*/ - for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; - for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + for (i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) + hash->headz[i] = -1; + for (i = 0; i != windowsize; ++i) + hash->chainz[i] = i; /*same value as index indicates uninitialized*/ return 0; } -static void hash_cleanup(Hash* hash) { +static void hash_cleanup(Hash *hash) { lodepng_free(hash->head); lodepng_free(hash->val); lodepng_free(hash->chain); @@ -1539,11 +1808,9 @@ static void hash_cleanup(Hash* hash) { lodepng_free(hash->chainz); } - - -static unsigned getHash(const unsigned char* data, size_t size, size_t pos) { +static unsigned getHash(const unsigned char *data, size_t size, size_t pos) { unsigned result = 0; - if(pos + 2 < size) { + if (pos + 2 < size) { /*A simple shift and xor hash is used. Since the data of PNGs is dominated by zeroes due to the filters, a better hash does not have a significant effect on speed in traversing the chain, and causes more time spend on @@ -1553,53 +1820,65 @@ static unsigned getHash(const unsigned char* data, size_t size, size_t pos) { result ^= ((unsigned)data[pos + 2] << 8u); } else { size_t amount, i; - if(pos >= size) return 0; + if (pos >= size) + return 0; amount = size - pos; - for(i = 0; i != amount; ++i) result ^= ((unsigned)data[pos + i] << (i * 8u)); + for (i = 0; i != amount; ++i) + result ^= ((unsigned)data[pos + i] << (i * 8u)); } return result & HASH_BIT_MASK; } -static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) { - const unsigned char* start = data + pos; - const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; - if(end > data + size) end = data + size; +static unsigned countZeros(const unsigned char *data, size_t size, size_t pos) { + const unsigned char *start = data + pos; + const unsigned char *end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if (end > data + size) + end = data + size; data = start; - while(data != end && *data == 0) ++data; - /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + while (data != end && *data == 0) + ++data; + /*subtracting two addresses returned as 32-bit number (max value is + * MAX_SUPPORTED_DEFLATE_LENGTH)*/ return (unsigned)(data - start); } /*wpos = pos & (windowsize - 1)*/ -static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) { +static void updateHashChain(Hash *hash, size_t wpos, unsigned hashval, + unsigned short numzeros) { hash->val[wpos] = (int)hashval; - if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + if (hash->head[hashval] != -1) + hash->chain[wpos] = hash->head[hashval]; hash->head[hashval] = (int)wpos; hash->zeros[wpos] = numzeros; - if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + if (hash->headz[numzeros] != -1) + hash->chainz[wpos] = hash->headz[numzeros]; hash->headz[numzeros] = (int)wpos; } /* -LZ77-encode the data. Return value is error code. The input are raw bytes, the output -is in the form of unsigned integers with codes representing for example literal bytes, or -length/distance pairs. -It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a -sliding window (of windowsize) is used, and all past bytes in that window can be used as -the "dictionary". A brute force search through all possible distances would be slow, and -this hash technique is one out of several ways to speed this up. +LZ77-encode the data. Return value is error code. The input are raw bytes, the +output is in the form of unsigned integers with codes representing for example +literal bytes, or length/distance pairs. It uses a hash table technique to let +it encode faster. When doing LZ77 encoding, a sliding window (of windowsize) is +used, and all past bytes in that window can be used as the "dictionary". A brute +force search through all possible distances would be slow, and this hash +technique is one out of several ways to speed this up. */ -static unsigned encodeLZ77(uivector* out, Hash* hash, - const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, - unsigned minmatch, unsigned nicematch, unsigned lazymatching) { +static unsigned encodeLZ77(uivector *out, Hash *hash, const unsigned char *in, + size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, + unsigned lazymatching) { size_t pos; unsigned i, error = 0; - /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + /*for large window lengths, assume the user wants no compression loss. + * Otherwise, max hash chain length speedup.*/ unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8u; - unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + unsigned maxlazymatch = + windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; - unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 + is better or worse*/ unsigned numzeros = 0; unsigned offset; /*the offset represents the distance in LZ77 terminology*/ @@ -1612,20 +1891,26 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, const unsigned char *lastptr, *foreptr, *backptr; unsigned hashpos; - if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ - if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + if (windowsize == 0 || windowsize > 32768) + return 60; /*error: windowsize smaller/larger than allowed*/ + if ((windowsize & (windowsize - 1)) != 0) + return 90; /*error: must be power of two*/ - if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + if (nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) + nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; - for(pos = inpos; pos < insize; ++pos) { - size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + for (pos = inpos; pos < insize; ++pos) { + size_t wpos = + pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ unsigned chainlength = 0; hashval = getHash(in, insize, pos); - if(usezeros && hashval == 0) { - if(numzeros == 0) numzeros = countZeros(in, insize, pos); - else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + if (usezeros && hashval == 0) { + if (numzeros == 0) + numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) + --numzeros; } else { numzeros = 0; } @@ -1638,96 +1923,125 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, hashpos = hash->chain[wpos]; - lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH + ? insize + : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; /*search for the longest string*/ prev_offset = 0; - for(;;) { - if(chainlength++ >= maxchainlength) break; - current_offset = (unsigned)(hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize); + for (;;) { + if (chainlength++ >= maxchainlength) + break; + current_offset = + (unsigned)(hashpos <= wpos ? wpos - hashpos + : wpos - hashpos + windowsize); - if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + if (current_offset < prev_offset) + break; /*stop when went completely around the circular buffer*/ prev_offset = current_offset; - if(current_offset > 0) { + if (current_offset > 0) { /*test the next characters*/ foreptr = &in[pos]; backptr = &in[pos - current_offset]; - /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ - if(numzeros >= 3) { + /*common case in PNGs is lots of zeros. Quickly skip over them as a + * speedup*/ + if (numzeros >= 3) { unsigned skip = hash->zeros[hashpos]; - if(skip > numzeros) skip = numzeros; + if (skip > numzeros) + skip = numzeros; backptr += skip; foreptr += skip; } - while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ { + while ( + foreptr != lastptr && + *backptr == + *foreptr) /*maximum supported length by deflate is max length*/ + { ++backptr; ++foreptr; } current_length = (unsigned)(foreptr - &in[pos]); - if(current_length > length) { + if (current_length > length) { length = current_length; /*the longest length*/ - offset = current_offset; /*the offset that is related to this longest length*/ - /*jump out once a length of max length is found (speed gain). This also jumps - out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ - if(current_length >= nicematch) break; + offset = current_offset; /*the offset that is related to this longest + length*/ + /*jump out once a length of max length is found (speed gain). This + also jumps out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if (current_length >= nicematch) + break; } } - if(hashpos == hash->chain[hashpos]) break; + if (hashpos == hash->chain[hashpos]) + break; - if(numzeros >= 3 && length > numzeros) { + if (numzeros >= 3 && length > numzeros) { hashpos = hash->chainz[hashpos]; - if(hash->zeros[hashpos] != numzeros) break; + if (hash->zeros[hashpos] != numzeros) + break; } else { hashpos = hash->chain[hashpos]; - /*outdated hash value, happens if particular value was not encountered in whole last window*/ - if(hash->val[hashpos] != (int)hashval) break; + /*outdated hash value, happens if particular value was not encountered + * in whole last window*/ + if (hash->val[hashpos] != (int)hashval) + break; } } - if(lazymatching) { - if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) { + if (lazymatching) { + if (!lazy && length >= 3 && length <= maxlazymatch && + length < MAX_SUPPORTED_DEFLATE_LENGTH) { lazy = 1; lazylength = length; lazyoffset = offset; continue; /*try the next byte*/ } - if(lazy) { + if (lazy) { lazy = 0; - if(pos == 0) ERROR_BREAK(81); - if(length > lazylength + 1) { + if (pos == 0) + ERROR_BREAK(81); + if (length > lazylength + 1) { /*push the previous character as literal*/ - if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + if (!uivector_push_back(out, in[pos - 1])) + ERROR_BREAK(83 /*alloc fail*/); } else { length = lazylength; offset = lazyoffset; - hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->head[hashval] = -1; /*the same hashchain update will be done, + this ensures no wrong alteration*/ hash->headz[numzeros] = -1; /*idem*/ --pos; } } } - if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + if (length >= 3 && offset > windowsize) + ERROR_BREAK(86 /*too big (or overflown negative) offset*/); /*encode it as length/distance pair or literal value*/ - if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ { - if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); - } else if(length < minmatch || (length == 3 && offset > 4096)) { + if (length < + 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if (!uivector_push_back(out, in[pos])) + ERROR_BREAK(83 /*alloc fail*/); + } else if (length < minmatch || (length == 3 && offset > 4096)) { /*compensate for the fact that longer offsets have more extra bits, a length of only 3 may be not worth it then*/ - if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + if (!uivector_push_back(out, in[pos])) + ERROR_BREAK(83 /*alloc fail*/); } else { addLengthDistance(out, length, offset); - for(i = 1; i < length; ++i) { + for (i = 1; i < length; ++i) { ++pos; wpos = pos & (windowsize - 1); hashval = getHash(in, insize, pos); - if(usezeros && hashval == 0) { - if(numzeros == 0) numzeros = countZeros(in, insize, pos); - else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + if (usezeros && hashval == 0) { + if (numzeros == 0) + numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) + --numzeros; } else { numzeros = 0; } @@ -1739,15 +2053,18 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, return error; } -/* /////////////////////////////////////////////////////////////////////////// */ +/* /////////////////////////////////////////////////////////////////////////// + */ -static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) { - /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, - 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ +static unsigned deflateNoCompression(ucvector *out, const unsigned char *data, + size_t datasize) { + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it + jumps to start of next byte, 2 bytes LEN, 2 bytes NLEN, LEN bytes literal + DATA*/ size_t i, numdeflateblocks = (datasize + 65534u) / 65535u; unsigned datapos = 0; - for(i = 0; i != numdeflateblocks; ++i) { + for (i = 0; i != numdeflateblocks; ++i) { unsigned BFINAL, BTYPE, LEN, NLEN; unsigned char firstbyte; size_t pos = out->size; @@ -1756,12 +2073,15 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s BTYPE = 0; LEN = 65535; - if(datasize - datapos < 65535u) LEN = (unsigned)datasize - datapos; + if (datasize - datapos < 65535u) + LEN = (unsigned)datasize - datapos; NLEN = 65535 - LEN; - if(!ucvector_resize(out, out->size + LEN + 5)) return 83; /*alloc fail*/ + if (!ucvector_resize(out, out->size + LEN + 5)) + return 83; /*alloc fail*/ - firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1u) << 1u) + ((BTYPE & 2u) << 1u)); + firstbyte = + (unsigned char)(BFINAL + ((BTYPE & 1u) << 1u) + ((BTYPE & 2u) << 1u)); out->data[pos + 0] = firstbyte; out->data[pos + 1] = (unsigned char)(LEN & 255); out->data[pos + 2] = (unsigned char)(LEN >> 8u); @@ -1775,17 +2095,19 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s } /* -write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. -tree_ll: the tree for lit and len codes. -tree_d: the tree for distance codes. +write the lz77-encoded data, which has lit, len and dist codes, to compressed +stream using huffman trees. tree_ll: the tree for lit and len codes. tree_d: the +tree for distance codes. */ -static void writeLZ77data(LodePNGBitWriter* writer, const uivector* lz77_encoded, - const HuffmanTree* tree_ll, const HuffmanTree* tree_d) { +static void writeLZ77data(LodePNGBitWriter *writer, + const uivector *lz77_encoded, + const HuffmanTree *tree_ll, + const HuffmanTree *tree_d) { size_t i = 0; - for(i = 0; i != lz77_encoded->size; ++i) { + for (i = 0; i != lz77_encoded->size; ++i) { unsigned val = lz77_encoded->data[i]; writeBitsReversed(writer, tree_ll->codes[val], tree_ll->lengths[val]); - if(val > 256) /*for a length code, 3 more things have to be added*/ { + if (val > 256) /*for a length code, 3 more things have to be added*/ { unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; unsigned length_extra_bits = lz77_encoded->data[++i]; @@ -1797,16 +2119,20 @@ static void writeLZ77data(LodePNGBitWriter* writer, const uivector* lz77_encoded unsigned distance_extra_bits = lz77_encoded->data[++i]; writeBits(writer, length_extra_bits, n_length_extra_bits); - writeBitsReversed(writer, tree_d->codes[distance_code], tree_d->lengths[distance_code]); + writeBitsReversed(writer, tree_d->codes[distance_code], + tree_d->lengths[distance_code]); writeBits(writer, distance_extra_bits, n_distance_extra_bits); } } } -/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ -static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, - const unsigned char* data, size_t datapos, size_t dataend, - const LodePNGCompressSettings* settings, unsigned final) { +/*Deflate for a block of type "dynamic", that is, with freely, optimally, + * created huffman trees*/ +static unsigned deflateDynamic(LodePNGBitWriter *writer, Hash *hash, + const unsigned char *data, size_t datapos, + size_t dataend, + const LodePNGCompressSettings *settings, + unsigned final) { unsigned error = 0; /* @@ -1820,25 +2146,29 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, the code length code lengths ("clcl"). */ - /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + /*The lz77 encoded data, represented with integers since there will also be + * length and distance codes in it*/ uivector lz77_encoded; HuffmanTree tree_ll; /*tree for lit,len values*/ - HuffmanTree tree_d; /*tree for distance codes*/ - HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ - unsigned* frequencies_ll = 0; /*frequency of lit,len codes*/ - unsigned* frequencies_d = 0; /*frequency of dist codes*/ - unsigned* frequencies_cl = 0; /*frequency of code length codes*/ - unsigned* bitlen_lld = 0; /*lit,len,dist code lengths (int bits), literally (without repeat codes).*/ - unsigned* bitlen_lld_e = 0; /*bitlen_lld encoded with repeat codes (this is a rudimentary run length compression)*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll + and tree_d*/ + unsigned *frequencies_ll = 0; /*frequency of lit,len codes*/ + unsigned *frequencies_d = 0; /*frequency of dist codes*/ + unsigned *frequencies_cl = 0; /*frequency of code length codes*/ + unsigned *bitlen_lld = 0; /*lit,len,dist code lengths (int bits), literally + (without repeat codes).*/ + unsigned *bitlen_lld_e = 0; /*bitlen_lld encoded with repeat codes (this is a + rudimentary run length compression)*/ size_t datasize = dataend - datapos; /* - If we could call "bitlen_cl" the the code length code lengths ("clcl"), that is the bit lengths of codes to represent - tree_cl in CLCL_ORDER, then due to the huffman compression of huffman tree representations ("two levels"), there are - some analogies: - bitlen_lld is to tree_cl what data is to tree_ll and tree_d. - bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. - bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + If we could call "bitlen_cl" the the code length code lengths ("clcl"), that + is the bit lengths of codes to represent tree_cl in CLCL_ORDER, then due to + the huffman compression of huffman tree representations ("two levels"), there + are some analogies: bitlen_lld is to tree_cl what data is to tree_ll and + tree_d. bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. bitlen_cl + is to bitlen_lld_e what bitlen_lld is to lz77_encoded. */ unsigned BFINAL = final; @@ -1851,90 +2181,110 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, HuffmanTree_init(&tree_d); HuffmanTree_init(&tree_cl); /* could fit on stack, but >1KB is on the larger side so allocate instead */ - frequencies_ll = (unsigned*)lodepng_malloc(286 * sizeof(*frequencies_ll)); - frequencies_d = (unsigned*)lodepng_malloc(30 * sizeof(*frequencies_d)); - frequencies_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl)); + frequencies_ll = (unsigned *)lodepng_malloc(286 * sizeof(*frequencies_ll)); + frequencies_d = (unsigned *)lodepng_malloc(30 * sizeof(*frequencies_d)); + frequencies_cl = (unsigned *)lodepng_malloc(NUM_CODE_LENGTH_CODES * + sizeof(*frequencies_cl)); - if(!frequencies_ll || !frequencies_d || !frequencies_cl) error = 83; /*alloc fail*/ + if (!frequencies_ll || !frequencies_d || !frequencies_cl) + error = 83; /*alloc fail*/ /*This while loop never loops due to a break at the end, it is here to allow breaking out of it to the cleanup phase on error conditions.*/ - while(!error) { + while (!error) { lodepng_memset(frequencies_ll, 0, 286 * sizeof(*frequencies_ll)); lodepng_memset(frequencies_d, 0, 30 * sizeof(*frequencies_d)); - lodepng_memset(frequencies_cl, 0, NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl)); + lodepng_memset(frequencies_cl, 0, + NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl)); - if(settings->use_lz77) { - error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, - settings->minmatch, settings->nicematch, settings->lazymatching); - if(error) break; + if (settings->use_lz77) { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, + settings->windowsize, settings->minmatch, + settings->nicematch, settings->lazymatching); + if (error) + break; } else { - if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); - for(i = datapos; i < dataend; ++i) lz77_encoded.data[i - datapos] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + if (!uivector_resize(&lz77_encoded, datasize)) + ERROR_BREAK(83 /*alloc fail*/); + for (i = datapos; i < dataend; ++i) + lz77_encoded.data[i - datapos] = + data[i]; /*no LZ77, but still will be Huffman compressed*/ } /*Count the frequencies of lit, len and dist codes*/ - for(i = 0; i != lz77_encoded.size; ++i) { + for (i = 0; i != lz77_encoded.size; ++i) { unsigned symbol = lz77_encoded.data[i]; ++frequencies_ll[symbol]; - if(symbol > 256) { + if (symbol > 256) { unsigned dist = lz77_encoded.data[i + 2]; ++frequencies_d[dist]; i += 3; } } - frequencies_ll[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + frequencies_ll[256] = + 1; /*there will be exactly 1 end code, at the end of the block*/ - /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ - error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll, 257, 286, 15); - if(error) break; - /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + /*Make both huffman trees, one for the lit and len codes, one for the dist + * codes*/ + error = + HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll, 257, 286, 15); + if (error) + break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least + * 2 symbols in the dist tree*/ error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d, 2, 30, 15); - if(error) break; + if (error) + break; numcodes_ll = LODEPNG_MIN(tree_ll.numcodes, 286); numcodes_d = LODEPNG_MIN(tree_d.numcodes, 30); /*store the code lengths of both generated trees in bitlen_lld*/ numcodes_lld = numcodes_ll + numcodes_d; - bitlen_lld = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld)); + bitlen_lld = (unsigned *)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld)); /*numcodes_lld_e never needs more size than bitlen_lld*/ - bitlen_lld_e = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld_e)); - if(!bitlen_lld || !bitlen_lld_e) ERROR_BREAK(83); /*alloc fail*/ + bitlen_lld_e = + (unsigned *)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld_e)); + if (!bitlen_lld || !bitlen_lld_e) + ERROR_BREAK(83); /*alloc fail*/ numcodes_lld_e = 0; - for(i = 0; i != numcodes_ll; ++i) bitlen_lld[i] = tree_ll.lengths[i]; - for(i = 0; i != numcodes_d; ++i) bitlen_lld[numcodes_ll + i] = tree_d.lengths[i]; + for (i = 0; i != numcodes_ll; ++i) + bitlen_lld[i] = tree_ll.lengths[i]; + for (i = 0; i != numcodes_d; ++i) + bitlen_lld[numcodes_ll + i] = tree_d.lengths[i]; - /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), - 17 (3-10 zeroes), 18 (11-138 zeroes)*/ - for(i = 0; i != numcodes_lld; ++i) { + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 + (copy length 3-6 times), 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for (i = 0; i != numcodes_lld; ++i) { unsigned j = 0; /*amount of repetitions*/ - while(i + j + 1 < numcodes_lld && bitlen_lld[i + j + 1] == bitlen_lld[i]) ++j; + while (i + j + 1 < numcodes_lld && bitlen_lld[i + j + 1] == bitlen_lld[i]) + ++j; - if(bitlen_lld[i] == 0 && j >= 2) /*repeat code for zeroes*/ { + if (bitlen_lld[i] == 0 && j >= 2) /*repeat code for zeroes*/ { ++j; /*include the first zero*/ - if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ { + if (j <= 10) /*repeat code 17 supports max 10 zeroes*/ { bitlen_lld_e[numcodes_lld_e++] = 17; bitlen_lld_e[numcodes_lld_e++] = j - 3; } else /*repeat code 18 supports max 138 zeroes*/ { - if(j > 138) j = 138; + if (j > 138) + j = 138; bitlen_lld_e[numcodes_lld_e++] = 18; bitlen_lld_e[numcodes_lld_e++] = j - 11; } i += (j - 1); - } else if(j >= 3) /*repeat code for value other than zero*/ { + } else if (j >= 3) /*repeat code for value other than zero*/ { size_t k; unsigned num = j / 6u, rest = j % 6u; bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i]; - for(k = 0; k < num; ++k) { + for (k = 0; k < num; ++k) { bitlen_lld_e[numcodes_lld_e++] = 16; bitlen_lld_e[numcodes_lld_e++] = 6 - 3; } - if(rest >= 3) { + if (rest >= 3) { bitlen_lld_e[numcodes_lld_e++] = 16; bitlen_lld_e[numcodes_lld_e++] = rest - 3; - } - else j -= rest; + } else + j -= rest; i += j; } else /*too short to benefit from repeat code*/ { bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i]; @@ -1942,21 +2292,26 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, } /*generate tree_cl, the huffmantree of huffmantrees*/ - for(i = 0; i != numcodes_lld_e; ++i) { + for (i = 0; i != numcodes_lld_e; ++i) { ++frequencies_cl[bitlen_lld_e[i]]; - /*after a repeat code come the bits that specify the number of repetitions, - those don't need to be in the frequencies_cl calculation*/ - if(bitlen_lld_e[i] >= 16) ++i; + /*after a repeat code come the bits that specify the number of + repetitions, those don't need to be in the frequencies_cl calculation*/ + if (bitlen_lld_e[i] >= 16) + ++i; } error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl, - NUM_CODE_LENGTH_CODES, NUM_CODE_LENGTH_CODES, 7); - if(error) break; + NUM_CODE_LENGTH_CODES, + NUM_CODE_LENGTH_CODES, 7); + if (error) + break; /*compute amount of code-length-code-lengths to output*/ numcodes_cl = NUM_CODE_LENGTH_CODES; - /*trim zeros at the end (using CLCL_ORDER), but minimum size must be 4 (see HCLEN below)*/ - while(numcodes_cl > 4u && tree_cl.lengths[CLCL_ORDER[numcodes_cl - 1u]] == 0) { + /*trim zeros at the end (using CLCL_ORDER), but minimum size must be 4 (see + * HCLEN below)*/ + while (numcodes_cl > 4u && + tree_cl.lengths[CLCL_ORDER[numcodes_cl - 1u]] == 0) { numcodes_cl--; } @@ -1966,8 +2321,8 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, After the BFINAL and BTYPE, the dynamic block consists out of the following: - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN - (HCLEN+4)*3 bits code lengths of code length alphabet - - HLIT + 257 code lengths of lit/length alphabet (encoded using the code length - alphabet, + possible repetition codes 16, 17, 18) + - HLIT + 257 code lengths of lit/length alphabet (encoded using the code + length alphabet, + possible repetition codes 16, 17, 18) - HDIST + 1 code lengths of distance alphabet (encoded using the code length alphabet, + possible repetition codes 16, 17, 18) - compressed data @@ -1980,8 +2335,9 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, writeBits(writer, 1, 1); /*second bit of BTYPE "dynamic"*/ /*write the HLIT, HDIST and HCLEN values*/ - /*all three sizes take trimmed ending zeroes into account, done either by HuffmanTree_makeFromFrequencies - or in the loop for numcodes_cl above, which saves space. */ + /*all three sizes take trimmed ending zeroes into account, done either by + HuffmanTree_makeFromFrequencies or in the loop for numcodes_cl above, which + saves space. */ HLIT = (unsigned)(numcodes_ll - 257); HDIST = (unsigned)(numcodes_d - 1); HCLEN = (unsigned)(numcodes_cl - 4); @@ -1990,21 +2346,27 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, writeBits(writer, HCLEN, 4); /*write the code lengths of the code length alphabet ("bitlen_cl")*/ - for(i = 0; i != numcodes_cl; ++i) writeBits(writer, tree_cl.lengths[CLCL_ORDER[i]], 3); + for (i = 0; i != numcodes_cl; ++i) + writeBits(writer, tree_cl.lengths[CLCL_ORDER[i]], 3); /*write the lengths of the lit/len AND the dist alphabet*/ - for(i = 0; i != numcodes_lld_e; ++i) { - writeBitsReversed(writer, tree_cl.codes[bitlen_lld_e[i]], tree_cl.lengths[bitlen_lld_e[i]]); + for (i = 0; i != numcodes_lld_e; ++i) { + writeBitsReversed(writer, tree_cl.codes[bitlen_lld_e[i]], + tree_cl.lengths[bitlen_lld_e[i]]); /*extra bits of repeat codes*/ - if(bitlen_lld_e[i] == 16) writeBits(writer, bitlen_lld_e[++i], 2); - else if(bitlen_lld_e[i] == 17) writeBits(writer, bitlen_lld_e[++i], 3); - else if(bitlen_lld_e[i] == 18) writeBits(writer, bitlen_lld_e[++i], 7); + if (bitlen_lld_e[i] == 16) + writeBits(writer, bitlen_lld_e[++i], 2); + else if (bitlen_lld_e[i] == 17) + writeBits(writer, bitlen_lld_e[++i], 3); + else if (bitlen_lld_e[i] == 18) + writeBits(writer, bitlen_lld_e[++i], 7); } /*write the compressed data symbols*/ writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d); /*error: the length of the end code 256 must be larger than 0*/ - if(tree_ll.lengths[256] == 0) ERROR_BREAK(64); + if (tree_ll.lengths[256] == 0) + ERROR_BREAK(64); /*write the end code*/ writeBitsReversed(writer, tree_ll.codes[256], tree_ll.lengths[256]); @@ -2026,12 +2388,13 @@ static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, return error; } -static unsigned deflateFixed(LodePNGBitWriter* writer, Hash* hash, - const unsigned char* data, - size_t datapos, size_t dataend, - const LodePNGCompressSettings* settings, unsigned final) { +static unsigned deflateFixed(LodePNGBitWriter *writer, Hash *hash, + const unsigned char *data, size_t datapos, + size_t dataend, + const LodePNGCompressSettings *settings, + unsigned final) { HuffmanTree tree_ll; /*tree for literal values and length codes*/ - HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ unsigned BFINAL = final; unsigned error = 0; @@ -2041,27 +2404,32 @@ static unsigned deflateFixed(LodePNGBitWriter* writer, Hash* hash, HuffmanTree_init(&tree_d); error = generateFixedLitLenTree(&tree_ll); - if(!error) error = generateFixedDistanceTree(&tree_d); + if (!error) + error = generateFixedDistanceTree(&tree_d); - if(!error) { + if (!error) { writeBits(writer, BFINAL, 1); writeBits(writer, 1, 1); /*first bit of BTYPE*/ writeBits(writer, 0, 1); /*second bit of BTYPE*/ - if(settings->use_lz77) /*LZ77 encoded*/ { + if (settings->use_lz77) /*LZ77 encoded*/ { uivector lz77_encoded; uivector_init(&lz77_encoded); - error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, - settings->minmatch, settings->nicematch, settings->lazymatching); - if(!error) writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, + settings->windowsize, settings->minmatch, + settings->nicematch, settings->lazymatching); + if (!error) + writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d); uivector_cleanup(&lz77_encoded); } else /*no LZ77, but still will be Huffman compressed*/ { - for(i = datapos; i < dataend; ++i) { - writeBitsReversed(writer, tree_ll.codes[data[i]], tree_ll.lengths[data[i]]); + for (i = datapos; i < dataend; ++i) { + writeBitsReversed(writer, tree_ll.codes[data[i]], + tree_ll.lengths[data[i]]); } } /*add END code*/ - if(!error) writeBitsReversed(writer,tree_ll.codes[256], tree_ll.lengths[256]); + if (!error) + writeBitsReversed(writer, tree_ll.codes[256], tree_ll.lengths[256]); } /*cleanup*/ @@ -2071,8 +2439,9 @@ static unsigned deflateFixed(LodePNGBitWriter* writer, Hash* hash, return error; } -static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings) { +static unsigned lodepng_deflatev(ucvector *out, const unsigned char *in, + size_t insize, + const LodePNGCompressSettings *settings) { unsigned error = 0; size_t i, blocksize, numdeflateblocks; Hash hash; @@ -2080,30 +2449,39 @@ static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t LodePNGBitWriter_init(&writer, out); - if(settings->btype > 2) return 61; - else if(settings->btype == 0) return deflateNoCompression(out, in, insize); - else if(settings->btype == 1) blocksize = insize; + if (settings->btype > 2) + return 61; + else if (settings->btype == 0) + return deflateNoCompression(out, in, insize); + else if (settings->btype == 1) + blocksize = insize; else /*if(settings->btype == 2)*/ { /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ blocksize = insize / 8u + 8; - if(blocksize < 65536) blocksize = 65536; - if(blocksize > 262144) blocksize = 262144; + if (blocksize < 65536) + blocksize = 65536; + if (blocksize > 262144) + blocksize = 262144; } numdeflateblocks = (insize + blocksize - 1) / blocksize; - if(numdeflateblocks == 0) numdeflateblocks = 1; + if (numdeflateblocks == 0) + numdeflateblocks = 1; error = hash_init(&hash, settings->windowsize); - if(!error) { - for(i = 0; i != numdeflateblocks && !error; ++i) { + if (!error) { + for (i = 0; i != numdeflateblocks && !error; ++i) { unsigned final = (i == numdeflateblocks - 1); size_t start = i * blocksize; size_t end = start + blocksize; - if(end > insize) end = insize; + if (end > insize) + end = insize; - if(settings->btype == 1) error = deflateFixed(&writer, &hash, in, start, end, settings, final); - else if(settings->btype == 2) error = deflateDynamic(&writer, &hash, in, start, end, settings, final); + if (settings->btype == 1) + error = deflateFixed(&writer, &hash, in, start, end, settings, final); + else if (settings->btype == 2) + error = deflateDynamic(&writer, &hash, in, start, end, settings, final); } } @@ -2112,9 +2490,9 @@ static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t return error; } -unsigned lodepng_deflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings) { +unsigned lodepng_deflate(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGCompressSettings *settings) { ucvector v = ucvector_init(*out, *outsize); unsigned error = lodepng_deflatev(&v, in, insize, settings); *out = v.data; @@ -2122,12 +2500,14 @@ unsigned lodepng_deflate(unsigned char** out, size_t* outsize, return error; } -static unsigned deflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings) { - if(settings->custom_deflate) { - unsigned error = settings->custom_deflate(out, outsize, in, insize, settings); - /*the custom deflate is allowed to have its own error codes, however, we translate it to code 111*/ +static unsigned deflate(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGCompressSettings *settings) { + if (settings->custom_deflate) { + unsigned error = + settings->custom_deflate(out, outsize, in, insize, settings); + /*the custom deflate is allowed to have its own error codes, however, we + * translate it to code 111*/ return error ? 111 : 0; } else { return lodepng_deflate(out, outsize, in, insize, settings); @@ -2140,16 +2520,18 @@ static unsigned deflate(unsigned char** out, size_t* outsize, /* / Adler32 / */ /* ////////////////////////////////////////////////////////////////////////// */ -static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) { +static unsigned update_adler32(unsigned adler, const unsigned char *data, + unsigned len) { unsigned s1 = adler & 0xffffu; unsigned s2 = (adler >> 16u) & 0xffffu; - while(len != 0u) { + while (len != 0u) { unsigned i; - /*at least 5552 sums can be done before the sums overflow, saving a lot of module divisions*/ + /*at least 5552 sums can be done before the sums overflow, saving a lot of + * module divisions*/ unsigned amount = len > 5552u ? 5552u : len; len -= amount; - for(i = 0; i != amount; ++i) { + for (i = 0; i != amount; ++i) { s1 += (*data++); s2 += s1; } @@ -2161,7 +2543,7 @@ static unsigned update_adler32(unsigned adler, const unsigned char* data, unsign } /*Return the adler32 of the bytes data[0..len-1]*/ -static unsigned adler32(const unsigned char* data, unsigned len) { +static unsigned adler32(const unsigned char *data, unsigned len) { return update_adler32(1u, data, len); } @@ -2171,16 +2553,18 @@ static unsigned adler32(const unsigned char* data, unsigned len) { #ifdef LODEPNG_COMPILE_DECODER -static unsigned lodepng_zlib_decompressv(ucvector* out, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings) { +static unsigned +lodepng_zlib_decompressv(ucvector *out, const unsigned char *in, size_t insize, + const LodePNGDecompressSettings *settings) { unsigned error = 0; unsigned CM, CINFO, FDICT; - if(insize < 2) return 53; /*error, size of zlib data too small*/ + if (insize < 2) + return 53; /*error, size of zlib data too small*/ /*read information from zlib header*/ - if((in[0] * 256 + in[1]) % 31 != 0) { - /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + if ((in[0] * 256 + in[1]) % 31 != 0) { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is + * supposed to be made that way*/ return 24; } @@ -2190,31 +2574,34 @@ static unsigned lodepng_zlib_decompressv(ucvector* out, FDICT = (in[1] >> 5) & 1; /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ - if(CM != 8 || CINFO > 7) { - /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + if (CM != 8 || CINFO > 7) { + /*error: only compression method 8: inflate with sliding window of 32k is + * supported by the PNG spec*/ return 25; } - if(FDICT != 0) { + if (FDICT != 0) { /*error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."*/ return 26; } error = inflatev(out, in + 2, insize - 2, settings); - if(error) return error; + if (error) + return error; - if(!settings->ignore_adler32) { + if (!settings->ignore_adler32) { unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); unsigned checksum = adler32(out->data, (unsigned)(out->size)); - if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + if (checksum != ADLER32) + return 58; /*error, adler checksum not correct, data must be corrupted*/ } return 0; /*no error*/ } - -unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGDecompressSettings* settings) { +unsigned lodepng_zlib_decompress(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGDecompressSettings *settings) { ucvector v = ucvector_init(*out, *outsize); unsigned error = lodepng_zlib_decompressv(&v, in, insize, settings); *out = v.data; @@ -2222,21 +2609,27 @@ unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const uns return error; } -/*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */ -static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, - const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { +/*expected_size is expected output size, to avoid intermediate allocations. Set + * to 0 if not known. */ +static unsigned zlib_decompress(unsigned char **out, size_t *outsize, + size_t expected_size, const unsigned char *in, + size_t insize, + const LodePNGDecompressSettings *settings) { unsigned error; - if(settings->custom_zlib) { + if (settings->custom_zlib) { error = settings->custom_zlib(out, outsize, in, insize, settings); - if(error) { - /*the custom zlib is allowed to have its own error codes, however, we translate it to code 110*/ + if (error) { + /*the custom zlib is allowed to have its own error codes, however, we + * translate it to code 110*/ error = 110; - /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ - if(settings->max_output_size && *outsize > settings->max_output_size) error = 109; + /*if there's a max output size, and the custom zlib returned error, then + * indicate that error instead*/ + if (settings->max_output_size && *outsize > settings->max_output_size) + error = 109; } } else { ucvector v = ucvector_init(*out, *outsize); - if(expected_size) { + if (expected_size) { /*reserve the memory to avoid intermediate reallocations*/ ucvector_resize(&v, *outsize + expected_size); v.size = *outsize; @@ -2252,27 +2645,31 @@ static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t exp #ifdef LODEPNG_COMPILE_ENCODER -unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGCompressSettings* settings) { +unsigned lodepng_zlib_compress(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGCompressSettings *settings) { size_t i; unsigned error; - unsigned char* deflatedata = 0; + unsigned char *deflatedata = 0; size_t deflatesize = 0; error = deflate(&deflatedata, &deflatesize, in, insize, settings); *out = NULL; *outsize = 0; - if(!error) { + if (!error) { *outsize = deflatesize + 6; - *out = (unsigned char*)lodepng_malloc(*outsize); - if(!*out) error = 83; /*alloc fail*/ + *out = (unsigned char *)lodepng_malloc(*outsize); + if (!*out) + error = 83; /*alloc fail*/ } - if(!error) { + if (!error) { unsigned ADLER32 = adler32(in, (unsigned)insize); - /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ - unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 + * checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window + size up to 32768 can be used.*/ unsigned FLEVEL = 0; unsigned FDICT = 0; unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; @@ -2281,7 +2678,8 @@ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsig (*out)[0] = (unsigned char)(CMFFLG >> 8); (*out)[1] = (unsigned char)(CMFFLG & 255); - for(i = 0; i != deflatesize; ++i) (*out)[i + 2] = deflatedata[i]; + for (i = 0; i != deflatesize; ++i) + (*out)[i + 2] = deflatedata[i]; lodepng_set32bitInt(&(*out)[*outsize - 4], ADLER32); } @@ -2290,11 +2688,13 @@ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsig } /* compress using the default or custom zlib function */ -static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGCompressSettings* settings) { - if(settings->custom_zlib) { +static unsigned zlib_compress(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGCompressSettings *settings) { + if (settings->custom_zlib) { unsigned error = settings->custom_zlib(out, outsize, in, insize, settings); - /*the custom zlib is allowed to have its own error codes, however, we translate it to code 111*/ + /*the custom zlib is allowed to have its own error codes, however, we + * translate it to code 111*/ return error ? 111 : 0; } else { return lodepng_zlib_compress(out, outsize, in, insize, settings); @@ -2306,17 +2706,22 @@ static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsign #else /*no LODEPNG_COMPILE_ZLIB*/ #ifdef LODEPNG_COMPILE_DECODER -static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, - const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { - if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ +static unsigned zlib_decompress(unsigned char **out, size_t *outsize, + size_t expected_size, const unsigned char *in, + size_t insize, + const LodePNGDecompressSettings *settings) { + if (!settings->custom_zlib) + return 87; /*no custom zlib function provided */ (void)expected_size; return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER -static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, - size_t insize, const LodePNGCompressSettings* settings) { - if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ +static unsigned zlib_compress(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGCompressSettings *settings) { + if (!settings->custom_zlib) + return 87; /*no custom zlib function provided */ return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_ENCODER*/ @@ -2330,8 +2735,9 @@ static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsign /*this is a good tradeoff between speed and compression ratio*/ #define DEFAULT_WINDOWSIZE 2048 -void lodepng_compress_settings_init(LodePNGCompressSettings* settings) { - /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ +void lodepng_compress_settings_init(LodePNGCompressSettings *settings) { + /*compress with dynamic huffman tree (not in the mathematical sense, just not + * the predefined one)*/ settings->btype = 2; settings->use_lz77 = 1; settings->windowsize = DEFAULT_WINDOWSIZE; @@ -2344,14 +2750,14 @@ void lodepng_compress_settings_init(LodePNGCompressSettings* settings) { settings->custom_context = 0; } -const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; - +const LodePNGCompressSettings lodepng_default_compress_settings = { + 2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DECODER -void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) { +void lodepng_decompress_settings_init(LodePNGDecompressSettings *settings) { settings->ignore_adler32 = 0; settings->ignore_nlen = 0; settings->max_output_size = 0; @@ -2361,7 +2767,8 @@ void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) { settings->custom_context = 0; } -const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0, 0}; +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, + 0, 0, 0}; #endif /*LODEPNG_COMPILE_DECODER*/ @@ -2377,85 +2784,113 @@ const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, /* / CRC32 / */ /* ////////////////////////////////////////////////////////////////////////// */ - #ifndef LODEPNG_NO_COMPILE_CRC /* CRC polynomial: 0xedb88320 */ static unsigned lodepng_crc32_table[256] = { - 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, - 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, - 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, - 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, - 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, - 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, - 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, - 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, - 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, - 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, - 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, - 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, - 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, - 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, - 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, - 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, - 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, - 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, - 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, - 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, - 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, - 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, - 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, - 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, - 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, - 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, - 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, - 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, - 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, - 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, - 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, - 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u -}; + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, + 1886057615u, 3915621685u, 2657392035u, 249268274u, 2044508324u, + 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, + 2428444049u, 498536548u, 1789927666u, 4089016648u, 2227061214u, + 450548861u, 1843258603u, 4107580753u, 2211677639u, 325883990u, + 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, + 4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, + 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, + 1172266101u, 3705015759u, 2882616665u, 651767980u, 1373503546u, + 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, + 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u, + 795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, + 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, + 2680153253u, 3904427059u, 2013776290u, 251722036u, 2517215374u, + 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, + 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u, + 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, + 4224994405u, 1303535960u, 984961486u, 2747007092u, 3569037538u, + 1256170817u, 1037604311u, 2765210733u, 3554079995u, 1131014506u, + 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, + 2852801631u, 3708648649u, 1342533948u, 654459306u, 3188396048u, + 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, + 783551873u, 3082640443u, 3233442989u, 3988292384u, 2596254646u, + 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, + 1943803523u, 3814918930u, 2489596804u, 225274430u, 2053790376u, + 3826175755u, 2466906013u, 167816743u, 2097651377u, 4027552580u, + 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, + 426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, + 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, + 2797360999u, 1068828381u, 1219638859u, 3624741850u, 2936675148u, + 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, + 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u, + 3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, + 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, + 752459403u, 1541320221u, 2607071920u, 3965973030u, 1969922972u, + 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, + 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u, + 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, + 414664567u, 2282248934u, 4279200368u, 1711684554u, 285281116u, + 2405801727u, 4167216745u, 1634467795u, 376229701u, 2685067896u, + 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, + 1231636301u, 1047427035u, 2932959818u, 3654703836u, 1088359270u, + 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, + 3453421203u, 1423857449u, 601450431u, 3009837614u, 3294710456u, + 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, + 755167117u}; /*Return the CRC of the bytes buf[0..len-1].*/ -unsigned lodepng_crc32(const unsigned char* data, size_t length) { +unsigned lodepng_crc32(const unsigned char *data, size_t length) { unsigned r = 0xffffffffu; size_t i; - for(i = 0; i < length; ++i) { + for (i = 0; i < length; ++i) { r = lodepng_crc32_table[(r ^ data[i]) & 0xffu] ^ (r >> 8u); } return r ^ 0xffffffffu; } -#else /* !LODEPNG_NO_COMPILE_CRC */ -unsigned lodepng_crc32(const unsigned char* data, size_t length); +#else /* !LODEPNG_NO_COMPILE_CRC */ +unsigned lodepng_crc32(const unsigned char *data, size_t length); #endif /* !LODEPNG_NO_COMPILE_CRC */ /* ////////////////////////////////////////////////////////////////////////// */ /* / Reading and writing PNG color channel bits / */ /* ////////////////////////////////////////////////////////////////////////// */ -/* The color channel bits of less-than-8-bit pixels are read with the MSB of bytes first, -so LodePNGBitWriter and LodePNGBitReader can't be used for those. */ +/* The color channel bits of less-than-8-bit pixels are read with the MSB of +bytes first, so LodePNGBitWriter and LodePNGBitReader can't be used for those. +*/ -static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) { - unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); +static unsigned char readBitFromReversedStream(size_t *bitpointer, + const unsigned char *bitstream) { + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> + (7 - ((*bitpointer) & 0x7))) & + 1); ++(*bitpointer); return result; } /* TODO: make this faster */ -static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { +static unsigned readBitsFromReversedStream(size_t *bitpointer, + const unsigned char *bitstream, + size_t nbits) { unsigned result = 0; size_t i; - for(i = 0 ; i < nbits; ++i) { + for (i = 0; i < nbits; ++i) { result <<= 1u; result |= (unsigned)readBitFromReversedStream(bitpointer, bitstream); } return result; } -static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) { +static void setBitOfReversedStream(size_t *bitpointer, unsigned char *bitstream, + unsigned char bit) { /*the current bit in bitstream may be 0 or 1 for this to work*/ - if(bit == 0) bitstream[(*bitpointer) >> 3u] &= (unsigned char)(~(1u << (7u - ((*bitpointer) & 7u)))); - else bitstream[(*bitpointer) >> 3u] |= (1u << (7u - ((*bitpointer) & 7u))); + if (bit == 0) + bitstream[(*bitpointer) >> 3u] &= + (unsigned char)(~(1u << (7u - ((*bitpointer) & 7u)))); + else + bitstream[(*bitpointer) >> 3u] |= (1u << (7u - ((*bitpointer) & 7u))); ++(*bitpointer); } @@ -2463,119 +2898,144 @@ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, /* / PNG chunks / */ /* ////////////////////////////////////////////////////////////////////////// */ -unsigned lodepng_chunk_length(const unsigned char* chunk) { +unsigned lodepng_chunk_length(const unsigned char *chunk) { return lodepng_read32bitInt(&chunk[0]); } -void lodepng_chunk_type(char type[5], const unsigned char* chunk) { +void lodepng_chunk_type(char type[5], const unsigned char *chunk) { unsigned i; - for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; + for (i = 0; i != 4; ++i) + type[i] = (char)chunk[4 + i]; type[4] = 0; /*null termination char*/ } -unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) { - if(lodepng_strlen(type) != 4) return 0; - return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +unsigned char lodepng_chunk_type_equals(const unsigned char *chunk, + const char *type) { + if (lodepng_strlen(type) != 4) + return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && + chunk[7] == type[3]); } -unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) { - return((chunk[4] & 32) != 0); +unsigned char lodepng_chunk_ancillary(const unsigned char *chunk) { + return ((chunk[4] & 32) != 0); } -unsigned char lodepng_chunk_private(const unsigned char* chunk) { - return((chunk[6] & 32) != 0); +unsigned char lodepng_chunk_private(const unsigned char *chunk) { + return ((chunk[6] & 32) != 0); } -unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) { - return((chunk[7] & 32) != 0); +unsigned char lodepng_chunk_safetocopy(const unsigned char *chunk) { + return ((chunk[7] & 32) != 0); } -unsigned char* lodepng_chunk_data(unsigned char* chunk) { +unsigned char *lodepng_chunk_data(unsigned char *chunk) { return &chunk[8]; } + +const unsigned char *lodepng_chunk_data_const(const unsigned char *chunk) { return &chunk[8]; } -const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) { - return &chunk[8]; -} - -unsigned lodepng_chunk_check_crc(const unsigned char* chunk) { +unsigned lodepng_chunk_check_crc(const unsigned char *chunk) { unsigned length = lodepng_chunk_length(chunk); unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ unsigned checksum = lodepng_crc32(&chunk[4], length + 4); - if(CRC != checksum) return 1; - else return 0; + if (CRC != checksum) + return 1; + else + return 0; } -void lodepng_chunk_generate_crc(unsigned char* chunk) { +void lodepng_chunk_generate_crc(unsigned char *chunk) { unsigned length = lodepng_chunk_length(chunk); unsigned CRC = lodepng_crc32(&chunk[4], length + 4); lodepng_set32bitInt(chunk + 8 + length, CRC); } -unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end) { - if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/ - if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 - && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { +unsigned char *lodepng_chunk_next(unsigned char *chunk, unsigned char *end) { + if (chunk >= end || end - chunk < 12) + return end; /*too small to contain a chunk*/ + if (chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && + chunk[3] == 0x47 && chunk[4] == 0x0d && chunk[5] == 0x0a && + chunk[6] == 0x1a && chunk[7] == 0x0a) { /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ return chunk + 8; } else { size_t total_chunk_length; - unsigned char* result; - if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; + unsigned char *result; + if (lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) + return end; result = chunk + total_chunk_length; - if(result < chunk) return end; /*pointer overflow*/ + if (result < chunk) + return end; /*pointer overflow*/ return result; } } -const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) { - if(chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/ - if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 - && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { +const unsigned char *lodepng_chunk_next_const(const unsigned char *chunk, + const unsigned char *end) { + if (chunk >= end || end - chunk < 12) + return end; /*too small to contain a chunk*/ + if (chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && + chunk[3] == 0x47 && chunk[4] == 0x0d && chunk[5] == 0x0a && + chunk[6] == 0x1a && chunk[7] == 0x0a) { /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ return chunk + 8; } else { size_t total_chunk_length; - const unsigned char* result; - if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; + const unsigned char *result; + if (lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) + return end; result = chunk + total_chunk_length; - if(result < chunk) return end; /*pointer overflow*/ + if (result < chunk) + return end; /*pointer overflow*/ return result; } } -unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]) { - for(;;) { - if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */ - if(lodepng_chunk_type_equals(chunk, type)) return chunk; +unsigned char *lodepng_chunk_find(unsigned char *chunk, unsigned char *end, + const char type[5]) { + for (;;) { + if (chunk >= end || end - chunk < 12) + return 0; /* past file end: chunk + 12 > end */ + if (lodepng_chunk_type_equals(chunk, type)) + return chunk; chunk = lodepng_chunk_next(chunk, end); } } -const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]) { - for(;;) { - if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */ - if(lodepng_chunk_type_equals(chunk, type)) return chunk; +const unsigned char *lodepng_chunk_find_const(const unsigned char *chunk, + const unsigned char *end, + const char type[5]) { + for (;;) { + if (chunk >= end || end - chunk < 12) + return 0; /* past file end: chunk + 12 > end */ + if (lodepng_chunk_type_equals(chunk, type)) + return chunk; chunk = lodepng_chunk_next_const(chunk, end); } } -unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk) { +unsigned lodepng_chunk_append(unsigned char **out, size_t *outsize, + const unsigned char *chunk) { unsigned i; size_t total_chunk_length, new_length; unsigned char *chunk_start, *new_buffer; - if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return 77; - if(lodepng_addofl(*outsize, total_chunk_length, &new_length)) return 77; + if (lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) + return 77; + if (lodepng_addofl(*outsize, total_chunk_length, &new_length)) + return 77; - new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); - if(!new_buffer) return 83; /*alloc fail*/ + new_buffer = (unsigned char *)lodepng_realloc(*out, new_length); + if (!new_buffer) + return 83; /*alloc fail*/ (*out) = new_buffer; (*outsize) = new_length; chunk_start = &(*out)[new_length - total_chunk_length]; - for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; + for (i = 0; i != total_chunk_length; ++i) + chunk_start[i] = chunk[i]; return 0; } @@ -2584,13 +3044,15 @@ unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsign set data or crc yet. Returns the start of the chunk in chunk. The start of the data is at chunk + 8. To finalize chunk, add the data, then use lodepng_chunk_generate_crc */ -static unsigned lodepng_chunk_init(unsigned char** chunk, - ucvector* out, - unsigned length, const char* type) { +static unsigned lodepng_chunk_init(unsigned char **chunk, ucvector *out, + unsigned length, const char *type) { size_t new_length = out->size; - if(lodepng_addofl(new_length, length, &new_length)) return 77; - if(lodepng_addofl(new_length, 12, &new_length)) return 77; - if(!ucvector_resize(out, new_length)) return 83; /*alloc fail*/ + if (lodepng_addofl(new_length, length, &new_length)) + return 77; + if (lodepng_addofl(new_length, 12, &new_length)) + return 77; + if (!ucvector_resize(out, new_length)) + return 83; /*alloc fail*/ *chunk = out->data + new_length - length - 12u; /*1: length*/ @@ -2603,9 +3065,10 @@ static unsigned lodepng_chunk_init(unsigned char** chunk, } /* like lodepng_chunk_create but with custom allocsize */ -static unsigned lodepng_chunk_createv(ucvector* out, - unsigned length, const char* type, const unsigned char* data) { - unsigned char* chunk; +static unsigned lodepng_chunk_createv(ucvector *out, unsigned length, + const char *type, + const unsigned char *data) { + unsigned char *chunk; CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type)); /*3: the data*/ @@ -2617,8 +3080,9 @@ static unsigned lodepng_chunk_createv(ucvector* out, return 0; } -unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, - unsigned length, const char* type, const unsigned char* data) { +unsigned lodepng_chunk_create(unsigned char **out, size_t *outsize, + unsigned length, const char *type, + const unsigned char *data) { ucvector v = ucvector_init(*out, *outsize); unsigned error = lodepng_chunk_createv(&v, length, type, data); *out = v.data; @@ -2630,41 +3094,66 @@ unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, /* / Color types, channels, bits / */ /* ////////////////////////////////////////////////////////////////////////// */ -/*checks if the colortype is valid and the bitdepth bd is allowed for this colortype. -Return value is a LodePNG error code.*/ +/*checks if the colortype is valid and the bitdepth bd is allowed for this +colortype. Return value is a LodePNG error code.*/ static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) { - switch(colortype) { - case LCT_GREY: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; - case LCT_RGB: if(!( bd == 8 || bd == 16)) return 37; break; - case LCT_PALETTE: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; - case LCT_GREY_ALPHA: if(!( bd == 8 || bd == 16)) return 37; break; - case LCT_RGBA: if(!( bd == 8 || bd == 16)) return 37; break; - case LCT_MAX_OCTET_VALUE: return 31; /* invalid color type */ - default: return 31; /* invalid color type */ + switch (colortype) { + case LCT_GREY: + if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) + return 37; + break; + case LCT_RGB: + if (!(bd == 8 || bd == 16)) + return 37; + break; + case LCT_PALETTE: + if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8)) + return 37; + break; + case LCT_GREY_ALPHA: + if (!(bd == 8 || bd == 16)) + return 37; + break; + case LCT_RGBA: + if (!(bd == 8 || bd == 16)) + return 37; + break; + case LCT_MAX_OCTET_VALUE: + return 31; /* invalid color type */ + default: + return 31; /* invalid color type */ } return 0; /*allowed color type / bits combination*/ } static unsigned getNumColorChannels(LodePNGColorType colortype) { - switch(colortype) { - case LCT_GREY: return 1; - case LCT_RGB: return 3; - case LCT_PALETTE: return 1; - case LCT_GREY_ALPHA: return 2; - case LCT_RGBA: return 4; - case LCT_MAX_OCTET_VALUE: return 0; /* invalid color type */ - default: return 0; /*invalid color type*/ + switch (colortype) { + case LCT_GREY: + return 1; + case LCT_RGB: + return 3; + case LCT_PALETTE: + return 1; + case LCT_GREY_ALPHA: + return 2; + case LCT_RGBA: + return 4; + case LCT_MAX_OCTET_VALUE: + return 0; /* invalid color type */ + default: + return 0; /*invalid color type*/ } } -static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) { +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, + unsigned bitdepth) { /*bits per pixel is amount of channels * bits per channel*/ return getNumColorChannels(colortype) * bitdepth; } /* ////////////////////////////////////////////////////////////////////////// */ -void lodepng_color_mode_init(LodePNGColorMode* info) { +void lodepng_color_mode_init(LodePNGColorMode *info) { info->key_defined = 0; info->key_r = info->key_g = info->key_b = 0; info->colortype = LCT_RGBA; @@ -2674,16 +3163,20 @@ void lodepng_color_mode_init(LodePNGColorMode* info) { } /*allocates palette memory if needed, and initializes all colors to black*/ -static void lodepng_color_mode_alloc_palette(LodePNGColorMode* info) { +static void lodepng_color_mode_alloc_palette(LodePNGColorMode *info) { size_t i; - /*if the palette is already allocated, it will have size 1024 so no reallocation needed in that case*/ + /*if the palette is already allocated, it will have size 1024 so no + * reallocation needed in that case*/ /*the palette must have room for up to 256 colors with 4 bytes each.*/ - if(!info->palette) info->palette = (unsigned char*)lodepng_malloc(1024); - if(!info->palette) return; /*alloc fail*/ - for(i = 0; i != 256; ++i) { - /*Initialize all unused colors with black, the value used for invalid palette indices. - This is an error according to the PNG spec, but common PNG decoders make it black instead. - That makes color conversion slightly faster due to no error handling needed.*/ + if (!info->palette) + info->palette = (unsigned char *)lodepng_malloc(1024); + if (!info->palette) + return; /*alloc fail*/ + for (i = 0; i != 256; ++i) { + /*Initialize all unused colors with black, the value used for invalid + palette indices. This is an error according to the PNG spec, but common PNG + decoders make it black instead. That makes color conversion slightly faster + due to no error handling needed.*/ info->palette[i * 4 + 0] = 0; info->palette[i * 4 + 1] = 0; info->palette[i * 4 + 2] = 0; @@ -2691,22 +3184,25 @@ static void lodepng_color_mode_alloc_palette(LodePNGColorMode* info) { } } -void lodepng_color_mode_cleanup(LodePNGColorMode* info) { +void lodepng_color_mode_cleanup(LodePNGColorMode *info) { lodepng_palette_clear(info); } -unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) { +unsigned lodepng_color_mode_copy(LodePNGColorMode *dest, + const LodePNGColorMode *source) { lodepng_color_mode_cleanup(dest); lodepng_memcpy(dest, source, sizeof(LodePNGColorMode)); - if(source->palette) { - dest->palette = (unsigned char*)lodepng_malloc(1024); - if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + if (source->palette) { + dest->palette = (unsigned char *)lodepng_malloc(1024); + if (!dest->palette && source->palettesize) + return 83; /*alloc fail*/ lodepng_memcpy(dest->palette, source->palette, source->palettesize * 4); } return 0; } -LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth) { +LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, + unsigned bitdepth) { LodePNGColorMode result; lodepng_color_mode_init(&result); result.colortype = colortype; @@ -2714,36 +3210,48 @@ LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bi return result; } -static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) { +static int lodepng_color_mode_equal(const LodePNGColorMode *a, + const LodePNGColorMode *b) { size_t i; - if(a->colortype != b->colortype) return 0; - if(a->bitdepth != b->bitdepth) return 0; - if(a->key_defined != b->key_defined) return 0; - if(a->key_defined) { - if(a->key_r != b->key_r) return 0; - if(a->key_g != b->key_g) return 0; - if(a->key_b != b->key_b) return 0; + if (a->colortype != b->colortype) + return 0; + if (a->bitdepth != b->bitdepth) + return 0; + if (a->key_defined != b->key_defined) + return 0; + if (a->key_defined) { + if (a->key_r != b->key_r) + return 0; + if (a->key_g != b->key_g) + return 0; + if (a->key_b != b->key_b) + return 0; } - if(a->palettesize != b->palettesize) return 0; - for(i = 0; i != a->palettesize * 4; ++i) { - if(a->palette[i] != b->palette[i]) return 0; + if (a->palettesize != b->palettesize) + return 0; + for (i = 0; i != a->palettesize * 4; ++i) { + if (a->palette[i] != b->palette[i]) + return 0; } return 1; } -void lodepng_palette_clear(LodePNGColorMode* info) { - if(info->palette) lodepng_free(info->palette); +void lodepng_palette_clear(LodePNGColorMode *info) { + if (info->palette) + lodepng_free(info->palette); info->palette = 0; info->palettesize = 0; } -unsigned lodepng_palette_add(LodePNGColorMode* info, - unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - if(!info->palette) /*allocate palette if empty*/ { +unsigned lodepng_palette_add(LodePNGColorMode *info, unsigned char r, + unsigned char g, unsigned char b, + unsigned char a) { + if (!info->palette) /*allocate palette if empty*/ { lodepng_color_mode_alloc_palette(info); - if(!info->palette) return 83; /*alloc fail*/ + if (!info->palette) + return 83; /*alloc fail*/ } - if(info->palettesize >= 256) { + if (info->palettesize >= 256) { return 108; /*too many palette values*/ } info->palette[4 * info->palettesize + 0] = r; @@ -2755,87 +3263,101 @@ unsigned lodepng_palette_add(LodePNGColorMode* info, } /*calculate bits per pixel out of colortype and bitdepth*/ -unsigned lodepng_get_bpp(const LodePNGColorMode* info) { +unsigned lodepng_get_bpp(const LodePNGColorMode *info) { return lodepng_get_bpp_lct(info->colortype, info->bitdepth); } -unsigned lodepng_get_channels(const LodePNGColorMode* info) { +unsigned lodepng_get_channels(const LodePNGColorMode *info) { return getNumColorChannels(info->colortype); } -unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) { +unsigned lodepng_is_greyscale_type(const LodePNGColorMode *info) { return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; } -unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) { +unsigned lodepng_is_alpha_type(const LodePNGColorMode *info) { return (info->colortype & 4) != 0; /*4 or 6*/ } -unsigned lodepng_is_palette_type(const LodePNGColorMode* info) { +unsigned lodepng_is_palette_type(const LodePNGColorMode *info) { return info->colortype == LCT_PALETTE; } -unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) { +unsigned lodepng_has_palette_alpha(const LodePNGColorMode *info) { size_t i; - for(i = 0; i != info->palettesize; ++i) { - if(info->palette[i * 4 + 3] < 255) return 1; + for (i = 0; i != info->palettesize; ++i) { + if (info->palette[i * 4 + 3] < 255) + return 1; } return 0; } -unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) { - return info->key_defined - || lodepng_is_alpha_type(info) - || lodepng_has_palette_alpha(info); +unsigned lodepng_can_have_alpha(const LodePNGColorMode *info) { + return info->key_defined || lodepng_is_alpha_type(info) || + lodepng_has_palette_alpha(info); } -static size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { +static size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, + LodePNGColorType colortype, + unsigned bitdepth) { size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth); size_t n = (size_t)w * (size_t)h; return ((n / 8u) * bpp) + ((n & 7u) * bpp + 7u) / 8u; } -size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) { +size_t lodepng_get_raw_size(unsigned w, unsigned h, + const LodePNGColorMode *color) { return lodepng_get_raw_size_lct(w, h, color->colortype, color->bitdepth); } - #ifdef LODEPNG_COMPILE_PNG -/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer, -and in addition has one extra byte per line: the filter byte. So this gives a larger -result than lodepng_get_raw_size. Set h to 1 to get the size of 1 row including filter byte. */ +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng +output buffer, and in addition has one extra byte per line: the filter byte. So +this gives a larger result than lodepng_get_raw_size. Set h to 1 to get the size +of 1 row including filter byte. */ static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, unsigned bpp) { /* + 1 for the filter byte, and possibly plus padding bits per line. */ - /* Ignoring casts, the expression is equal to (w * bpp + 7) / 8 + 1, but avoids overflow of w * bpp */ + /* Ignoring casts, the expression is equal to (w * bpp + 7) / 8 + 1, but + * avoids overflow of w * bpp */ size_t line = ((size_t)(w / 8u) * bpp) + 1u + ((w & 7u) * bpp + 7u) / 8u; return (size_t)h * line; } #ifdef LODEPNG_COMPILE_DECODER /*Safely checks whether size_t overflow can be caused due to amount of pixels. -This check is overcautious rather than precise. If this check indicates no overflow, -you can safely compute in a size_t (but not an unsigned): +This check is overcautious rather than precise. If this check indicates no +overflow, you can safely compute in a size_t (but not an unsigned): -(size_t)w * (size_t)h * 8 -amount of bytes in IDAT (including filter, padding and Adam7 bytes) -amount of bytes in raw color model Returns 1 if overflow possible, 0 if not. */ static int lodepng_pixel_overflow(unsigned w, unsigned h, - const LodePNGColorMode* pngcolor, const LodePNGColorMode* rawcolor) { - size_t bpp = LODEPNG_MAX(lodepng_get_bpp(pngcolor), lodepng_get_bpp(rawcolor)); + const LodePNGColorMode *pngcolor, + const LodePNGColorMode *rawcolor) { + size_t bpp = + LODEPNG_MAX(lodepng_get_bpp(pngcolor), lodepng_get_bpp(rawcolor)); size_t numpixels, total; size_t line; /* bytes per line in worst case */ - if(lodepng_mulofl((size_t)w, (size_t)h, &numpixels)) return 1; - if(lodepng_mulofl(numpixels, 8, &total)) return 1; /* bit pointer with 8-bit color, or 8 bytes per channel color */ + if (lodepng_mulofl((size_t)w, (size_t)h, &numpixels)) + return 1; + if (lodepng_mulofl(numpixels, 8, &total)) + return 1; /* bit pointer with 8-bit color, or 8 bytes per channel color */ - /* Bytes per scanline with the expression "(w / 8u) * bpp) + ((w & 7u) * bpp + 7u) / 8u" */ - if(lodepng_mulofl((size_t)(w / 8u), bpp, &line)) return 1; - if(lodepng_addofl(line, ((w & 7u) * bpp + 7u) / 8u, &line)) return 1; + /* Bytes per scanline with the expression "(w / 8u) * bpp) + ((w & 7u) * bpp + + * 7u) / 8u" */ + if (lodepng_mulofl((size_t)(w / 8u), bpp, &line)) + return 1; + if (lodepng_addofl(line, ((w & 7u) * bpp + 7u) / 8u, &line)) + return 1; - if(lodepng_addofl(line, 5, &line)) return 1; /* 5 bytes overhead per line: 1 filterbyte, 4 for Adam7 worst case */ - if(lodepng_mulofl(line, h, &total)) return 1; /* Total bytes in worst case */ + if (lodepng_addofl(line, 5, &line)) + return 1; /* 5 bytes overhead per line: 1 filterbyte, 4 for Adam7 worst case + */ + if (lodepng_mulofl(line, h, &total)) + return 1; /* Total bytes in worst case */ return 0; /* no overflow */ } @@ -2844,28 +3366,34 @@ static int lodepng_pixel_overflow(unsigned w, unsigned h, #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -static void LodePNGUnknownChunks_init(LodePNGInfo* info) { +static void LodePNGUnknownChunks_init(LodePNGInfo *info) { unsigned i; - for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; - for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; + for (i = 0; i != 3; ++i) + info->unknown_chunks_data[i] = 0; + for (i = 0; i != 3; ++i) + info->unknown_chunks_size[i] = 0; } -static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) { +static void LodePNGUnknownChunks_cleanup(LodePNGInfo *info) { unsigned i; - for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); + for (i = 0; i != 3; ++i) + lodepng_free(info->unknown_chunks_data[i]); } -static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) { +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo *dest, + const LodePNGInfo *src) { unsigned i; LodePNGUnknownChunks_cleanup(dest); - for(i = 0; i != 3; ++i) { + for (i = 0; i != 3; ++i) { size_t j; dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; - dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); - if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ - for(j = 0; j < src->unknown_chunks_size[i]; ++j) { + dest->unknown_chunks_data[i] = + (unsigned char *)lodepng_malloc(src->unknown_chunks_size[i]); + if (!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) + return 83; /*alloc fail*/ + for (j = 0; j < src->unknown_chunks_size[i]; ++j) { dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; } } @@ -2875,15 +3403,15 @@ static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* /******************************************************************************/ -static void LodePNGText_init(LodePNGInfo* info) { +static void LodePNGText_init(LodePNGInfo *info) { info->text_num = 0; info->text_keys = NULL; info->text_strings = NULL; } -static void LodePNGText_cleanup(LodePNGInfo* info) { +static void LodePNGText_cleanup(LodePNGInfo *info) { size_t i; - for(i = 0; i != info->text_num; ++i) { + for (i = 0; i != info->text_num; ++i) { string_cleanup(&info->text_keys[i]); string_cleanup(&info->text_strings[i]); } @@ -2891,45 +3419,52 @@ static void LodePNGText_cleanup(LodePNGInfo* info) { lodepng_free(info->text_strings); } -static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { +static unsigned LodePNGText_copy(LodePNGInfo *dest, const LodePNGInfo *source) { size_t i = 0; dest->text_keys = NULL; dest->text_strings = NULL; dest->text_num = 0; - for(i = 0; i != source->text_num; ++i) { - CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + for (i = 0; i != source->text_num; ++i) { + CERROR_TRY_RETURN( + lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); } return 0; } -static unsigned lodepng_add_text_sized(LodePNGInfo* info, const char* key, const char* str, size_t size) { - char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); - char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); +static unsigned lodepng_add_text_sized(LodePNGInfo *info, const char *key, + const char *str, size_t size) { + char **new_keys = (char **)(lodepng_realloc( + info->text_keys, sizeof(char *) * (info->text_num + 1))); + char **new_strings = (char **)(lodepng_realloc( + info->text_strings, sizeof(char *) * (info->text_num + 1))); - if(new_keys) info->text_keys = new_keys; - if(new_strings) info->text_strings = new_strings; + if (new_keys) + info->text_keys = new_keys; + if (new_strings) + info->text_strings = new_strings; - if(!new_keys || !new_strings) return 83; /*alloc fail*/ + if (!new_keys || !new_strings) + return 83; /*alloc fail*/ ++info->text_num; info->text_keys[info->text_num - 1] = alloc_string(key); info->text_strings[info->text_num - 1] = alloc_string_sized(str, size); - if(!info->text_keys[info->text_num - 1] || !info->text_strings[info->text_num - 1]) return 83; /*alloc fail*/ + if (!info->text_keys[info->text_num - 1] || + !info->text_strings[info->text_num - 1]) + return 83; /*alloc fail*/ return 0; } -unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { +unsigned lodepng_add_text(LodePNGInfo *info, const char *key, const char *str) { return lodepng_add_text_sized(info, key, str, lodepng_strlen(str)); } -void lodepng_clear_text(LodePNGInfo* info) { - LodePNGText_cleanup(info); -} +void lodepng_clear_text(LodePNGInfo *info) { LodePNGText_cleanup(info); } /******************************************************************************/ -static void LodePNGIText_init(LodePNGInfo* info) { +static void LodePNGIText_init(LodePNGInfo *info) { info->itext_num = 0; info->itext_keys = NULL; info->itext_langtags = NULL; @@ -2937,9 +3472,9 @@ static void LodePNGIText_init(LodePNGInfo* info) { info->itext_strings = NULL; } -static void LodePNGIText_cleanup(LodePNGInfo* info) { +static void LodePNGIText_cleanup(LodePNGInfo *info) { size_t i; - for(i = 0; i != info->itext_num; ++i) { + for (i = 0; i != info->itext_num; ++i) { string_cleanup(&info->itext_keys[i]); string_cleanup(&info->itext_langtags[i]); string_cleanup(&info->itext_transkeys[i]); @@ -2951,37 +3486,48 @@ static void LodePNGIText_cleanup(LodePNGInfo* info) { lodepng_free(info->itext_strings); } -static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { +static unsigned LodePNGIText_copy(LodePNGInfo *dest, + const LodePNGInfo *source) { size_t i = 0; dest->itext_keys = NULL; dest->itext_langtags = NULL; dest->itext_transkeys = NULL; dest->itext_strings = NULL; dest->itext_num = 0; - for(i = 0; i != source->itext_num; ++i) { - CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], - source->itext_transkeys[i], source->itext_strings[i])); + for (i = 0; i != source->itext_num; ++i) { + CERROR_TRY_RETURN(lodepng_add_itext( + dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); } return 0; } -void lodepng_clear_itext(LodePNGInfo* info) { - LodePNGIText_cleanup(info); -} +void lodepng_clear_itext(LodePNGInfo *info) { LodePNGIText_cleanup(info); } -static unsigned lodepng_add_itext_sized(LodePNGInfo* info, const char* key, const char* langtag, - const char* transkey, const char* str, size_t size) { - char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); - char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); - char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); - char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); +static unsigned lodepng_add_itext_sized(LodePNGInfo *info, const char *key, + const char *langtag, + const char *transkey, const char *str, + size_t size) { + char **new_keys = (char **)(lodepng_realloc( + info->itext_keys, sizeof(char *) * (info->itext_num + 1))); + char **new_langtags = (char **)(lodepng_realloc( + info->itext_langtags, sizeof(char *) * (info->itext_num + 1))); + char **new_transkeys = (char **)(lodepng_realloc( + info->itext_transkeys, sizeof(char *) * (info->itext_num + 1))); + char **new_strings = (char **)(lodepng_realloc( + info->itext_strings, sizeof(char *) * (info->itext_num + 1))); - if(new_keys) info->itext_keys = new_keys; - if(new_langtags) info->itext_langtags = new_langtags; - if(new_transkeys) info->itext_transkeys = new_transkeys; - if(new_strings) info->itext_strings = new_strings; + if (new_keys) + info->itext_keys = new_keys; + if (new_langtags) + info->itext_langtags = new_langtags; + if (new_transkeys) + info->itext_transkeys = new_transkeys; + if (new_strings) + info->itext_strings = new_strings; - if(!new_keys || !new_langtags || !new_transkeys || !new_strings) return 83; /*alloc fail*/ + if (!new_keys || !new_langtags || !new_transkeys || !new_strings) + return 83; /*alloc fail*/ ++info->itext_num; @@ -2993,19 +3539,25 @@ static unsigned lodepng_add_itext_sized(LodePNGInfo* info, const char* key, cons return 0; } -unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, - const char* transkey, const char* str) { - return lodepng_add_itext_sized(info, key, langtag, transkey, str, lodepng_strlen(str)); +unsigned lodepng_add_itext(LodePNGInfo *info, const char *key, + const char *langtag, const char *transkey, + const char *str) { + return lodepng_add_itext_sized(info, key, langtag, transkey, str, + lodepng_strlen(str)); } /* same as set but does not delete */ -static unsigned lodepng_assign_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) { - if(profile_size == 0) return 100; /*invalid ICC profile size*/ +static unsigned lodepng_assign_icc(LodePNGInfo *info, const char *name, + const unsigned char *profile, + unsigned profile_size) { + if (profile_size == 0) + return 100; /*invalid ICC profile size*/ info->iccp_name = alloc_string(name); - info->iccp_profile = (unsigned char*)lodepng_malloc(profile_size); + info->iccp_profile = (unsigned char *)lodepng_malloc(profile_size); - if(!info->iccp_name || !info->iccp_profile) return 83; /*alloc fail*/ + if (!info->iccp_name || !info->iccp_profile) + return 83; /*alloc fail*/ lodepng_memcpy(info->iccp_profile, profile, profile_size); info->iccp_profile_size = profile_size; @@ -3013,14 +3565,16 @@ static unsigned lodepng_assign_icc(LodePNGInfo* info, const char* name, const un return 0; /*ok*/ } -unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) { - if(info->iccp_name) lodepng_clear_icc(info); +unsigned lodepng_set_icc(LodePNGInfo *info, const char *name, + const unsigned char *profile, unsigned profile_size) { + if (info->iccp_name) + lodepng_clear_icc(info); info->iccp_defined = 1; return lodepng_assign_icc(info, name, profile, profile_size); } -void lodepng_clear_icc(LodePNGInfo* info) { +void lodepng_clear_icc(LodePNGInfo *info) { string_cleanup(&info->iccp_name); lodepng_free(info->iccp_profile); info->iccp_profile = NULL; @@ -3029,7 +3583,7 @@ void lodepng_clear_icc(LodePNGInfo* info) { } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -void lodepng_info_init(LodePNGInfo* info) { +void lodepng_info_init(LodePNGInfo *info) { lodepng_color_mode_init(&info->color); info->interlace_method = 0; info->compression_method = 0; @@ -3055,7 +3609,7 @@ void lodepng_info_init(LodePNGInfo* info) { #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } -void lodepng_info_cleanup(LodePNGInfo* info) { +void lodepng_info_cleanup(LodePNGInfo *info) { lodepng_color_mode_cleanup(&info->color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS LodePNGText_cleanup(info); @@ -3067,7 +3621,7 @@ void lodepng_info_cleanup(LodePNGInfo* info) { #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } -unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { +unsigned lodepng_info_copy(LodePNGInfo *dest, const LodePNGInfo *source) { lodepng_info_cleanup(dest); lodepng_memcpy(dest, source, sizeof(LodePNGInfo)); lodepng_color_mode_init(&dest->color); @@ -3076,8 +3630,10 @@ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); - if(source->iccp_defined) { - CERROR_TRY_RETURN(lodepng_assign_icc(dest, source->iccp_name, source->iccp_profile, source->iccp_profile_size)); + if (source->iccp_defined) { + CERROR_TRY_RETURN(lodepng_assign_icc(dest, source->iccp_name, + source->iccp_profile, + source->iccp_profile_size)); } LodePNGUnknownChunks_init(dest); @@ -3088,39 +3644,45 @@ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { /* ////////////////////////////////////////////////////////////////////////// */ -/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ -static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) { +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, + * out: octet array to add bits to*/ +static void addColorBits(unsigned char *out, size_t index, unsigned bits, + unsigned in) { unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ - /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first + * half or 1 for second half*/ unsigned p = index & m; in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ in = in << (bits * (m - p)); - if(p == 0) out[index * bits / 8u] = in; - else out[index * bits / 8u] |= in; + if (p == 0) + out[index * bits / 8u] = in; + else + out[index * bits / 8u] |= in; } typedef struct ColorTree ColorTree; /* One node of a color tree -This is the data structure used to count the number of unique colors and to get a palette -index for a color. It's like an octree, but because the alpha channel is used too, each -node has 16 instead of 8 children. +This is the data structure used to count the number of unique colors and to get +a palette index for a color. It's like an octree, but because the alpha channel +is used too, each node has 16 instead of 8 children. */ struct ColorTree { - ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ - int index; /*the payload. Only has a meaningful value if this is in the last level*/ + ColorTree *children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last + level*/ }; -static void color_tree_init(ColorTree* tree) { +static void color_tree_init(ColorTree *tree) { lodepng_memset(tree->children, 0, 16 * sizeof(*tree->children)); tree->index = -1; } -static void color_tree_cleanup(ColorTree* tree) { +static void color_tree_cleanup(ColorTree *tree) { int i; - for(i = 0; i != 16; ++i) { - if(tree->children[i]) { + for (i = 0; i != 16; ++i) { + if (tree->children[i]) { color_tree_cleanup(tree->children[i]); lodepng_free(tree->children[i]); } @@ -3128,33 +3690,41 @@ static void color_tree_cleanup(ColorTree* tree) { } /*returns -1 if color not present, its index otherwise*/ -static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { +static int color_tree_get(ColorTree *tree, unsigned char r, unsigned char g, + unsigned char b, unsigned char a) { int bit = 0; - for(bit = 0; bit < 8; ++bit) { - int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); - if(!tree->children[i]) return -1; - else tree = tree->children[i]; + for (bit = 0; bit < 8; ++bit) { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + + 1 * ((a >> bit) & 1); + if (!tree->children[i]) + return -1; + else + tree = tree->children[i]; } return tree ? tree->index : -1; } #ifdef LODEPNG_COMPILE_ENCODER -static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { +static int color_tree_has(ColorTree *tree, unsigned char r, unsigned char g, + unsigned char b, unsigned char a) { return color_tree_get(tree, r, g, b, a) >= 0; } #endif /*LODEPNG_COMPILE_ENCODER*/ /*color is not allowed to already exist. -Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist") -Returns error code, or 0 if ok*/ -static unsigned color_tree_add(ColorTree* tree, - unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) { +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't +exist") Returns error code, or 0 if ok*/ +static unsigned color_tree_add(ColorTree *tree, unsigned char r, + unsigned char g, unsigned char b, + unsigned char a, unsigned index) { int bit; - for(bit = 0; bit < 8; ++bit) { - int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); - if(!tree->children[i]) { - tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); - if(!tree->children[i]) return 83; /*alloc fail*/ + for (bit = 0; bit < 8; ++bit) { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + + 1 * ((a >> bit) & 1); + if (!tree->children[i]) { + tree->children[i] = (ColorTree *)lodepng_malloc(sizeof(ColorTree)); + if (!tree->children[i]) + return 83; /*alloc fail*/ color_tree_init(tree->children[i]); } tree = tree->children[i]; @@ -3164,20 +3734,25 @@ static unsigned color_tree_add(ColorTree* tree, } /*put a pixel, given its RGBA color, into image of any color type*/ -static unsigned rgba8ToPixel(unsigned char* out, size_t i, - const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, - unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - if(mode->colortype == LCT_GREY) { +static unsigned rgba8ToPixel(unsigned char *out, size_t i, + const LodePNGColorMode *mode, + ColorTree *tree /*for palette*/, unsigned char r, + unsigned char g, unsigned char b, + unsigned char a) { + if (mode->colortype == LCT_GREY) { unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/ - if(mode->bitdepth == 8) out[i] = gray; - else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = gray; + if (mode->bitdepth == 8) + out[i] = gray; + else if (mode->bitdepth == 16) + out[i * 2 + 0] = out[i * 2 + 1] = gray; else { /*take the most significant bits of gray*/ - gray = ((unsigned)gray >> (8u - mode->bitdepth)) & ((1u << mode->bitdepth) - 1u); + gray = ((unsigned)gray >> (8u - mode->bitdepth)) & + ((1u << mode->bitdepth) - 1u); addColorBits(out, i, mode->bitdepth, gray); } - } else if(mode->colortype == LCT_RGB) { - if(mode->bitdepth == 8) { + } else if (mode->colortype == LCT_RGB) { + if (mode->bitdepth == 8) { out[i * 3 + 0] = r; out[i * 3 + 1] = g; out[i * 3 + 2] = b; @@ -3186,22 +3761,25 @@ static unsigned rgba8ToPixel(unsigned char* out, size_t i, out[i * 6 + 2] = out[i * 6 + 3] = g; out[i * 6 + 4] = out[i * 6 + 5] = b; } - } else if(mode->colortype == LCT_PALETTE) { + } else if (mode->colortype == LCT_PALETTE) { int index = color_tree_get(tree, r, g, b, a); - if(index < 0) return 82; /*color not in palette*/ - if(mode->bitdepth == 8) out[i] = index; - else addColorBits(out, i, mode->bitdepth, (unsigned)index); - } else if(mode->colortype == LCT_GREY_ALPHA) { + if (index < 0) + return 82; /*color not in palette*/ + if (mode->bitdepth == 8) + out[i] = index; + else + addColorBits(out, i, mode->bitdepth, (unsigned)index); + } else if (mode->colortype == LCT_GREY_ALPHA) { unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/ - if(mode->bitdepth == 8) { + if (mode->bitdepth == 8) { out[i * 2 + 0] = gray; out[i * 2 + 1] = a; - } else if(mode->bitdepth == 16) { + } else if (mode->bitdepth == 16) { out[i * 4 + 0] = out[i * 4 + 1] = gray; out[i * 4 + 2] = out[i * 4 + 3] = a; } - } else if(mode->colortype == LCT_RGBA) { - if(mode->bitdepth == 8) { + } else if (mode->colortype == LCT_RGBA) { + if (mode->bitdepth == 8) { out[i * 4 + 0] = r; out[i * 4 + 1] = g; out[i * 4 + 2] = b; @@ -3217,28 +3795,30 @@ static unsigned rgba8ToPixel(unsigned char* out, size_t i, return 0; /*no error*/ } -/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ -static void rgba16ToPixel(unsigned char* out, size_t i, - const LodePNGColorMode* mode, - unsigned short r, unsigned short g, unsigned short b, unsigned short a) { - if(mode->colortype == LCT_GREY) { +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth + * type*/ +static void rgba16ToPixel(unsigned char *out, size_t i, + const LodePNGColorMode *mode, unsigned short r, + unsigned short g, unsigned short b, + unsigned short a) { + if (mode->colortype == LCT_GREY) { unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/ out[i * 2 + 0] = (gray >> 8) & 255; out[i * 2 + 1] = gray & 255; - } else if(mode->colortype == LCT_RGB) { + } else if (mode->colortype == LCT_RGB) { out[i * 6 + 0] = (r >> 8) & 255; out[i * 6 + 1] = r & 255; out[i * 6 + 2] = (g >> 8) & 255; out[i * 6 + 3] = g & 255; out[i * 6 + 4] = (b >> 8) & 255; out[i * 6 + 5] = b & 255; - } else if(mode->colortype == LCT_GREY_ALPHA) { + } else if (mode->colortype == LCT_GREY_ALPHA) { unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/ out[i * 4 + 0] = (gray >> 8) & 255; out[i * 4 + 1] = gray & 255; out[i * 4 + 2] = (a >> 8) & 255; out[i * 4 + 3] = a & 255; - } else if(mode->colortype == LCT_RGBA) { + } else if (mode->colortype == LCT_RGBA) { out[i * 8 + 0] = (r >> 8) & 255; out[i * 8 + 1] = r & 255; out[i * 8 + 2] = (g >> 8) & 255; @@ -3250,64 +3830,83 @@ static void rgba16ToPixel(unsigned char* out, size_t i, } } -/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ -static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, - unsigned char* b, unsigned char* a, - const unsigned char* in, size_t i, - const LodePNGColorMode* mode) { - if(mode->colortype == LCT_GREY) { - if(mode->bitdepth == 8) { +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with + * given color type.*/ +static void getPixelColorRGBA8(unsigned char *r, unsigned char *g, + unsigned char *b, unsigned char *a, + const unsigned char *in, size_t i, + const LodePNGColorMode *mode) { + if (mode->colortype == LCT_GREY) { + if (mode->bitdepth == 8) { *r = *g = *b = in[i]; - if(mode->key_defined && *r == mode->key_r) *a = 0; - else *a = 255; - } else if(mode->bitdepth == 16) { + if (mode->key_defined && *r == mode->key_r) + *a = 0; + else + *a = 255; + } else if (mode->bitdepth == 16) { *r = *g = *b = in[i * 2 + 0]; - if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; - else *a = 255; + if (mode->key_defined && + 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) + *a = 0; + else + *a = 255; } else { - unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + unsigned highest = ((1U << mode->bitdepth) - + 1U); /*highest possible value for this bit depth*/ size_t j = i * mode->bitdepth; unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); *r = *g = *b = (value * 255) / highest; - if(mode->key_defined && value == mode->key_r) *a = 0; - else *a = 255; + if (mode->key_defined && value == mode->key_r) + *a = 0; + else + *a = 255; } - } else if(mode->colortype == LCT_RGB) { - if(mode->bitdepth == 8) { - *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; - if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; - else *a = 255; + } else if (mode->colortype == LCT_RGB) { + if (mode->bitdepth == 8) { + *r = in[i * 3 + 0]; + *g = in[i * 3 + 1]; + *b = in[i * 3 + 2]; + if (mode->key_defined && *r == mode->key_r && *g == mode->key_g && + *b == mode->key_b) + *a = 0; + else + *a = 255; } else { *r = in[i * 6 + 0]; *g = in[i * 6 + 2]; *b = in[i * 6 + 4]; - if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r - && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g - && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; - else *a = 255; + if (mode->key_defined && + 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && + 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && + 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) + *a = 0; + else + *a = 255; } - } else if(mode->colortype == LCT_PALETTE) { + } else if (mode->colortype == LCT_PALETTE) { unsigned index; - if(mode->bitdepth == 8) index = in[i]; + if (mode->bitdepth == 8) + index = in[i]; else { size_t j = i * mode->bitdepth; index = readBitsFromReversedStream(&j, in, mode->bitdepth); } - /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + /*out of bounds of palette not checked: see + * lodepng_color_mode_alloc_palette.*/ *r = mode->palette[index * 4 + 0]; *g = mode->palette[index * 4 + 1]; *b = mode->palette[index * 4 + 2]; *a = mode->palette[index * 4 + 3]; - } else if(mode->colortype == LCT_GREY_ALPHA) { - if(mode->bitdepth == 8) { + } else if (mode->colortype == LCT_GREY_ALPHA) { + if (mode->bitdepth == 8) { *r = *g = *b = in[i * 2 + 0]; *a = in[i * 2 + 1]; } else { *r = *g = *b = in[i * 4 + 0]; *a = in[i * 4 + 2]; } - } else if(mode->colortype == LCT_RGBA) { - if(mode->bitdepth == 8) { + } else if (mode->colortype == LCT_RGBA) { + if (mode->bitdepth == 8) { *r = in[i * 4 + 0]; *g = in[i * 4 + 1]; *b = in[i * 4 + 2]; @@ -3325,92 +3924,105 @@ static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, mode test cases, optimized to convert the colors much faster, when converting to the common case of RGBA with 8 bit per channel. buffer must be RGBA with enough memory.*/ -static void getPixelColorsRGBA8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, - const unsigned char* LODEPNG_RESTRICT in, - const LodePNGColorMode* mode) { +static void getPixelColorsRGBA8(unsigned char *LODEPNG_RESTRICT buffer, + size_t numpixels, + const unsigned char *LODEPNG_RESTRICT in, + const LodePNGColorMode *mode) { unsigned num_channels = 4; size_t i; - if(mode->colortype == LCT_GREY) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + if (mode->colortype == LCT_GREY) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i]; buffer[3] = 255; } - if(mode->key_defined) { + if (mode->key_defined) { buffer -= numpixels * num_channels; - for(i = 0; i != numpixels; ++i, buffer += num_channels) { - if(buffer[0] == mode->key_r) buffer[3] = 0; + for (i = 0; i != numpixels; ++i, buffer += num_channels) { + if (buffer[0] == mode->key_r) + buffer[3] = 0; } } - } else if(mode->bitdepth == 16) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->bitdepth == 16) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2]; - buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + buffer[3] = mode->key_defined && + 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r + ? 0 + : 255; } } else { - unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + unsigned highest = ((1U << mode->bitdepth) - + 1U); /*highest possible value for this bit depth*/ size_t j = 0; - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; } } - } else if(mode->colortype == LCT_RGB) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->colortype == LCT_RGB) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { lodepng_memcpy(buffer, &in[i * 3], 3); buffer[3] = 255; } - if(mode->key_defined) { + if (mode->key_defined) { buffer -= numpixels * num_channels; - for(i = 0; i != numpixels; ++i, buffer += num_channels) { - if(buffer[0] == mode->key_r && buffer[1]== mode->key_g && buffer[2] == mode->key_b) buffer[3] = 0; + for (i = 0; i != numpixels; ++i, buffer += num_channels) { + if (buffer[0] == mode->key_r && buffer[1] == mode->key_g && + buffer[2] == mode->key_b) + buffer[3] = 0; } } } else { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 6 + 0]; buffer[1] = in[i * 6 + 2]; buffer[2] = in[i * 6 + 4]; - buffer[3] = mode->key_defined - && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r - && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g - && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + buffer[3] = + mode->key_defined && + 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && + 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && + 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b + ? 0 + : 255; } } - } else if(mode->colortype == LCT_PALETTE) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->colortype == LCT_PALETTE) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned index = in[i]; - /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + /*out of bounds of palette not checked: see + * lodepng_color_mode_alloc_palette.*/ lodepng_memcpy(buffer, &mode->palette[index * 4], 4); } } else { size_t j = 0; - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth); - /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + /*out of bounds of palette not checked: see + * lodepng_color_mode_alloc_palette.*/ lodepng_memcpy(buffer, &mode->palette[index * 4], 4); } } - } else if(mode->colortype == LCT_GREY_ALPHA) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->colortype == LCT_GREY_ALPHA) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; buffer[3] = in[i * 2 + 1]; } } else { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; buffer[3] = in[i * 4 + 2]; } } - } else if(mode->colortype == LCT_RGBA) { - if(mode->bitdepth == 8) { + } else if (mode->colortype == LCT_RGBA) { + if (mode->bitdepth == 8) { lodepng_memcpy(buffer, in, numpixels * 4); } else { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 8 + 0]; buffer[1] = in[i * 8 + 2]; buffer[2] = in[i * 8 + 4]; @@ -3421,70 +4033,74 @@ static void getPixelColorsRGBA8(unsigned char* LODEPNG_RESTRICT buffer, size_t n } /*Similar to getPixelColorsRGBA8, but with 3-channel RGB output.*/ -static void getPixelColorsRGB8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, - const unsigned char* LODEPNG_RESTRICT in, - const LodePNGColorMode* mode) { +static void getPixelColorsRGB8(unsigned char *LODEPNG_RESTRICT buffer, + size_t numpixels, + const unsigned char *LODEPNG_RESTRICT in, + const LodePNGColorMode *mode) { const unsigned num_channels = 3; size_t i; - if(mode->colortype == LCT_GREY) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + if (mode->colortype == LCT_GREY) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i]; } - } else if(mode->bitdepth == 16) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->bitdepth == 16) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2]; } } else { - unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + unsigned highest = ((1U << mode->bitdepth) - + 1U); /*highest possible value for this bit depth*/ size_t j = 0; - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; } } - } else if(mode->colortype == LCT_RGB) { - if(mode->bitdepth == 8) { + } else if (mode->colortype == LCT_RGB) { + if (mode->bitdepth == 8) { lodepng_memcpy(buffer, in, numpixels * 3); } else { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 6 + 0]; buffer[1] = in[i * 6 + 2]; buffer[2] = in[i * 6 + 4]; } } - } else if(mode->colortype == LCT_PALETTE) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->colortype == LCT_PALETTE) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned index = in[i]; - /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + /*out of bounds of palette not checked: see + * lodepng_color_mode_alloc_palette.*/ lodepng_memcpy(buffer, &mode->palette[index * 4], 3); } } else { size_t j = 0; - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth); - /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + /*out of bounds of palette not checked: see + * lodepng_color_mode_alloc_palette.*/ lodepng_memcpy(buffer, &mode->palette[index * 4], 3); } } - } else if(mode->colortype == LCT_GREY_ALPHA) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->colortype == LCT_GREY_ALPHA) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; } } else { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; } } - } else if(mode->colortype == LCT_RGBA) { - if(mode->bitdepth == 8) { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + } else if (mode->colortype == LCT_RGBA) { + if (mode->bitdepth == 8) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { lodepng_memcpy(buffer, &in[i * 4], 3); } } else { - for(i = 0; i != numpixels; ++i, buffer += num_channels) { + for (i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 8 + 0]; buffer[1] = in[i * 8 + 2]; buffer[2] = in[i * 8 + 4]; @@ -3495,25 +4111,32 @@ static void getPixelColorsRGB8(unsigned char* LODEPNG_RESTRICT buffer, size_t nu /*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with given color type, but the given color type must be 16-bit itself.*/ -static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, - const unsigned char* in, size_t i, const LodePNGColorMode* mode) { - if(mode->colortype == LCT_GREY) { +static void getPixelColorRGBA16(unsigned short *r, unsigned short *g, + unsigned short *b, unsigned short *a, + const unsigned char *in, size_t i, + const LodePNGColorMode *mode) { + if (mode->colortype == LCT_GREY) { *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; - if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; - else *a = 65535; - } else if(mode->colortype == LCT_RGB) { + if (mode->key_defined && + 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) + *a = 0; + else + *a = 65535; + } else if (mode->colortype == LCT_RGB) { *r = 256u * in[i * 6 + 0] + in[i * 6 + 1]; *g = 256u * in[i * 6 + 2] + in[i * 6 + 3]; *b = 256u * in[i * 6 + 4] + in[i * 6 + 5]; - if(mode->key_defined - && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r - && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g - && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; - else *a = 65535; - } else if(mode->colortype == LCT_GREY_ALPHA) { + if (mode->key_defined && + 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r && + 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g && + 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) + *a = 0; + else + *a = 65535; + } else if (mode->colortype == LCT_GREY_ALPHA) { *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1]; *a = 256u * in[i * 4 + 2] + in[i * 4 + 3]; - } else if(mode->colortype == LCT_RGBA) { + } else if (mode->colortype == LCT_RGBA) { *r = 256u * in[i * 8 + 0] + in[i * 8 + 1]; *g = 256u * in[i * 8 + 2] + in[i * 8 + 3]; *b = 256u * in[i * 8 + 4] + in[i * 8 + 5]; @@ -3521,103 +4144,111 @@ static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned s } } -unsigned lodepng_convert(unsigned char* out, const unsigned char* in, - const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, - unsigned w, unsigned h) { +unsigned lodepng_convert(unsigned char *out, const unsigned char *in, + const LodePNGColorMode *mode_out, + const LodePNGColorMode *mode_in, unsigned w, + unsigned h) { size_t i; ColorTree tree; size_t numpixels = (size_t)w * (size_t)h; unsigned error = 0; - if(mode_in->colortype == LCT_PALETTE && !mode_in->palette) { + if (mode_in->colortype == LCT_PALETTE && !mode_in->palette) { return 107; /* error: must provide palette if input mode is palette */ } - if(lodepng_color_mode_equal(mode_out, mode_in)) { + if (lodepng_color_mode_equal(mode_out, mode_in)) { size_t numbytes = lodepng_get_raw_size(w, h, mode_in); lodepng_memcpy(out, in, numbytes); return 0; } - if(mode_out->colortype == LCT_PALETTE) { + if (mode_out->colortype == LCT_PALETTE) { size_t palettesize = mode_out->palettesize; - const unsigned char* palette = mode_out->palette; + const unsigned char *palette = mode_out->palette; size_t palsize = (size_t)1u << mode_out->bitdepth; /*if the user specified output palette but did not give the values, assume they want the values of the input color type (assuming that one is palette). Note that we never create a new palette ourselves.*/ - if(palettesize == 0) { + if (palettesize == 0) { palettesize = mode_in->palettesize; palette = mode_in->palette; - /*if the input was also palette with same bitdepth, then the color types are also - equal, so copy literally. This to preserve the exact indices that were in the PNG - even in case there are duplicate colors in the palette.*/ - if(mode_in->colortype == LCT_PALETTE && mode_in->bitdepth == mode_out->bitdepth) { + /*if the input was also palette with same bitdepth, then the color types + are also equal, so copy literally. This to preserve the exact indices that + were in the PNG even in case there are duplicate colors in the palette.*/ + if (mode_in->colortype == LCT_PALETTE && + mode_in->bitdepth == mode_out->bitdepth) { size_t numbytes = lodepng_get_raw_size(w, h, mode_in); lodepng_memcpy(out, in, numbytes); return 0; } } - if(palettesize < palsize) palsize = palettesize; + if (palettesize < palsize) + palsize = palettesize; color_tree_init(&tree); - for(i = 0; i != palsize; ++i) { - const unsigned char* p = &palette[i * 4]; + for (i = 0; i != palsize; ++i) { + const unsigned char *p = &palette[i * 4]; error = color_tree_add(&tree, p[0], p[1], p[2], p[3], (unsigned)i); - if(error) break; + if (error) + break; } } - if(!error) { - if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) { - for(i = 0; i != numpixels; ++i) { + if (!error) { + if (mode_in->bitdepth == 16 && mode_out->bitdepth == 16) { + for (i = 0; i != numpixels; ++i) { unsigned short r = 0, g = 0, b = 0, a = 0; getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); rgba16ToPixel(out, i, mode_out, r, g, b, a); } - } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) { + } else if (mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) { getPixelColorsRGBA8(out, numpixels, in, mode_in); - } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) { + } else if (mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) { getPixelColorsRGB8(out, numpixels, in, mode_in); } else { unsigned char r = 0, g = 0, b = 0, a = 0; - for(i = 0; i != numpixels; ++i) { + for (i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); - if(error) break; + if (error) + break; } } } - if(mode_out->colortype == LCT_PALETTE) { + if (mode_out->colortype == LCT_PALETTE) { color_tree_cleanup(&tree); } return error; } - -/* Converts a single rgb color without alpha from one type to another, color bits truncated to -their bitdepth. In case of single channel (gray or palette), only the r channel is used. Slow -function, do not use to process all pixels of an image. Alpha channel not supported on purpose: -this is for bKGD, supporting alpha may prevent it from finding a color in the palette, from the -specification it looks like bKGD should ignore the alpha values of the palette since it can use -any palette index but doesn't have an alpha channel. Idem with ignoring color key. */ -unsigned lodepng_convert_rgb( - unsigned* r_out, unsigned* g_out, unsigned* b_out, - unsigned r_in, unsigned g_in, unsigned b_in, - const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in) { +/* Converts a single rgb color without alpha from one type to another, color +bits truncated to their bitdepth. In case of single channel (gray or palette), +only the r channel is used. Slow function, do not use to process all pixels of +an image. Alpha channel not supported on purpose: this is for bKGD, supporting +alpha may prevent it from finding a color in the palette, from the specification +it looks like bKGD should ignore the alpha values of the palette since it can +use any palette index but doesn't have an alpha channel. Idem with ignoring +color key. */ +unsigned lodepng_convert_rgb(unsigned *r_out, unsigned *g_out, unsigned *b_out, + unsigned r_in, unsigned g_in, unsigned b_in, + const LodePNGColorMode *mode_out, + const LodePNGColorMode *mode_in) { unsigned r = 0, g = 0, b = 0; - unsigned mul = 65535 / ((1u << mode_in->bitdepth) - 1u); /*65535, 21845, 4369, 257, 1*/ + unsigned mul = + 65535 / ((1u << mode_in->bitdepth) - 1u); /*65535, 21845, 4369, 257, 1*/ unsigned shift = 16 - mode_out->bitdepth; - if(mode_in->colortype == LCT_GREY || mode_in->colortype == LCT_GREY_ALPHA) { + if (mode_in->colortype == LCT_GREY || mode_in->colortype == LCT_GREY_ALPHA) { r = g = b = r_in * mul; - } else if(mode_in->colortype == LCT_RGB || mode_in->colortype == LCT_RGBA) { + } else if (mode_in->colortype == LCT_RGB || mode_in->colortype == LCT_RGBA) { r = r_in * mul; g = g_in * mul; b = b_in * mul; - } else if(mode_in->colortype == LCT_PALETTE) { - if(r_in >= mode_in->palettesize) return 82; + } else if (mode_in->colortype == LCT_PALETTE) { + if (r_in >= mode_in->palettesize) + return 82; r = mode_in->palette[r_in * 4 + 0] * 257u; g = mode_in->palette[r_in * 4 + 1] * 257u; b = mode_in->palette[r_in * 4 + 2] * 257u; @@ -3626,19 +4257,23 @@ unsigned lodepng_convert_rgb( } /* now convert to output format */ - if(mode_out->colortype == LCT_GREY || mode_out->colortype == LCT_GREY_ALPHA) { - *r_out = r >> shift ; - } else if(mode_out->colortype == LCT_RGB || mode_out->colortype == LCT_RGBA) { - *r_out = r >> shift ; - *g_out = g >> shift ; - *b_out = b >> shift ; - } else if(mode_out->colortype == LCT_PALETTE) { + if (mode_out->colortype == LCT_GREY || + mode_out->colortype == LCT_GREY_ALPHA) { + *r_out = r >> shift; + } else if (mode_out->colortype == LCT_RGB || + mode_out->colortype == LCT_RGBA) { + *r_out = r >> shift; + *g_out = g >> shift; + *b_out = b >> shift; + } else if (mode_out->colortype == LCT_PALETTE) { unsigned i; /* a 16-bit color cannot be in the palette */ - if((r >> 8) != (r & 255) || (g >> 8) != (g & 255) || (b >> 8) != (b & 255)) return 82; - for(i = 0; i < mode_out->palettesize; i++) { + if ((r >> 8) != (r & 255) || (g >> 8) != (g & 255) || (b >> 8) != (b & 255)) + return 82; + for (i = 0; i < mode_out->palettesize; i++) { unsigned j = i * 4; - if((r >> 8) == mode_out->palette[j + 0] && (g >> 8) == mode_out->palette[j + 1] && + if ((r >> 8) == mode_out->palette[j + 0] && + (g >> 8) == mode_out->palette[j + 1] && (b >> 8) == mode_out->palette[j + 2]) { *r_out = i; return 0; @@ -3654,7 +4289,7 @@ unsigned lodepng_convert_rgb( #ifdef LODEPNG_COMPILE_ENCODER -void lodepng_color_stats_init(LodePNGColorStats* stats) { +void lodepng_color_stats_init(LodePNGColorStats *stats) { /*stats*/ stats->colored = 0; stats->key = 0; @@ -3682,22 +4317,26 @@ void lodepng_color_stats_init(LodePNGColorStats* stats) { /*Returns how many bits needed to represent given value (max 8 bit)*/ static unsigned getValueRequiredBits(unsigned char value) { - if(value == 0 || value == 255) return 1; + if (value == 0 || value == 255) + return 1; /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ - if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + if (value % 17 == 0) + return value % 85 == 0 ? 2 : 4; return 8; } /*stats must already have been inited. */ -unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, - const unsigned char* in, unsigned w, unsigned h, - const LodePNGColorMode* mode_in) { +unsigned lodepng_compute_color_stats(LodePNGColorStats *stats, + const unsigned char *in, unsigned w, + unsigned h, + const LodePNGColorMode *mode_in) { size_t i; ColorTree tree; size_t numpixels = (size_t)w * (size_t)h; unsigned error = 0; - /* mark things as done already if it would be impossible to have a more expensive case */ + /* mark things as done already if it would be impossible to have a more + * expensive case */ unsigned colored_done = lodepng_is_greyscale_type(mode_in) ? 1 : 0; unsigned alpha_done = lodepng_can_have_alpha(mode_in) ? 0 : 1; unsigned numcolors_done = 0; @@ -3705,84 +4344,100 @@ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, unsigned bits_done = (stats->bits == 1 && bpp == 1) ? 1 : 0; unsigned sixteen = 0; /* whether the input image is 16 bit */ unsigned maxnumcolors = 257; - if(bpp <= 8) maxnumcolors = LODEPNG_MIN(257, stats->numcolors + (1u << bpp)); + if (bpp <= 8) + maxnumcolors = LODEPNG_MIN(257, stats->numcolors + (1u << bpp)); stats->numpixels += numpixels; /*if palette not allowed, no need to compute numcolors*/ - if(!stats->allow_palette) numcolors_done = 1; + if (!stats->allow_palette) + numcolors_done = 1; color_tree_init(&tree); - /*If the stats was already filled in from previous data, fill its palette in tree - and mark things as done already if we know they are the most expensive case already*/ - if(stats->alpha) alpha_done = 1; - if(stats->colored) colored_done = 1; - if(stats->bits == 16) numcolors_done = 1; - if(stats->bits >= bpp) bits_done = 1; - if(stats->numcolors >= maxnumcolors) numcolors_done = 1; + /*If the stats was already filled in from previous data, fill its palette in + tree and mark things as done already if we know they are the most expensive + case already*/ + if (stats->alpha) + alpha_done = 1; + if (stats->colored) + colored_done = 1; + if (stats->bits == 16) + numcolors_done = 1; + if (stats->bits >= bpp) + bits_done = 1; + if (stats->numcolors >= maxnumcolors) + numcolors_done = 1; - if(!numcolors_done) { - for(i = 0; i < stats->numcolors; i++) { - const unsigned char* color = &stats->palette[i * 4]; + if (!numcolors_done) { + for (i = 0; i < stats->numcolors; i++) { + const unsigned char *color = &stats->palette[i * 4]; error = color_tree_add(&tree, color[0], color[1], color[2], color[3], i); - if(error) goto cleanup; + if (error) + goto cleanup; } } /*Check if the 16-bit input is truly 16-bit*/ - if(mode_in->bitdepth == 16 && !sixteen) { + if (mode_in->bitdepth == 16 && !sixteen) { unsigned short r = 0, g = 0, b = 0, a = 0; - for(i = 0; i != numpixels; ++i) { + for (i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); - if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || - (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ { + if ((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || + (b & 255) != ((b >> 8) & 255) || + (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ { stats->bits = 16; sixteen = 1; bits_done = 1; - numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + numcolors_done = 1; /*counting colors no longer useful, palette doesn't + support 16-bit*/ break; } } } - if(sixteen) { + if (sixteen) { unsigned short r = 0, g = 0, b = 0, a = 0; - for(i = 0; i != numpixels; ++i) { + for (i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); - if(!colored_done && (r != g || r != b)) { + if (!colored_done && (r != g || r != b)) { stats->colored = 1; colored_done = 1; } - if(!alpha_done) { - unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b); - if(a != 65535 && (a != 0 || (stats->key && !matchkey))) { + if (!alpha_done) { + unsigned matchkey = + (r == stats->key_r && g == stats->key_g && b == stats->key_b); + if (a != 65535 && (a != 0 || (stats->key && !matchkey))) { stats->alpha = 1; stats->key = 0; alpha_done = 1; - } else if(a == 0 && !stats->alpha && !stats->key) { + } else if (a == 0 && !stats->alpha && !stats->key) { stats->key = 1; stats->key_r = r; stats->key_g = g; stats->key_b = b; - } else if(a == 65535 && stats->key && matchkey) { - /* Color key cannot be used if an opaque pixel also has that RGB color. */ + } else if (a == 65535 && stats->key && matchkey) { + /* Color key cannot be used if an opaque pixel also has that RGB + * color. */ stats->alpha = 1; stats->key = 0; alpha_done = 1; } } - if(alpha_done && numcolors_done && colored_done && bits_done) break; + if (alpha_done && numcolors_done && colored_done && bits_done) + break; } - if(stats->key && !stats->alpha) { - for(i = 0; i != numpixels; ++i) { + if (stats->key && !stats->alpha) { + for (i = 0; i != numpixels; ++i) { getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); - if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) { - /* Color key cannot be used if an opaque pixel also has that RGB color. */ + if (a != 0 && r == stats->key_r && g == stats->key_g && + b == stats->key_b) { + /* Color key cannot be used if an opaque pixel also has that RGB + * color. */ stats->alpha = 1; stats->key = 0; alpha_done = 1; @@ -3791,49 +4446,59 @@ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, } } else /* < 16-bit */ { unsigned char r = 0, g = 0, b = 0, a = 0; - for(i = 0; i != numpixels; ++i) { + for (i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); - if(!bits_done && stats->bits < 8) { + if (!bits_done && stats->bits < 8) { /*only r is checked, < 8 bits is only relevant for grayscale*/ unsigned bits = getValueRequiredBits(r); - if(bits > stats->bits) stats->bits = bits; + if (bits > stats->bits) + stats->bits = bits; } bits_done = (stats->bits >= bpp); - if(!colored_done && (r != g || r != b)) { + if (!colored_done && (r != g || r != b)) { stats->colored = 1; colored_done = 1; - if(stats->bits < 8) stats->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + if (stats->bits < 8) + stats->bits = + 8; /*PNG has no colored modes with less than 8-bit per channel*/ } - if(!alpha_done) { - unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b); - if(a != 255 && (a != 0 || (stats->key && !matchkey))) { + if (!alpha_done) { + unsigned matchkey = + (r == stats->key_r && g == stats->key_g && b == stats->key_b); + if (a != 255 && (a != 0 || (stats->key && !matchkey))) { stats->alpha = 1; stats->key = 0; alpha_done = 1; - if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ - } else if(a == 0 && !stats->alpha && !stats->key) { + if (stats->bits < 8) + stats->bits = 8; /*PNG has no alphachannel modes with less than + 8-bit per channel*/ + } else if (a == 0 && !stats->alpha && !stats->key) { stats->key = 1; stats->key_r = r; stats->key_g = g; stats->key_b = b; - } else if(a == 255 && stats->key && matchkey) { - /* Color key cannot be used if an opaque pixel also has that RGB color. */ + } else if (a == 255 && stats->key && matchkey) { + /* Color key cannot be used if an opaque pixel also has that RGB + * color. */ stats->alpha = 1; stats->key = 0; alpha_done = 1; - if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + if (stats->bits < 8) + stats->bits = 8; /*PNG has no alphachannel modes with less than + 8-bit per channel*/ } } - if(!numcolors_done) { - if(!color_tree_has(&tree, r, g, b, a)) { + if (!numcolors_done) { + if (!color_tree_has(&tree, r, g, b, a)) { error = color_tree_add(&tree, r, g, b, a, stats->numcolors); - if(error) goto cleanup; - if(stats->numcolors < 256) { - unsigned char* p = stats->palette; + if (error) + goto cleanup; + if (stats->numcolors < 256) { + unsigned char *p = stats->palette; unsigned n = stats->numcolors; p[n * 4 + 0] = r; p[n * 4 + 1] = g; @@ -3845,23 +4510,29 @@ unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, } } - if(alpha_done && numcolors_done && colored_done && bits_done) break; + if (alpha_done && numcolors_done && colored_done && bits_done) + break; } - if(stats->key && !stats->alpha) { - for(i = 0; i != numpixels; ++i) { + if (stats->key && !stats->alpha) { + for (i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); - if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) { - /* Color key cannot be used if an opaque pixel also has that RGB color. */ + if (a != 0 && r == stats->key_r && g == stats->key_g && + b == stats->key_b) { + /* Color key cannot be used if an opaque pixel also has that RGB + * color. */ stats->alpha = 1; stats->key = 0; alpha_done = 1; - if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + if (stats->bits < 8) + stats->bits = 8; /*PNG has no alphachannel modes with less than + 8-bit per channel*/ } } } - /*make the stats's key always 16-bit for consistency - repeat each byte twice*/ + /*make the stats's key always 16-bit for consistency - repeat each byte + * twice*/ stats->key_r += (stats->key_r << 8); stats->key_g += (stats->key_g << 8); stats->key_b += (stats->key_b << 8); @@ -3873,17 +4544,24 @@ cleanup: } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -/*Adds a single color to the color stats. The stats must already have been inited. The color must be given as 16-bit -(with 2 bytes repeating for 8-bit and 65535 for opaque alpha channel). This function is expensive, do not call it for +/*Adds a single color to the color stats. The stats must already have been +inited. The color must be given as 16-bit (with 2 bytes repeating for 8-bit and +65535 for opaque alpha channel). This function is expensive, do not call it for all pixels of an image but only for a few additional values. */ -static unsigned lodepng_color_stats_add(LodePNGColorStats* stats, - unsigned r, unsigned g, unsigned b, unsigned a) { +static unsigned lodepng_color_stats_add(LodePNGColorStats *stats, unsigned r, + unsigned g, unsigned b, unsigned a) { unsigned error = 0; unsigned char image[8]; LodePNGColorMode mode; lodepng_color_mode_init(&mode); - image[0] = r >> 8; image[1] = r; image[2] = g >> 8; image[3] = g; - image[4] = b >> 8; image[5] = b; image[6] = a >> 8; image[7] = a; + image[0] = r >> 8; + image[1] = r; + image[2] = g >> 8; + image[3] = g; + image[4] = b >> 8; + image[5] = b; + image[6] = a >> 8; + image[7] = a; mode.bitdepth = 16; mode.colortype = LCT_RGBA; error = lodepng_compute_color_stats(stats, image, 1, 1, &mode); @@ -3892,16 +4570,18 @@ static unsigned lodepng_color_stats_add(LodePNGColorStats* stats, } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -/*Computes a minimal PNG color model that can contain all colors as indicated by the stats. -The stats should be computed with lodepng_compute_color_stats. -mode_in is raw color profile of the image the stats were computed on, to copy palette order from when relevant. -Minimal PNG color model means the color type and bit depth that gives smallest amount of bits in the output image, -e.g. gray if only grayscale pixels, palette if less than 256 colors, color key if only single transparent color, ... -This is used if auto_convert is enabled (it is by default). +/*Computes a minimal PNG color model that can contain all colors as indicated by +the stats. The stats should be computed with lodepng_compute_color_stats. +mode_in is raw color profile of the image the stats were computed on, to copy +palette order from when relevant. Minimal PNG color model means the color type +and bit depth that gives smallest amount of bits in the output image, e.g. gray +if only grayscale pixels, palette if less than 256 colors, color key if only +single transparent color, ... This is used if auto_convert is enabled (it is by +default). */ -static unsigned auto_choose_color(LodePNGColorMode* mode_out, - const LodePNGColorMode* mode_in, - const LodePNGColorStats* stats) { +static unsigned auto_choose_color(LodePNGColorMode *mode_out, + const LodePNGColorMode *mode_in, + const LodePNGColorStats *stats) { unsigned error = 0; unsigned palettebits; size_t i, n; @@ -3914,37 +4594,50 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out, mode_out->key_defined = 0; - if(key && numpixels <= 16) { + if (key && numpixels <= 16) { alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ key = 0; - if(bits < 8) bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + if (bits < 8) + bits = + 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } gray_ok = !stats->colored; - if(!stats->allow_greyscale) gray_ok = 0; - if(!gray_ok && bits < 8) bits = 8; + if (!stats->allow_greyscale) + gray_ok = 0; + if (!gray_ok && bits < 8) + bits = 8; n = stats->numcolors; palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); - palette_ok = n <= 256 && bits <= 8 && n != 0; /*n==0 means likely numcolors wasn't computed*/ - if(numpixels < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ - if(gray_ok && !alpha && bits <= palettebits) palette_ok = 0; /*gray is less overhead*/ - if(!stats->allow_palette) palette_ok = 0; + palette_ok = n <= 256 && bits <= 8 && + n != 0; /*n==0 means likely numcolors wasn't computed*/ + if (numpixels < n * 2) + palette_ok = + 0; /*don't add palette overhead if image has only a few pixels*/ + if (gray_ok && !alpha && bits <= palettebits) + palette_ok = 0; /*gray is less overhead*/ + if (!stats->allow_palette) + palette_ok = 0; - if(palette_ok) { - const unsigned char* p = stats->palette; + if (palette_ok) { + const unsigned char *p = stats->palette; lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ - for(i = 0; i != stats->numcolors; ++i) { - error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); - if(error) break; + for (i = 0; i != stats->numcolors; ++i) { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], + p[i * 4 + 2], p[i * 4 + 3]); + if (error) + break; } mode_out->colortype = LCT_PALETTE; mode_out->bitdepth = palettebits; - if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize - && mode_in->bitdepth == mode_out->bitdepth) { - /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + if (mode_in->colortype == LCT_PALETTE && + mode_in->palettesize >= mode_out->palettesize && + mode_in->bitdepth == mode_out->bitdepth) { + /*If input should have same palette colors, keep original to preserve its + * order and prevent conversion*/ lodepng_color_mode_cleanup(mode_out); lodepng_color_mode_copy(mode_out, mode_in); } @@ -3952,8 +4645,9 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out, mode_out->bitdepth = bits; mode_out->colortype = alpha ? (gray_ok ? LCT_GREY_ALPHA : LCT_RGBA) : (gray_ok ? LCT_GREY : LCT_RGB); - if(key) { - unsigned mask = (1u << mode_out->bitdepth) - 1u; /*stats always uses 16-bit, mask converts it*/ + if (key) { + unsigned mask = (1u << mode_out->bitdepth) - + 1u; /*stats always uses 16-bit, mask converts it*/ mode_out->key_r = stats->key_r & mask; mode_out->key_g = stats->key_g & mask; mode_out->key_b = stats->key_b & mask; @@ -3968,31 +4662,34 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out, /* Paeth predictor, used by PNG filter type 4 -The parameters are of type short, but should come from unsigned chars, the shorts -are only needed to make the paeth calculation correct. +The parameters are of type short, but should come from unsigned chars, the +shorts are only needed to make the paeth calculation correct. */ static unsigned char paethPredictor(short a, short b, short c) { short pa = LODEPNG_ABS(b - c); short pb = LODEPNG_ABS(a - c); short pc = LODEPNG_ABS(a + b - c - c); - /* return input value associated with smallest of pa, pb, pc (with certain priority if equal) */ - if(pb < pa) { a = b; pa = pb; } + /* return input value associated with smallest of pa, pb, pc (with certain + * priority if equal) */ + if (pb < pa) { + a = b; + pa = pb; + } return (pc < pa) ? c : a; } /*shared values used by multiple Adam7 related functions*/ -static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ -static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ -static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ -static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ +static const unsigned ADAM7_IX[7] = {0, 4, 0, 2, 0, 1, 0}; /*x start values*/ +static const unsigned ADAM7_IY[7] = {0, 0, 4, 0, 2, 0, 1}; /*y start values*/ +static const unsigned ADAM7_DX[7] = {8, 8, 4, 4, 2, 2, 1}; /*x delta values*/ +static const unsigned ADAM7_DY[7] = {8, 8, 8, 4, 4, 2, 2}; /*y delta values*/ /* -Outputs various dimensions and positions in the image related to the Adam7 reduced images. -passw: output containing the width of the 7 passes -passh: output containing the height of the 7 passes -filter_passstart: output containing the index of the start and end of each - reduced image with filter bytes +Outputs various dimensions and positions in the image related to the Adam7 +reduced images. passw: output containing the width of the 7 passes passh: output +containing the height of the 7 passes filter_passstart: output containing the +index of the start and end of each reduced image with filter bytes padded_passstart output containing the index of the start and end of each reduced image when without filter bytes but with padded scanlines passstart: output containing the index of the start and end of each reduced @@ -4002,26 +4699,34 @@ bpp: bits per pixel "padded" is only relevant if bpp is less than 8 and a scanline or image does not end at a full byte */ -static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], - size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) { - /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], + size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], + unsigned w, unsigned h, unsigned bpp) { + /*the passstart values have 8 values: the 8th one indicates the byte after the + * end of the 7th (= last) pass*/ unsigned i; /*calculate width and height in pixels of each pass*/ - for(i = 0; i != 7; ++i) { + for (i = 0; i != 7; ++i) { passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; - if(passw[i] == 0) passh[i] = 0; - if(passh[i] == 0) passw[i] = 0; + if (passw[i] == 0) + passh[i] = 0; + if (passh[i] == 0) + passw[i] = 0; } filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; - for(i = 0; i != 7; ++i) { + for (i = 0; i != 7; ++i) { /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ - filter_passstart[i + 1] = filter_passstart[i] - + ((passw[i] && passh[i]) ? passh[i] * (1u + (passw[i] * bpp + 7u) / 8u) : 0); + filter_passstart[i + 1] = + filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1u + (passw[i] * bpp + 7u) / 8u) + : 0); /*bits padded if needed to fill full byte at end of each scanline*/ - padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7u) / 8u); + padded_passstart[i + 1] = + padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7u) / 8u); /*only padded at end of reduced image*/ passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7u) / 8u; } @@ -4033,40 +4738,50 @@ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t fil /* / PNG Decoder / */ /* ////////////////////////////////////////////////////////////////////////// */ -/*read the information from the header and store it in the LodePNGInfo. return value is error*/ -unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, - const unsigned char* in, size_t insize) { +/*read the information from the header and store it in the LodePNGInfo. return + * value is error*/ +unsigned lodepng_inspect(unsigned *w, unsigned *h, LodePNGState *state, + const unsigned char *in, size_t insize) { unsigned width, height; - LodePNGInfo* info = &state->info_png; - if(insize == 0 || in == 0) { + LodePNGInfo *info = &state->info_png; + if (insize == 0 || in == 0) { CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ } - if(insize < 33) { - CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + if (insize < 33) { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller + than the length of a PNG header*/ } - /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + /*when decoding a new PNG image, make sure all parameters created after + * previous decoding are reset*/ /* TODO: remove this. One should use a new LodePNGState for new sessions */ lodepng_info_cleanup(info); lodepng_info_init(info); - if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 - || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { - CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || + in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { + CERROR_RETURN_ERROR( + state->error, + 28); /*error: the first 8 bytes are not the correct PNG signature*/ } - if(lodepng_chunk_length(in + 8) != 13) { - CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/ + if (lodepng_chunk_length(in + 8) != 13) { + CERROR_RETURN_ERROR(state->error, + 94); /*error: header size must be 13 bytes*/ } - if(!lodepng_chunk_type_equals(in + 8, "IHDR")) { - CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + if (!lodepng_chunk_type_equals(in + 8, "IHDR")) { + CERROR_RETURN_ERROR(state->error, + 29); /*error: it doesn't start with a IHDR chunk!*/ } /*read the values given in the header*/ width = lodepng_read32bitInt(&in[16]); height = lodepng_read32bitInt(&in[20]); - /*TODO: remove the undocumented feature that allows to give null pointers to width or height*/ - if(w) *w = width; - if(h) *h = height; + /*TODO: remove the undocumented feature that allows to give null pointers to + * width or height*/ + if (w) + *w = width; + if (h) + *h = height; info->color.bitdepth = in[24]; info->color.colortype = (LodePNGColorType)in[25]; info->compression_method = in[26]; @@ -4076,21 +4791,27 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, /*errors returned only after the parsing so other values are still output*/ /*error: invalid image size*/ - if(width == 0 || height == 0) CERROR_RETURN_ERROR(state->error, 93); + if (width == 0 || height == 0) + CERROR_RETURN_ERROR(state->error, 93); /*error: invalid colortype or bitdepth combination*/ - state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); - if(state->error) return state->error; + state->error = + checkColorValidity(info->color.colortype, info->color.bitdepth); + if (state->error) + return state->error; /*error: only compression method 0 is allowed in the specification*/ - if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + if (info->compression_method != 0) + CERROR_RETURN_ERROR(state->error, 32); /*error: only filter method 0 is allowed in the specification*/ - if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + if (info->filter_method != 0) + CERROR_RETURN_ERROR(state->error, 33); /*error: only interlace methods 0 and 1 exist in the specification*/ - if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + if (info->interlace_method > 1) + CERROR_RETURN_ERROR(state->error, 34); - if(!state->decoder.ignore_crc) { + if (!state->decoder.ignore_crc) { unsigned CRC = lodepng_read32bitInt(&in[29]); unsigned checksum = lodepng_crc32(&in[12], 17); - if(CRC != checksum) { + if (CRC != checksum) { CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ } } @@ -4098,126 +4819,159 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, return state->error; } -static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, - size_t bytewidth, unsigned char filterType, size_t length) { +static unsigned unfilterScanline(unsigned char *recon, + const unsigned char *scanline, + const unsigned char *precon, size_t bytewidth, + unsigned char filterType, size_t length) { /* For PNG filter method 0 - unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, - the filter works byte per byte (bytewidth = 1) - precon is the previous unfiltered scanline, recon the result, scanline the current one - the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead - recon and scanline MAY be the same memory address! precon must be disjoint. + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 + byte, the filter works byte per byte (bytewidth = 1) precon is the previous + unfiltered scanline, recon the result, scanline the current one the incoming + scanlines do NOT include the filtertype byte, that one is given in the + parameter filterType instead recon and scanline MAY be the same memory + address! precon must be disjoint. */ size_t i; - switch(filterType) { - case 0: - for(i = 0; i != length; ++i) recon[i] = scanline[i]; - break; - case 1: - for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; - for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; - break; - case 2: - if(precon) { - for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; - } else { - for(i = 0; i != length; ++i) recon[i] = scanline[i]; + switch (filterType) { + case 0: + for (i = 0; i != length; ++i) + recon[i] = scanline[i]; + break; + case 1: + for (i = 0; i != bytewidth; ++i) + recon[i] = scanline[i]; + for (i = bytewidth; i < length; ++i) + recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if (precon) { + for (i = 0; i != length; ++i) + recon[i] = scanline[i] + precon[i]; + } else { + for (i = 0; i != length; ++i) + recon[i] = scanline[i]; + } + break; + case 3: + if (precon) { + for (i = 0; i != bytewidth; ++i) + recon[i] = scanline[i] + (precon[i] >> 1u); + for (i = bytewidth; i < length; ++i) + recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1u); + } else { + for (i = 0; i != bytewidth; ++i) + recon[i] = scanline[i]; + for (i = bytewidth; i < length; ++i) + recon[i] = scanline[i] + (recon[i - bytewidth] >> 1u); + } + break; + case 4: + if (precon) { + for (i = 0; i != bytewidth; ++i) { + recon[i] = + (scanline[i] + + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ } - break; - case 3: - if(precon) { - for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1u); - for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1u); - } else { - for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; - for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1u); - } - break; - case 4: - if(precon) { - for(i = 0; i != bytewidth; ++i) { - recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ - } - /* Unroll independent paths of the paeth predictor. A 6x and 8x version would also be possible but that - adds too much code. Whether this actually speeds anything up at all depends on compiler and settings. */ - if(bytewidth >= 4) { - for(; i + 3 < length; i += 4) { - size_t j = i - bytewidth; - unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3]; - unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3]; - unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3]; - unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2], q3 = precon[j + 3]; - recon[i + 0] = s0 + paethPredictor(r0, p0, q0); - recon[i + 1] = s1 + paethPredictor(r1, p1, q1); - recon[i + 2] = s2 + paethPredictor(r2, p2, q2); - recon[i + 3] = s3 + paethPredictor(r3, p3, q3); - } - } else if(bytewidth >= 3) { - for(; i + 2 < length; i += 3) { - size_t j = i - bytewidth; - unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2]; - unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2]; - unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2]; - unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2]; - recon[i + 0] = s0 + paethPredictor(r0, p0, q0); - recon[i + 1] = s1 + paethPredictor(r1, p1, q1); - recon[i + 2] = s2 + paethPredictor(r2, p2, q2); - } - } else if(bytewidth >= 2) { - for(; i + 1 < length; i += 2) { - size_t j = i - bytewidth; - unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1]; - unsigned char r0 = recon[j + 0], r1 = recon[j + 1]; - unsigned char p0 = precon[i + 0], p1 = precon[i + 1]; - unsigned char q0 = precon[j + 0], q1 = precon[j + 1]; - recon[i + 0] = s0 + paethPredictor(r0, p0, q0); - recon[i + 1] = s1 + paethPredictor(r1, p1, q1); - } + /* Unroll independent paths of the paeth predictor. A 6x and 8x version + would also be possible but that adds too much code. Whether this actually + speeds anything up at all depends on compiler and settings. */ + if (bytewidth >= 4) { + for (; i + 3 < length; i += 4) { + size_t j = i - bytewidth; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], + s2 = scanline[i + 2], s3 = scanline[i + 3]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], + r3 = recon[j + 3]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], + p2 = precon[i + 2], p3 = precon[i + 3]; + unsigned char q0 = precon[j + 0], q1 = precon[j + 1], + q2 = precon[j + 2], q3 = precon[j + 3]; + recon[i + 0] = s0 + paethPredictor(r0, p0, q0); + recon[i + 1] = s1 + paethPredictor(r1, p1, q1); + recon[i + 2] = s2 + paethPredictor(r2, p2, q2); + recon[i + 3] = s3 + paethPredictor(r3, p3, q3); } - - for(; i != length; ++i) { - recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } else if (bytewidth >= 3) { + for (; i + 2 < length; i += 3) { + size_t j = i - bytewidth; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], + s2 = scanline[i + 2]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], + p2 = precon[i + 2]; + unsigned char q0 = precon[j + 0], q1 = precon[j + 1], + q2 = precon[j + 2]; + recon[i + 0] = s0 + paethPredictor(r0, p0, q0); + recon[i + 1] = s1 + paethPredictor(r1, p1, q1); + recon[i + 2] = s2 + paethPredictor(r2, p2, q2); } - } else { - for(i = 0; i != bytewidth; ++i) { - recon[i] = scanline[i]; - } - for(i = bytewidth; i < length; ++i) { - /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ - recon[i] = (scanline[i] + recon[i - bytewidth]); + } else if (bytewidth >= 2) { + for (; i + 1 < length; i += 2) { + size_t j = i - bytewidth; + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1]; + unsigned char q0 = precon[j + 0], q1 = precon[j + 1]; + recon[i + 0] = s0 + paethPredictor(r0, p0, q0); + recon[i + 1] = s1 + paethPredictor(r1, p1, q1); } } - break; - default: return 36; /*error: invalid filter type given*/ + + for (; i != length; ++i) { + recon[i] = + (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], + precon[i - bytewidth])); + } + } else { + for (i = 0; i != bytewidth; ++i) { + recon[i] = scanline[i]; + } + for (i = bytewidth; i < length; ++i) { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - + * bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: + return 36; /*error: invalid filter type given*/ } return 0; } -static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { +static unsigned unfilter(unsigned char *out, const unsigned char *in, + unsigned w, unsigned h, unsigned bpp) { /* For PNG filter method 0 - this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) - out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline - w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel - in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + this function unfilters a single image (e.g. without interlacing this is + called once, with Adam7 seven times) out must have enough bytes allocated + already, in must have the scanlines + 1 filtertype byte per scanline w and h + are image dimensions or dimensions of reduced image, bpp is bits per pixel in + and out are allowed to be the same memory address (but aren't the same size + since in has the extra filter bytes) */ unsigned y; - unsigned char* prevline = 0; + unsigned char *prevline = 0; - /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per + * pixel otherwise*/ size_t bytewidth = (bpp + 7u) / 8u; /*the width of a scanline in bytes, not including the filter type*/ size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u; - for(y = 0; y < h; ++y) { + for (y = 0; y < h; ++y) { size_t outindex = linebytes * y; - size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = + (1 + linebytes) * y; /*the extra filterbyte added to each row*/ unsigned char filterType = in[inindex]; - CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], + prevline, bytewidth, filterType, + linebytes)); prevline = &out[outindex]; } @@ -4228,71 +4982,79 @@ static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w /* in: Adam7 interlaced image, with no padding bits between scanlines, but between reduced images so that each reduced image starts at a byte. -out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h -bpp: bits per pixel -out has the following size in bits: w * h * bpp. -in is possibly bigger due to padding bits between reduced images. -out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +out: the same pixels, but re-ordered so that they're now a non-interlaced image +with size w*h bpp: bits per pixel out has the following size in bits: w * h * +bpp. in is possibly bigger due to padding bits between reduced images. out must +be big enough AND must be 0 everywhere if bpp < 8 in the current implementation (because that's likely a little bit faster) NOTE: comments about padding bits are only relevant if bpp < 8 */ -static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { +static void Adam7_deinterlace(unsigned char *out, const unsigned char *in, + unsigned w, unsigned h, unsigned bpp) { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, + passstart, w, h, bpp); - if(bpp >= 8) { - for(i = 0; i != 7; ++i) { + if (bpp >= 8) { + for (i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8u; - for(y = 0; y < passh[i]; ++y) - for(x = 0; x < passw[i]; ++x) { - size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; - size_t pixeloutstart = ((ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * (size_t)w - + ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bytewidth; - for(b = 0; b < bytewidth; ++b) { - out[pixeloutstart + b] = in[pixelinstart + b]; + for (y = 0; y < passh[i]; ++y) + for (x = 0; x < passw[i]; ++x) { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = + ((ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * (size_t)w + + ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * + bytewidth; + for (b = 0; b < bytewidth; ++b) { + out[pixeloutstart + b] = in[pixelinstart + b]; + } } - } } - } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { - for(i = 0; i != 7; ++i) { + } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit + pointers*/ + { + for (i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ - for(y = 0; y < passh[i]; ++y) - for(x = 0; x < passw[i]; ++x) { - ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); - obp = (ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bpp; - for(b = 0; b < bpp; ++b) { - unsigned char bit = readBitFromReversedStream(&ibp, in); - setBitOfReversedStream(&obp, out, bit); + for (y = 0; y < passh[i]; ++y) + for (x = 0; x < passw[i]; ++x) { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * olinebits + + (ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bpp; + for (b = 0; b < bpp; ++b) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } } - } } } } -static void removePaddingBits(unsigned char* out, const unsigned char* in, +static void removePaddingBits(unsigned char *out, const unsigned char *in, size_t olinebits, size_t ilinebits, unsigned h) { /* - After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need - to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers - for the Adam7 code, the color convert code and the output to the user. - in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must - have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits - also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 - only useful if (ilinebits - olinebits) is a value in the range 1..7 + After filtering there are still padding bits if scanlines have non multiple of + 8 bit amounts. They need to be removed (except at last scanline of + (Adam7-reduced) image) before working with pure image buffers for the Adam7 + code, the color convert code and the output to the user. in and out are + allowed to be the same buffer, in may also be higher but still overlapping; in + must have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits + must be <= ilinebits also used to move bits after earlier such operations + happened, e.g. in a sequence of reduced images from Adam7 only useful if + (ilinebits - olinebits) is a value in the range 1..7 */ unsigned y; size_t diff = ilinebits - olinebits; size_t ibp = 0, obp = 0; /*input and output bit pointers*/ - for(y = 0; y < h; ++y) { + for (y = 0; y < h; ++y) { size_t x; - for(x = 0; x < olinebits; ++x) { + for (x = 0; x < olinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } @@ -4300,43 +5062,53 @@ static void removePaddingBits(unsigned char* out, const unsigned char* in, } } -/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from -the IDAT chunks (with filter index bytes and possible padding bits) -return value is error*/ -static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, - unsigned w, unsigned h, const LodePNGInfo* info_png) { +/*out must be buffer big enough to contain full image, and in must contain the +full decompressed data from the IDAT chunks (with filter index bytes and +possible padding bits) return value is error*/ +static unsigned postProcessScanlines(unsigned char *out, unsigned char *in, + unsigned w, unsigned h, + const LodePNGInfo *info_png) { /* - This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. - Steps: - *) if no Adam7: 1) unfilter 2) remove padding bits (= possible extra bits per scanline if bpp < 8) + This function converts the filtered-padded-interlaced data into pure 2D image + buffer with the PNG's colortype. Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= possible extra bits per + scanline if bpp < 8) *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace NOTE: the in buffer will be overwritten with intermediate data! */ unsigned bpp = lodepng_get_bpp(&info_png->color); - if(bpp == 0) return 31; /*error: invalid colortype*/ + if (bpp == 0) + return 31; /*error: invalid colortype*/ - if(info_png->interlace_method == 0) { - if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { + if (info_png->interlace_method == 0) { + if (bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); removePaddingBits(out, in, w * bpp, ((w * bpp + 7u) / 8u) * 8u, h); } /*we can immediately filter into the out buffer, no other steps needed*/ - else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + else + CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); } else /*interlace_method is 1 (Adam7)*/ { - unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, + passstart, w, h, bpp); - for(i = 0; i != 7; ++i) { - CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); - /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, - move bytes instead of bits or move not at all*/ - if(bpp < 8) { - /*remove padding bits in scanlines; after this there still may be padding - bits between the different reduced images: each reduced image still starts nicely at a byte*/ - removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, - ((passw[i] * bpp + 7u) / 8u) * 8u, passh[i]); + for (i = 0; i != 7; ++i) { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], + &in[filter_passstart[i]], passw[i], passh[i], + bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits + fit nicely in 1 scanline, move bytes instead of bits or move not at all*/ + if (bpp < 8) { + /*remove padding bits in scanlines; after this there still may be + padding bits between the different reduced images: each reduced image + still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], + passw[i] * bpp, ((passw[i] * bpp + 7u) / 8u) * 8u, + passh[i]); } } @@ -4346,76 +5118,90 @@ static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, return 0; } -static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { +static unsigned readChunk_PLTE(LodePNGColorMode *color, + const unsigned char *data, size_t chunkLength) { unsigned pos = 0, i; color->palettesize = chunkLength / 3u; - if(color->palettesize == 0 || color->palettesize > 256) return 38; /*error: palette too small or big*/ + if (color->palettesize == 0 || color->palettesize > 256) + return 38; /*error: palette too small or big*/ lodepng_color_mode_alloc_palette(color); - if(!color->palette && color->palettesize) { + if (!color->palette && color->palettesize) { color->palettesize = 0; return 83; /*alloc fail*/ } - for(i = 0; i != color->palettesize; ++i) { + for (i = 0; i != color->palettesize; ++i) { color->palette[4 * i + 0] = data[pos++]; /*R*/ color->palette[4 * i + 1] = data[pos++]; /*G*/ color->palette[4 * i + 2] = data[pos++]; /*B*/ - color->palette[4 * i + 3] = 255; /*alpha*/ + color->palette[4 * i + 3] = 255; /*alpha*/ } return 0; /* OK */ } -static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { +static unsigned readChunk_tRNS(LodePNGColorMode *color, + const unsigned char *data, size_t chunkLength) { unsigned i; - if(color->colortype == LCT_PALETTE) { + if (color->colortype == LCT_PALETTE) { /*error: more alpha values given than there are palette entries*/ - if(chunkLength > color->palettesize) return 39; + if (chunkLength > color->palettesize) + return 39; - for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; - } else if(color->colortype == LCT_GREY) { + for (i = 0; i != chunkLength; ++i) + color->palette[4 * i + 3] = data[i]; + } else if (color->colortype == LCT_GREY) { /*error: this chunk must be 2 bytes for grayscale image*/ - if(chunkLength != 2) return 30; + if (chunkLength != 2) + return 30; color->key_defined = 1; color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; - } else if(color->colortype == LCT_RGB) { + } else if (color->colortype == LCT_RGB) { /*error: this chunk must be 6 bytes for RGB image*/ - if(chunkLength != 6) return 41; + if (chunkLength != 6) + return 41; color->key_defined = 1; color->key_r = 256u * data[0] + data[1]; color->key_g = 256u * data[2] + data[3]; color->key_b = 256u * data[4] + data[5]; - } - else return 42; /*error: tRNS chunk not allowed for other color models*/ + } else + return 42; /*error: tRNS chunk not allowed for other color models*/ return 0; /* OK */ } - #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*background color chunk (bKGD)*/ -static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { - if(info->color.colortype == LCT_PALETTE) { +static unsigned readChunk_bKGD(LodePNGInfo *info, const unsigned char *data, + size_t chunkLength) { + if (info->color.colortype == LCT_PALETTE) { /*error: this chunk must be 1 byte for indexed color image*/ - if(chunkLength != 1) return 43; + if (chunkLength != 1) + return 43; /*error: invalid palette index, or maybe this chunk appeared before PLTE*/ - if(data[0] >= info->color.palettesize) return 103; + if (data[0] >= info->color.palettesize) + return 103; info->background_defined = 1; info->background_r = info->background_g = info->background_b = data[0]; - } else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { + } else if (info->color.colortype == LCT_GREY || + info->color.colortype == LCT_GREY_ALPHA) { /*error: this chunk must be 2 bytes for grayscale image*/ - if(chunkLength != 2) return 44; + if (chunkLength != 2) + return 44; /*the values are truncated to bitdepth in the PNG file*/ info->background_defined = 1; - info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; - } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { + info->background_r = info->background_g = info->background_b = + 256u * data[0] + data[1]; + } else if (info->color.colortype == LCT_RGB || + info->color.colortype == LCT_RGBA) { /*error: this chunk must be 6 bytes for grayscale image*/ - if(chunkLength != 6) return 45; + if (chunkLength != 6) + return 45; /*the values are truncated to bitdepth in the PNG file*/ info->background_defined = 1; @@ -4428,30 +5214,37 @@ static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, siz } /*text chunk (tEXt)*/ -static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { +static unsigned readChunk_tEXt(LodePNGInfo *info, const unsigned char *data, + size_t chunkLength) { unsigned error = 0; char *key = 0, *str = 0; - while(!error) /*not really a while loop, only used to break on error*/ { + while (!error) /*not really a while loop, only used to break on error*/ { unsigned length, string2_begin; length = 0; - while(length < chunkLength && data[length] != 0) ++length; + while (length < chunkLength && data[length] != 0) + ++length; /*even though it's not allowed by the standard, no error is thrown if there's no null termination char, if the text is empty*/ - if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + if (length < 1 || length > 79) + CERROR_BREAK(error, 89); /*keyword too short or long*/ - key = (char*)lodepng_malloc(length + 1); - if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + key = (char *)lodepng_malloc(length + 1); + if (!key) + CERROR_BREAK(error, 83); /*alloc fail*/ lodepng_memcpy(key, data, length); key[length] = 0; string2_begin = length + 1; /*skip keyword null terminator*/ - length = (unsigned)(chunkLength < string2_begin ? 0 : chunkLength - string2_begin); - str = (char*)lodepng_malloc(length + 1); - if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + length = + (unsigned)(chunkLength < string2_begin ? 0 + : chunkLength - string2_begin); + str = (char *)lodepng_malloc(length + 1); + if (!str) + CERROR_BREAK(error, 83); /*alloc fail*/ lodepng_memcpy(str, data + string2_begin, length); str[length] = 0; @@ -4468,8 +5261,9 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz } /*compressed text chunk (zTXt)*/ -static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, - const unsigned char* data, size_t chunkLength) { +static unsigned readChunk_zTXt(LodePNGInfo *info, + const LodePNGDecoderSettings *decoder, + const unsigned char *data, size_t chunkLength) { unsigned error = 0; /*copy the object to change parameters in it*/ @@ -4477,34 +5271,42 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings* unsigned length, string2_begin; char *key = 0; - unsigned char* str = 0; + unsigned char *str = 0; size_t size = 0; - while(!error) /*not really a while loop, only used to break on error*/ { - for(length = 0; length < chunkLength && data[length] != 0; ++length) ; - if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ - if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + while (!error) /*not really a while loop, only used to break on error*/ { + for (length = 0; length < chunkLength && data[length] != 0; ++length) + ; + if (length + 2 >= chunkLength) + CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if (length < 1 || length > 79) + CERROR_BREAK(error, 89); /*keyword too short or long*/ - key = (char*)lodepng_malloc(length + 1); - if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + key = (char *)lodepng_malloc(length + 1); + if (!key) + CERROR_BREAK(error, 83); /*alloc fail*/ lodepng_memcpy(key, data, length); key[length] = 0; - if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + if (data[length + 1] != 0) + CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ string2_begin = length + 2; - if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if (string2_begin > chunkLength) + CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ length = (unsigned)chunkLength - string2_begin; zlibsettings.max_output_size = decoder->max_text_size; /*will fail if zlib error, e.g. if length is too small*/ - error = zlib_decompress(&str, &size, 0, &data[string2_begin], - length, &zlibsettings); + error = zlib_decompress(&str, &size, 0, &data[string2_begin], length, + &zlibsettings); /*error: compressed text larger than decoder->max_text_size*/ - if(error && size > zlibsettings.max_output_size) error = 112; - if(error) break; - error = lodepng_add_text_sized(info, key, (char*)str, size); + if (error && size > zlibsettings.max_output_size) + error = 112; + if (error) + break; + error = lodepng_add_text_sized(info, key, (char *)str, size); break; } @@ -4515,8 +5317,9 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings* } /*international text chunk (iTXt)*/ -static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, - const unsigned char* data, size_t chunkLength) { +static unsigned readChunk_iTXt(LodePNGInfo *info, + const LodePNGDecoderSettings *decoder, + const unsigned char *data, size_t chunkLength) { unsigned error = 0; unsigned i; @@ -4526,36 +5329,46 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* unsigned length, begin, compressed; char *key = 0, *langtag = 0, *transkey = 0; - while(!error) /*not really a while loop, only used to break on error*/ { + while (!error) /*not really a while loop, only used to break on error*/ { /*Quick check if the chunk length isn't too small. Even without check - it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ - if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + it'd still fail with other error checks below if it's too short. This just + gives a different error code.*/ + if (chunkLength < 5) + CERROR_BREAK(error, 30); /*iTXt chunk too short*/ /*read the key*/ - for(length = 0; length < chunkLength && data[length] != 0; ++length) ; - if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ - if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + for (length = 0; length < chunkLength && data[length] != 0; ++length) + ; + if (length + 3 >= chunkLength) + CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if (length < 1 || length > 79) + CERROR_BREAK(error, 89); /*keyword too short or long*/ - key = (char*)lodepng_malloc(length + 1); - if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + key = (char *)lodepng_malloc(length + 1); + if (!key) + CERROR_BREAK(error, 83); /*alloc fail*/ lodepng_memcpy(key, data, length); key[length] = 0; /*read the compression method*/ compressed = data[length + 1]; - if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + if (data[length + 2] != 0) + CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ /*even though it's not allowed by the standard, no error is thrown if - there's no null termination char, if the text is empty for the next 3 texts*/ + there's no null termination char, if the text is empty for the next 3 + texts*/ /*read the langtag*/ begin = length + 3; length = 0; - for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + for (i = begin; i < chunkLength && data[i] != 0; ++i) + ++length; - langtag = (char*)lodepng_malloc(length + 1); - if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + langtag = (char *)lodepng_malloc(length + 1); + if (!langtag) + CERROR_BREAK(error, 83); /*alloc fail*/ lodepng_memcpy(langtag, data + begin, length); langtag[length] = 0; @@ -4563,10 +5376,12 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* /*read the transkey*/ begin += length + 1; length = 0; - for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + for (i = begin; i < chunkLength && data[i] != 0; ++i) + ++length; - transkey = (char*)lodepng_malloc(length + 1); - if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + transkey = (char *)lodepng_malloc(length + 1); + if (!transkey) + CERROR_BREAK(error, 83); /*alloc fail*/ lodepng_memcpy(transkey, data + begin, length); transkey[length] = 0; @@ -4576,19 +5391,23 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* length = (unsigned)chunkLength < begin ? 0 : (unsigned)chunkLength - begin; - if(compressed) { - unsigned char* str = 0; + if (compressed) { + unsigned char *str = 0; size_t size = 0; zlibsettings.max_output_size = decoder->max_text_size; /*will fail if zlib error, e.g. if length is too small*/ - error = zlib_decompress(&str, &size, 0, &data[begin], - length, &zlibsettings); + error = + zlib_decompress(&str, &size, 0, &data[begin], length, &zlibsettings); /*error: compressed text larger than decoder->max_text_size*/ - if(error && size > zlibsettings.max_output_size) error = 112; - if(!error) error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)str, size); + if (error && size > zlibsettings.max_output_size) + error = 112; + if (!error) + error = lodepng_add_itext_sized(info, key, langtag, transkey, + (char *)str, size); lodepng_free(str); } else { - error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)(data + begin), length); + error = lodepng_add_itext_sized(info, key, langtag, transkey, + (char *)(data + begin), length); } break; @@ -4601,8 +5420,10 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* return error; } -static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { - if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ +static unsigned readChunk_tIME(LodePNGInfo *info, const unsigned char *data, + size_t chunkLength) { + if (chunkLength != 7) + return 73; /*invalid tIME chunk size*/ info->time_defined = 1; info->time.year = 256u * data[0] + data[1]; @@ -4615,44 +5436,63 @@ static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, siz return 0; /* OK */ } -static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { - if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ +static unsigned readChunk_pHYs(LodePNGInfo *info, const unsigned char *data, + size_t chunkLength) { + if (chunkLength != 9) + return 74; /*invalid pHYs chunk size*/ info->phys_defined = 1; - info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; - info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_x = + 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = + 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; info->phys_unit = data[8]; return 0; /* OK */ } -static unsigned readChunk_gAMA(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { - if(chunkLength != 4) return 96; /*invalid gAMA chunk size*/ +static unsigned readChunk_gAMA(LodePNGInfo *info, const unsigned char *data, + size_t chunkLength) { + if (chunkLength != 4) + return 96; /*invalid gAMA chunk size*/ info->gama_defined = 1; - info->gama_gamma = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->gama_gamma = + 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; return 0; /* OK */ } -static unsigned readChunk_cHRM(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { - if(chunkLength != 32) return 97; /*invalid cHRM chunk size*/ +static unsigned readChunk_cHRM(LodePNGInfo *info, const unsigned char *data, + size_t chunkLength) { + if (chunkLength != 32) + return 97; /*invalid cHRM chunk size*/ info->chrm_defined = 1; - info->chrm_white_x = 16777216u * data[ 0] + 65536u * data[ 1] + 256u * data[ 2] + data[ 3]; - info->chrm_white_y = 16777216u * data[ 4] + 65536u * data[ 5] + 256u * data[ 6] + data[ 7]; - info->chrm_red_x = 16777216u * data[ 8] + 65536u * data[ 9] + 256u * data[10] + data[11]; - info->chrm_red_y = 16777216u * data[12] + 65536u * data[13] + 256u * data[14] + data[15]; - info->chrm_green_x = 16777216u * data[16] + 65536u * data[17] + 256u * data[18] + data[19]; - info->chrm_green_y = 16777216u * data[20] + 65536u * data[21] + 256u * data[22] + data[23]; - info->chrm_blue_x = 16777216u * data[24] + 65536u * data[25] + 256u * data[26] + data[27]; - info->chrm_blue_y = 16777216u * data[28] + 65536u * data[29] + 256u * data[30] + data[31]; + info->chrm_white_x = + 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->chrm_white_y = + 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->chrm_red_x = + 16777216u * data[8] + 65536u * data[9] + 256u * data[10] + data[11]; + info->chrm_red_y = + 16777216u * data[12] + 65536u * data[13] + 256u * data[14] + data[15]; + info->chrm_green_x = + 16777216u * data[16] + 65536u * data[17] + 256u * data[18] + data[19]; + info->chrm_green_y = + 16777216u * data[20] + 65536u * data[21] + 256u * data[22] + data[23]; + info->chrm_blue_x = + 16777216u * data[24] + 65536u * data[25] + 256u * data[26] + data[27]; + info->chrm_blue_y = + 16777216u * data[28] + 65536u * data[29] + 256u * data[30] + data[31]; return 0; /* OK */ } -static unsigned readChunk_sRGB(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { - if(chunkLength != 1) return 98; /*invalid sRGB chunk size (this one is never ignored)*/ +static unsigned readChunk_sRGB(LodePNGInfo *info, const unsigned char *data, + size_t chunkLength) { + if (chunkLength != 1) + return 98; /*invalid sRGB chunk size (this one is never ignored)*/ info->srgb_defined = 1; info->srgb_intent = data[0]; @@ -4660,8 +5500,9 @@ static unsigned readChunk_sRGB(LodePNGInfo* info, const unsigned char* data, siz return 0; /* OK */ } -static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, - const unsigned char* data, size_t chunkLength) { +static unsigned readChunk_iCCP(LodePNGInfo *info, + const LodePNGDecoderSettings *decoder, + const unsigned char *data, size_t chunkLength) { unsigned error = 0; unsigned i; size_t size = 0; @@ -4671,97 +5512,114 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings* unsigned length, string2_begin; info->iccp_defined = 1; - if(info->iccp_name) lodepng_clear_icc(info); + if (info->iccp_name) + lodepng_clear_icc(info); - for(length = 0; length < chunkLength && data[length] != 0; ++length) ; - if(length + 2 >= chunkLength) return 75; /*no null termination, corrupt?*/ - if(length < 1 || length > 79) return 89; /*keyword too short or long*/ + for (length = 0; length < chunkLength && data[length] != 0; ++length) + ; + if (length + 2 >= chunkLength) + return 75; /*no null termination, corrupt?*/ + if (length < 1 || length > 79) + return 89; /*keyword too short or long*/ - info->iccp_name = (char*)lodepng_malloc(length + 1); - if(!info->iccp_name) return 83; /*alloc fail*/ + info->iccp_name = (char *)lodepng_malloc(length + 1); + if (!info->iccp_name) + return 83; /*alloc fail*/ info->iccp_name[length] = 0; - for(i = 0; i != length; ++i) info->iccp_name[i] = (char)data[i]; + for (i = 0; i != length; ++i) + info->iccp_name[i] = (char)data[i]; - if(data[length + 1] != 0) return 72; /*the 0 byte indicating compression must be 0*/ + if (data[length + 1] != 0) + return 72; /*the 0 byte indicating compression must be 0*/ string2_begin = length + 2; - if(string2_begin > chunkLength) return 75; /*no null termination, corrupt?*/ + if (string2_begin > chunkLength) + return 75; /*no null termination, corrupt?*/ length = (unsigned)chunkLength - string2_begin; zlibsettings.max_output_size = decoder->max_icc_size; - error = zlib_decompress(&info->iccp_profile, &size, 0, - &data[string2_begin], + error = zlib_decompress(&info->iccp_profile, &size, 0, &data[string2_begin], length, &zlibsettings); /*error: ICC profile larger than decoder->max_icc_size*/ - if(error && size > zlibsettings.max_output_size) error = 113; + if (error && size > zlibsettings.max_output_size) + error = 113; info->iccp_profile_size = size; - if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/ + if (!error && !info->iccp_profile_size) + error = 100; /*invalid ICC profile size*/ return error; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, - const unsigned char* in, size_t insize) { - const unsigned char* chunk = in + pos; +unsigned lodepng_inspect_chunk(LodePNGState *state, size_t pos, + const unsigned char *in, size_t insize) { + const unsigned char *chunk = in + pos; unsigned chunkLength; - const unsigned char* data; + const unsigned char *data; unsigned unhandled = 0; unsigned error = 0; - if(pos + 4 > insize) return 30; + if (pos + 4 > insize) + return 30; chunkLength = lodepng_chunk_length(chunk); - if(chunkLength > 2147483647) return 63; + if (chunkLength > 2147483647) + return 63; data = lodepng_chunk_data_const(chunk); - if(data + chunkLength + 4 > in + insize) return 30; + if (data + chunkLength + 4 > in + insize) + return 30; - if(lodepng_chunk_type_equals(chunk, "PLTE")) { + if (lodepng_chunk_type_equals(chunk, "PLTE")) { error = readChunk_PLTE(&state->info_png.color, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "tRNS")) { + } else if (lodepng_chunk_type_equals(chunk, "tRNS")) { error = readChunk_tRNS(&state->info_png.color, data, chunkLength); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - } else if(lodepng_chunk_type_equals(chunk, "bKGD")) { + } else if (lodepng_chunk_type_equals(chunk, "bKGD")) { error = readChunk_bKGD(&state->info_png, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "tEXt")) { + } else if (lodepng_chunk_type_equals(chunk, "tEXt")) { error = readChunk_tEXt(&state->info_png, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { - error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { - error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "tIME")) { + } else if (lodepng_chunk_type_equals(chunk, "zTXt")) { + error = + readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); + } else if (lodepng_chunk_type_equals(chunk, "iTXt")) { + error = + readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); + } else if (lodepng_chunk_type_equals(chunk, "tIME")) { error = readChunk_tIME(&state->info_png, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { + } else if (lodepng_chunk_type_equals(chunk, "pHYs")) { error = readChunk_pHYs(&state->info_png, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "gAMA")) { + } else if (lodepng_chunk_type_equals(chunk, "gAMA")) { error = readChunk_gAMA(&state->info_png, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "cHRM")) { + } else if (lodepng_chunk_type_equals(chunk, "cHRM")) { error = readChunk_cHRM(&state->info_png, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "sRGB")) { + } else if (lodepng_chunk_type_equals(chunk, "sRGB")) { error = readChunk_sRGB(&state->info_png, data, chunkLength); - } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { - error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); + } else if (lodepng_chunk_type_equals(chunk, "iCCP")) { + error = + readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } else { /* unhandled chunk is ok (is not an error) */ unhandled = 1; } - if(!error && !unhandled && !state->decoder.ignore_crc) { - if(lodepng_chunk_check_crc(chunk)) return 57; /*invalid CRC*/ + if (!error && !unhandled && !state->decoder.ignore_crc) { + if (lodepng_chunk_check_crc(chunk)) + return 57; /*invalid CRC*/ } return error; } -/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ -static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize) { +/*read a PNG, the result will be in the same color type as the PNG (hence + * "generic")*/ +static void decodeGeneric(unsigned char **out, unsigned *w, unsigned *h, + LodePNGState *state, const unsigned char *in, + size_t insize) { unsigned char IEND = 0; - const unsigned char* chunk; - unsigned char* idat; /*the data from idat chunks, zlib compressed*/ + const unsigned char *chunk; + unsigned char *idat; /*the data from idat chunks, zlib compressed*/ size_t idatsize = 0; - unsigned char* scanlines = 0; + unsigned char *scanlines = 0; size_t scanlines_size = 0, expected_size = 0; size_t outsize = 0; @@ -4769,48 +5627,59 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, unsigned unknown = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /* safe output values in case error happens */ *out = 0; *w = *h = 0; - state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ - if(state->error) return; + state->error = lodepng_inspect( + w, h, state, in, + insize); /*reads header and resets other parameters in state->info_png*/ + if (state->error) + return; - if(lodepng_pixel_overflow(*w, *h, &state->info_png.color, &state->info_raw)) { - CERROR_RETURN(state->error, 92); /*overflow possible due to amount of pixels*/ + if (lodepng_pixel_overflow(*w, *h, &state->info_png.color, + &state->info_raw)) { + CERROR_RETURN(state->error, + 92); /*overflow possible due to amount of pixels*/ } /*the input filesize is a safe upper bound for the sum of idat chunks size*/ - idat = (unsigned char*)lodepng_malloc(insize); - if(!idat) CERROR_RETURN(state->error, 83); /*alloc fail*/ + idat = (unsigned char *)lodepng_malloc(insize); + if (!idat) + CERROR_RETURN(state->error, 83); /*alloc fail*/ chunk = &in[33]; /*first byte of the first chunk after the header*/ /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer*/ - while(!IEND && !state->error) { + while (!IEND && !state->error) { unsigned chunkLength; - const unsigned char* data; /*the data in the chunk*/ + const unsigned char *data; /*the data in the chunk*/ /*error: size of the in buffer too small to contain next chunk*/ - if((size_t)((chunk - in) + 12) > insize || chunk < in) { - if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + if ((size_t)((chunk - in) + 12) > insize || chunk < in) { + if (state->decoder.ignore_end) + break; /*other errors may still happen though*/ CERROR_BREAK(state->error, 30); } - /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + /*length of the data of the chunk, excluding the length bytes, chunk type + * and CRC bytes*/ chunkLength = lodepng_chunk_length(chunk); /*error: chunk length larger than the max PNG chunk size*/ - if(chunkLength > 2147483647) { - if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + if (chunkLength > 2147483647) { + if (state->decoder.ignore_end) + break; /*other errors may still happen though*/ CERROR_BREAK(state->error, 63); } - if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) { - CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + if ((size_t)((chunk - in) + chunkLength + 12) > insize || + (chunk + chunkLength + 12) < in) { + CERROR_BREAK( + state->error, + 64); /*error: size of the in buffer too small to contain next chunk*/ } data = lodepng_chunk_data_const(chunk); @@ -4818,175 +5687,225 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, unknown = 0; /*IDAT chunk, containing compressed image data*/ - if(lodepng_chunk_type_equals(chunk, "IDAT")) { + if (lodepng_chunk_type_equals(chunk, "IDAT")) { size_t newsize; - if(lodepng_addofl(idatsize, chunkLength, &newsize)) CERROR_BREAK(state->error, 95); - if(newsize > insize) CERROR_BREAK(state->error, 95); + if (lodepng_addofl(idatsize, chunkLength, &newsize)) + CERROR_BREAK(state->error, 95); + if (newsize > insize) + CERROR_BREAK(state->error, 95); lodepng_memcpy(idat + idatsize, data, chunkLength); idatsize += chunkLength; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 3; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - } else if(lodepng_chunk_type_equals(chunk, "IEND")) { + } else if (lodepng_chunk_type_equals(chunk, "IEND")) { /*IEND chunk*/ IEND = 1; - } else if(lodepng_chunk_type_equals(chunk, "PLTE")) { + } else if (lodepng_chunk_type_equals(chunk, "PLTE")) { /*palette chunk (PLTE)*/ state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); - if(state->error) break; + if (state->error) + break; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 2; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - } else if(lodepng_chunk_type_equals(chunk, "tRNS")) { - /*palette transparency chunk (tRNS). Even though this one is an ancillary chunk , it is still compiled - in without 'LODEPNG_COMPILE_ANCILLARY_CHUNKS' because it contains essential color information that - affects the alpha channel of pixels. */ + } else if (lodepng_chunk_type_equals(chunk, "tRNS")) { + /*palette transparency chunk (tRNS). Even though this one is an ancillary + chunk , it is still compiled in without 'LODEPNG_COMPILE_ANCILLARY_CHUNKS' + because it contains essential color information that affects the alpha + channel of pixels. */ state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); - if(state->error) break; + if (state->error) + break; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*background color chunk (bKGD)*/ - } else if(lodepng_chunk_type_equals(chunk, "bKGD")) { + } else if (lodepng_chunk_type_equals(chunk, "bKGD")) { state->error = readChunk_bKGD(&state->info_png, data, chunkLength); - if(state->error) break; - } else if(lodepng_chunk_type_equals(chunk, "tEXt")) { + if (state->error) + break; + } else if (lodepng_chunk_type_equals(chunk, "tEXt")) { /*text chunk (tEXt)*/ - if(state->decoder.read_text_chunks) { + if (state->decoder.read_text_chunks) { state->error = readChunk_tEXt(&state->info_png, data, chunkLength); - if(state->error) break; + if (state->error) + break; } - } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { + } else if (lodepng_chunk_type_equals(chunk, "zTXt")) { /*compressed text chunk (zTXt)*/ - if(state->decoder.read_text_chunks) { - state->error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); - if(state->error) break; + if (state->decoder.read_text_chunks) { + state->error = readChunk_zTXt(&state->info_png, &state->decoder, data, + chunkLength); + if (state->error) + break; } - } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { + } else if (lodepng_chunk_type_equals(chunk, "iTXt")) { /*international text chunk (iTXt)*/ - if(state->decoder.read_text_chunks) { - state->error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); - if(state->error) break; + if (state->decoder.read_text_chunks) { + state->error = readChunk_iTXt(&state->info_png, &state->decoder, data, + chunkLength); + if (state->error) + break; } - } else if(lodepng_chunk_type_equals(chunk, "tIME")) { + } else if (lodepng_chunk_type_equals(chunk, "tIME")) { state->error = readChunk_tIME(&state->info_png, data, chunkLength); - if(state->error) break; - } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { + if (state->error) + break; + } else if (lodepng_chunk_type_equals(chunk, "pHYs")) { state->error = readChunk_pHYs(&state->info_png, data, chunkLength); - if(state->error) break; - } else if(lodepng_chunk_type_equals(chunk, "gAMA")) { + if (state->error) + break; + } else if (lodepng_chunk_type_equals(chunk, "gAMA")) { state->error = readChunk_gAMA(&state->info_png, data, chunkLength); - if(state->error) break; - } else if(lodepng_chunk_type_equals(chunk, "cHRM")) { + if (state->error) + break; + } else if (lodepng_chunk_type_equals(chunk, "cHRM")) { state->error = readChunk_cHRM(&state->info_png, data, chunkLength); - if(state->error) break; - } else if(lodepng_chunk_type_equals(chunk, "sRGB")) { + if (state->error) + break; + } else if (lodepng_chunk_type_equals(chunk, "sRGB")) { state->error = readChunk_sRGB(&state->info_png, data, chunkLength); - if(state->error) break; - } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { - state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); - if(state->error) break; -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - } else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { - /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ - if(!state->decoder.ignore_critical && !lodepng_chunk_ancillary(chunk)) { + if (state->error) + break; + } else if (lodepng_chunk_type_equals(chunk, "iCCP")) { + state->error = + readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); + if (state->error) + break; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else /*it's not an implemented chunk type, so ignore it: skip over the + data*/ + { + /*error: unknown critical chunk (5th bit of first byte of chunk type is + * 0)*/ + if (!state->decoder.ignore_critical && !lodepng_chunk_ancillary(chunk)) { CERROR_BREAK(state->error, 69); } unknown = 1; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - if(state->decoder.remember_unknown_chunks) { - state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], - &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); - if(state->error) break; + if (state->decoder.remember_unknown_chunks) { + state->error = lodepng_chunk_append( + &state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if (state->error) + break; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } - if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ { - if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + if (!state->decoder.ignore_crc && + !unknown) /*check CRC if wanted, only on known chunk types*/ { + if (lodepng_chunk_check_crc(chunk)) + CERROR_BREAK(state->error, 57); /*invalid CRC*/ } - if(!IEND) chunk = lodepng_chunk_next_const(chunk, in + insize); + if (!IEND) + chunk = lodepng_chunk_next_const(chunk, in + insize); } - if(!state->error && state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) { - state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */ + if (!state->error && state->info_png.color.colortype == LCT_PALETTE && + !state->info_png.color.palette) { + state->error = + 106; /* error: PNG file must have PLTE chunk if color type is palette */ } - if(!state->error) { - /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. - If the decompressed size does not match the prediction, the image must be corrupt.*/ - if(state->info_png.interlace_method == 0) { + if (!state->error) { + /*predict output size, to allocate exact size for output buffer to avoid + more dynamic allocation. If the decompressed size does not match the + prediction, the image must be corrupt.*/ + if (state->info_png.interlace_method == 0) { size_t bpp = lodepng_get_bpp(&state->info_png.color); expected_size = lodepng_get_raw_size_idat(*w, *h, bpp); } else { size_t bpp = lodepng_get_bpp(&state->info_png.color); /*Adam-7 interlaced: expected size is the sum of the 7 sub-images sizes*/ expected_size = 0; - expected_size += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp); - if(*w > 4) expected_size += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp); - expected_size += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp); - if(*w > 2) expected_size += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp); - expected_size += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp); - if(*w > 1) expected_size += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp); + expected_size += + lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp); + if (*w > 4) + expected_size += + lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp); + expected_size += + lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp); + if (*w > 2) + expected_size += + lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp); + expected_size += + lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp); + if (*w > 1) + expected_size += + lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp); expected_size += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, bpp); } - state->error = zlib_decompress(&scanlines, &scanlines_size, expected_size, idat, idatsize, &state->decoder.zlibsettings); + state->error = + zlib_decompress(&scanlines, &scanlines_size, expected_size, idat, + idatsize, &state->decoder.zlibsettings); } - if(!state->error && scanlines_size != expected_size) state->error = 91; /*decompressed size doesn't match prediction*/ + if (!state->error && scanlines_size != expected_size) + state->error = 91; /*decompressed size doesn't match prediction*/ lodepng_free(idat); - if(!state->error) { + if (!state->error) { outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); - *out = (unsigned char*)lodepng_malloc(outsize); - if(!*out) state->error = 83; /*alloc fail*/ + *out = (unsigned char *)lodepng_malloc(outsize); + if (!*out) + state->error = 83; /*alloc fail*/ } - if(!state->error) { + if (!state->error) { lodepng_memset(*out, 0, outsize); - state->error = postProcessScanlines(*out, scanlines, *w, *h, &state->info_png); + state->error = + postProcessScanlines(*out, scanlines, *w, *h, &state->info_png); } lodepng_free(scanlines); } -unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize) { +unsigned lodepng_decode(unsigned char **out, unsigned *w, unsigned *h, + LodePNGState *state, const unsigned char *in, + size_t insize) { *out = 0; decodeGeneric(out, w, h, state, in, insize); - if(state->error) return state->error; - if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) { + if (state->error) + return state->error; + if (!state->decoder.color_convert || + lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) { /*same color type, no copying or converting of data needed*/ - /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype - the raw image has to the end user*/ - if(!state->decoder.color_convert) { - state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); - if(state->error) return state->error; + /*store the info_png color settings on the info_raw so that the info_raw + still reflects what colortype the raw image has to the end user*/ + if (!state->decoder.color_convert) { + state->error = + lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if (state->error) + return state->error; } } else { /*color conversion needed*/ - unsigned char* data = *out; + unsigned char *data = *out; size_t outsize; - /*TODO: check if this works according to the statement in the documentation: "The converter can convert - from grayscale input color type, to 8-bit grayscale or grayscale with alpha"*/ - if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) - && !(state->info_raw.bitdepth == 8)) { + /*TODO: check if this works according to the statement in the documentation: + "The converter can convert from grayscale input color type, to 8-bit + grayscale or grayscale with alpha"*/ + if (!(state->info_raw.colortype == LCT_RGB || + state->info_raw.colortype == LCT_RGBA) && + !(state->info_raw.bitdepth == 8)) { return 56; /*unsupported color mode conversion*/ } outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); - *out = (unsigned char*)lodepng_malloc(outsize); - if(!(*out)) { + *out = (unsigned char *)lodepng_malloc(outsize); + if (!(*out)) { state->error = 83; /*alloc fail*/ - } - else state->error = lodepng_convert(*out, data, &state->info_raw, - &state->info_png.color, *w, *h); + } else + state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); lodepng_free(data); } return state->error; } -unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, - size_t insize, LodePNGColorType colortype, unsigned bitdepth) { +unsigned lodepng_decode_memory(unsigned char **out, unsigned *w, unsigned *h, + const unsigned char *in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth) { unsigned error; LodePNGState state; lodepng_state_init(&state); @@ -5002,46 +5921,54 @@ unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, co return error; } -unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { +unsigned lodepng_decode32(unsigned char **out, unsigned *w, unsigned *h, + const unsigned char *in, size_t insize) { return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); } -unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { +unsigned lodepng_decode24(unsigned char **out, unsigned *w, unsigned *h, + const unsigned char *in, size_t insize) { return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); } #ifdef LODEPNG_COMPILE_DISK -unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, - LodePNGColorType colortype, unsigned bitdepth) { - unsigned char* buffer = 0; +unsigned lodepng_decode_file(unsigned char **out, unsigned *w, unsigned *h, + const char *filename, LodePNGColorType colortype, + unsigned bitdepth) { + unsigned char *buffer = 0; size_t buffersize; unsigned error; /* safe output values in case error happens */ *out = 0; *w = *h = 0; error = lodepng_load_file(&buffer, &buffersize, filename); - if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + if (!error) + error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, + bitdepth); lodepng_free(buffer); return error; } -unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { +unsigned lodepng_decode32_file(unsigned char **out, unsigned *w, unsigned *h, + const char *filename) { return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); } -unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { +unsigned lodepng_decode24_file(unsigned char **out, unsigned *w, unsigned *h, + const char *filename) { return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); } #endif /*LODEPNG_COMPILE_DISK*/ -void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) { +void lodepng_decoder_settings_init(LodePNGDecoderSettings *settings) { settings->color_convert = 1; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS settings->read_text_chunks = 1; settings->remember_unknown_chunks = 0; settings->max_text_size = 16777216; - settings->max_icc_size = 16777216; /* 16MB is much more than enough for any reasonable ICC profile */ -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->max_icc_size = 16777216; /* 16MB is much more than enough for any + reasonable ICC profile */ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ settings->ignore_crc = 0; settings->ignore_critical = 0; settings->ignore_end = 0; @@ -5052,7 +5979,7 @@ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) { #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) -void lodepng_state_init(LodePNGState* state) { +void lodepng_state_init(LodePNGState *state) { #ifdef LODEPNG_COMPILE_DECODER lodepng_decoder_settings_init(&state->decoder); #endif /*LODEPNG_COMPILE_DECODER*/ @@ -5064,21 +5991,26 @@ void lodepng_state_init(LodePNGState* state) { state->error = 1; } -void lodepng_state_cleanup(LodePNGState* state) { +void lodepng_state_cleanup(LodePNGState *state) { lodepng_color_mode_cleanup(&state->info_raw); lodepng_info_cleanup(&state->info_png); } -void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) { +void lodepng_state_copy(LodePNGState *dest, const LodePNGState *source) { lodepng_state_cleanup(dest); *dest = *source; lodepng_color_mode_init(&dest->info_raw); lodepng_info_init(&dest->info_png); - dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; - dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); + if (dest->error) + return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); + if (dest->error) + return; } -#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) \ + */ #ifdef LODEPNG_COMPILE_ENCODER @@ -5086,42 +6018,44 @@ void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) { /* / PNG Encoder / */ /* ////////////////////////////////////////////////////////////////////////// */ - -static unsigned writeSignature(ucvector* out) { +static unsigned writeSignature(ucvector *out) { size_t pos = out->size; const unsigned char signature[] = {137, 80, 78, 71, 13, 10, 26, 10}; /*8 bytes PNG signature, aka the magic bytes*/ - if(!ucvector_resize(out, out->size + 8)) return 83; /*alloc fail*/ + if (!ucvector_resize(out, out->size + 8)) + return 83; /*alloc fail*/ lodepng_memcpy(out->data + pos, signature, 8); return 0; } -static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) { +static unsigned addChunk_IHDR(ucvector *out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, + unsigned interlace_method) { unsigned char *chunk, *data; CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 13, "IHDR")); data = chunk + 8; - lodepng_set32bitInt(data + 0, w); /*width*/ - lodepng_set32bitInt(data + 4, h); /*height*/ - data[8] = (unsigned char)bitdepth; /*bit depth*/ + lodepng_set32bitInt(data + 0, w); /*width*/ + lodepng_set32bitInt(data + 4, h); /*height*/ + data[8] = (unsigned char)bitdepth; /*bit depth*/ data[9] = (unsigned char)colortype; /*color type*/ - data[10] = 0; /*compression method*/ - data[11] = 0; /*filter method*/ - data[12] = interlace_method; /*interlace method*/ + data[10] = 0; /*compression method*/ + data[11] = 0; /*filter method*/ + data[12] = interlace_method; /*interlace method*/ lodepng_chunk_generate_crc(chunk); return 0; } /* only adds the chunk if needed (there is a key or palette with alpha) */ -static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { - unsigned char* chunk; +static unsigned addChunk_PLTE(ucvector *out, const LodePNGColorMode *info) { + unsigned char *chunk; size_t i, j = 8; - CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE")); + CERROR_TRY_RETURN( + lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE")); - for(i = 0; i != info->palettesize; ++i) { + for (i = 0; i != info->palettesize; ++i) { /*add all channels except alpha channel*/ chunk[j++] = info->palette[i * 4 + 0]; chunk[j++] = info->palette[i * 4 + 1]; @@ -5132,29 +6066,32 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { return 0; } -static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { - unsigned char* chunk = 0; +static unsigned addChunk_tRNS(ucvector *out, const LodePNGColorMode *info) { + unsigned char *chunk = 0; - if(info->colortype == LCT_PALETTE) { + if (info->colortype == LCT_PALETTE) { size_t i, amount = info->palettesize; - /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ - for(i = info->palettesize; i != 0; --i) { - if(info->palette[4 * (i - 1) + 3] != 255) break; + /*the tail of palette values that all have 255 as alpha, does not have to be + * encoded*/ + for (i = info->palettesize; i != 0; --i) { + if (info->palette[4 * (i - 1) + 3] != 255) + break; --amount; } - if(amount) { + if (amount) { CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, "tRNS")); /*add the alpha channel values from the palette*/ - for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3]; + for (i = 0; i != amount; ++i) + chunk[8 + i] = info->palette[4 * i + 3]; } - } else if(info->colortype == LCT_GREY) { - if(info->key_defined) { + } else if (info->colortype == LCT_GREY) { + if (info->key_defined) { CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "tRNS")); chunk[8] = (unsigned char)(info->key_r >> 8); chunk[9] = (unsigned char)(info->key_r & 255); } - } else if(info->colortype == LCT_RGB) { - if(info->key_defined) { + } else if (info->colortype == LCT_RGB) { + if (info->key_defined) { CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "tRNS")); chunk[8] = (unsigned char)(info->key_r >> 8); chunk[9] = (unsigned char)(info->key_r & 255); @@ -5165,35 +6102,40 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { } } - if(chunk) lodepng_chunk_generate_crc(chunk); + if (chunk) + lodepng_chunk_generate_crc(chunk); return 0; } -static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, - LodePNGCompressSettings* zlibsettings) { +static unsigned addChunk_IDAT(ucvector *out, const unsigned char *data, + size_t datasize, + LodePNGCompressSettings *zlibsettings) { unsigned error = 0; - unsigned char* zlib = 0; + unsigned char *zlib = 0; size_t zlibsize = 0; error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings); - if(!error) { + if (!error) { error = lodepng_chunk_createv(out, zlibsize, "IDAT", zlib); } lodepng_free(zlib); return error; } -static unsigned addChunk_IEND(ucvector* out) { +static unsigned addChunk_IEND(ucvector *out) { return lodepng_chunk_createv(out, 0, "IEND", 0); } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) { - unsigned char* chunk = 0; - size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring); +static unsigned addChunk_tEXt(ucvector *out, const char *keyword, + const char *textstring) { + unsigned char *chunk = 0; + size_t keysize = lodepng_strlen(keyword), + textsize = lodepng_strlen(textstring); size_t size = keysize + 1 + textsize; - if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + if (keysize < 1 || keysize > 79) + return 89; /*error: invalid keyword size*/ CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, "tEXt")); lodepng_memcpy(chunk + 8, keyword, keysize); chunk[8 + keysize] = 0; /*null termination char*/ @@ -5202,23 +6144,26 @@ static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* te return 0; } -static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, - LodePNGCompressSettings* zlibsettings) { +static unsigned addChunk_zTXt(ucvector *out, const char *keyword, + const char *textstring, + LodePNGCompressSettings *zlibsettings) { unsigned error = 0; - unsigned char* chunk = 0; - unsigned char* compressed = 0; + unsigned char *chunk = 0; + unsigned char *compressed = 0; size_t compressedsize = 0; size_t textsize = lodepng_strlen(textstring); size_t keysize = lodepng_strlen(keyword); - if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + if (keysize < 1 || keysize > 79) + return 89; /*error: invalid keyword size*/ - error = zlib_compress(&compressed, &compressedsize, - (const unsigned char*)textstring, textsize, zlibsettings); - if(!error) { + error = + zlib_compress(&compressed, &compressedsize, + (const unsigned char *)textstring, textsize, zlibsettings); + if (!error) { size_t size = keysize + 2 + compressedsize; error = lodepng_chunk_init(&chunk, out, size, "zTXt"); } - if(!error) { + if (!error) { lodepng_memcpy(chunk + 8, keyword, keysize); chunk[8 + keysize] = 0; /*null termination char*/ chunk[9 + keysize] = 0; /*compression method: 0*/ @@ -5230,39 +6175,45 @@ static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* te return error; } -static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyword, const char* langtag, - const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) { +static unsigned addChunk_iTXt(ucvector *out, unsigned compress, + const char *keyword, const char *langtag, + const char *transkey, const char *textstring, + LodePNGCompressSettings *zlibsettings) { unsigned error = 0; - unsigned char* chunk = 0; - unsigned char* compressed = 0; + unsigned char *chunk = 0; + unsigned char *compressed = 0; size_t compressedsize = 0; size_t textsize = lodepng_strlen(textstring); - size_t keysize = lodepng_strlen(keyword), langsize = lodepng_strlen(langtag), transsize = lodepng_strlen(transkey); + size_t keysize = lodepng_strlen(keyword), langsize = lodepng_strlen(langtag), + transsize = lodepng_strlen(transkey); - if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + if (keysize < 1 || keysize > 79) + return 89; /*error: invalid keyword size*/ - if(compress) { + if (compress) { error = zlib_compress(&compressed, &compressedsize, - (const unsigned char*)textstring, textsize, zlibsettings); + (const unsigned char *)textstring, textsize, + zlibsettings); } - if(!error) { - size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize); + if (!error) { + size_t size = keysize + 3 + langsize + 1 + transsize + 1 + + (compress ? compressedsize : textsize); error = lodepng_chunk_init(&chunk, out, size, "iTXt"); } - if(!error) { + if (!error) { size_t pos = 8; lodepng_memcpy(chunk + pos, keyword, keysize); pos += keysize; - chunk[pos++] = 0; /*null termination char*/ + chunk[pos++] = 0; /*null termination char*/ chunk[pos++] = (compress ? 1 : 0); /*compression flag*/ - chunk[pos++] = 0; /*compression method: 0*/ + chunk[pos++] = 0; /*compression method: 0*/ lodepng_memcpy(chunk + pos, langtag, langsize); pos += langsize; chunk[pos++] = 0; /*null termination char*/ lodepng_memcpy(chunk + pos, transkey, transsize); pos += transsize; chunk[pos++] = 0; /*null termination char*/ - if(compress) { + if (compress) { lodepng_memcpy(chunk + pos, compressed, compressedsize); } else { lodepng_memcpy(chunk + pos, textstring, textsize); @@ -5274,13 +6225,15 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyw return error; } -static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) { - unsigned char* chunk = 0; - if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { +static unsigned addChunk_bKGD(ucvector *out, const LodePNGInfo *info) { + unsigned char *chunk = 0; + if (info->color.colortype == LCT_GREY || + info->color.colortype == LCT_GREY_ALPHA) { CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "bKGD")); chunk[8] = (unsigned char)(info->background_r >> 8); chunk[9] = (unsigned char)(info->background_r & 255); - } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { + } else if (info->color.colortype == LCT_RGB || + info->color.colortype == LCT_RGBA) { CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "bKGD")); chunk[8] = (unsigned char)(info->background_r >> 8); chunk[9] = (unsigned char)(info->background_r & 255); @@ -5288,16 +6241,17 @@ static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) { chunk[11] = (unsigned char)(info->background_g & 255); chunk[12] = (unsigned char)(info->background_b >> 8); chunk[13] = (unsigned char)(info->background_b & 255); - } else if(info->color.colortype == LCT_PALETTE) { + } else if (info->color.colortype == LCT_PALETTE) { CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "bKGD")); chunk[8] = (unsigned char)(info->background_r & 255); /*palette index*/ } - if(chunk) lodepng_chunk_generate_crc(chunk); + if (chunk) + lodepng_chunk_generate_crc(chunk); return 0; } -static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) { - unsigned char* chunk; +static unsigned addChunk_tIME(ucvector *out, const LodePNGTime *time) { + unsigned char *chunk; CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 7, "tIME")); chunk[8] = (unsigned char)(time->year >> 8); chunk[9] = (unsigned char)(time->year & 255); @@ -5310,8 +6264,8 @@ static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) { return 0; } -static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) { - unsigned char* chunk; +static unsigned addChunk_pHYs(ucvector *out, const LodePNGInfo *info) { + unsigned char *chunk; CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 9, "pHYs")); lodepng_set32bitInt(chunk + 8, info->phys_x); lodepng_set32bitInt(chunk + 12, info->phys_y); @@ -5320,16 +6274,16 @@ static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) { return 0; } -static unsigned addChunk_gAMA(ucvector* out, const LodePNGInfo* info) { - unsigned char* chunk; +static unsigned addChunk_gAMA(ucvector *out, const LodePNGInfo *info) { + unsigned char *chunk; CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "gAMA")); lodepng_set32bitInt(chunk + 8, info->gama_gamma); lodepng_chunk_generate_crc(chunk); return 0; } -static unsigned addChunk_cHRM(ucvector* out, const LodePNGInfo* info) { - unsigned char* chunk; +static unsigned addChunk_cHRM(ucvector *out, const LodePNGInfo *info) { + unsigned char *chunk; CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 32, "cHRM")); lodepng_set32bitInt(chunk + 8, info->chrm_white_x); lodepng_set32bitInt(chunk + 12, info->chrm_white_y); @@ -5343,26 +6297,28 @@ static unsigned addChunk_cHRM(ucvector* out, const LodePNGInfo* info) { return 0; } -static unsigned addChunk_sRGB(ucvector* out, const LodePNGInfo* info) { +static unsigned addChunk_sRGB(ucvector *out, const LodePNGInfo *info) { unsigned char data = info->srgb_intent; return lodepng_chunk_createv(out, 1, "sRGB", &data); } -static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCompressSettings* zlibsettings) { +static unsigned addChunk_iCCP(ucvector *out, const LodePNGInfo *info, + LodePNGCompressSettings *zlibsettings) { unsigned error = 0; - unsigned char* chunk = 0; - unsigned char* compressed = 0; + unsigned char *chunk = 0; + unsigned char *compressed = 0; size_t compressedsize = 0; size_t keysize = lodepng_strlen(info->iccp_name); - if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ - error = zlib_compress(&compressed, &compressedsize, - info->iccp_profile, info->iccp_profile_size, zlibsettings); - if(!error) { + if (keysize < 1 || keysize > 79) + return 89; /*error: invalid keyword size*/ + error = zlib_compress(&compressed, &compressedsize, info->iccp_profile, + info->iccp_profile_size, zlibsettings); + if (!error) { size_t size = keysize + 2 + compressedsize; error = lodepng_chunk_init(&chunk, out, size, "iCCP"); } - if(!error) { + if (!error) { lodepng_memcpy(chunk + 8, info->iccp_name, keysize); chunk[8 + keysize] = 0; /*null termination char*/ chunk[9 + keysize] = 0; /*compression method: 0*/ @@ -5376,150 +6332,197 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, - size_t length, size_t bytewidth, unsigned char filterType) { +static void filterScanline(unsigned char *out, const unsigned char *scanline, + const unsigned char *prevline, size_t length, + size_t bytewidth, unsigned char filterType) { size_t i; - switch(filterType) { - case 0: /*None*/ - for(i = 0; i != length; ++i) out[i] = scanline[i]; - break; - case 1: /*Sub*/ - for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; - for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; - break; - case 2: /*Up*/ - if(prevline) { - for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; - } else { - for(i = 0; i != length; ++i) out[i] = scanline[i]; + switch (filterType) { + case 0: /*None*/ + for (i = 0; i != length; ++i) + out[i] = scanline[i]; + break; + case 1: /*Sub*/ + for (i = 0; i != bytewidth; ++i) + out[i] = scanline[i]; + for (i = bytewidth; i < length; ++i) + out[i] = scanline[i] - scanline[i - bytewidth]; + break; + case 2: /*Up*/ + if (prevline) { + for (i = 0; i != length; ++i) + out[i] = scanline[i] - prevline[i]; + } else { + for (i = 0; i != length; ++i) + out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if (prevline) { + for (i = 0; i != bytewidth; ++i) + out[i] = scanline[i] - (prevline[i] >> 1); + for (i = bytewidth; i < length; ++i) + out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1); + } else { + for (i = 0; i != bytewidth; ++i) + out[i] = scanline[i]; + for (i = bytewidth; i < length; ++i) + out[i] = scanline[i] - (scanline[i - bytewidth] >> 1); + } + break; + case 4: /*Paeth*/ + if (prevline) { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for (i = 0; i != bytewidth; ++i) + out[i] = (scanline[i] - prevline[i]); + for (i = bytewidth; i < length; ++i) { + out[i] = + (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], + prevline[i - bytewidth])); } - break; - case 3: /*Average*/ - if(prevline) { - for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - (prevline[i] >> 1); - for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1); - } else { - for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; - for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - (scanline[i - bytewidth] >> 1); - } - break; - case 4: /*Paeth*/ - if(prevline) { - /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ - for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); - for(i = bytewidth; i < length; ++i) { - out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); - } - } else { - for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; - /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ - for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); - } - break; - default: return; /*invalid filter type given*/ + } else { + for (i = 0; i != bytewidth; ++i) + out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - + * bytewidth]*/ + for (i = bytewidth; i < length; ++i) + out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: + return; /*invalid filter type given*/ } } /* integer binary logarithm, max return value is 31 */ static size_t ilog2(size_t i) { size_t result = 0; - if(i >= 65536) { result += 16; i >>= 16; } - if(i >= 256) { result += 8; i >>= 8; } - if(i >= 16) { result += 4; i >>= 4; } - if(i >= 4) { result += 2; i >>= 2; } - if(i >= 2) { result += 1; /*i >>= 1;*/ } + if (i >= 65536) { + result += 16; + i >>= 16; + } + if (i >= 256) { + result += 8; + i >>= 8; + } + if (i >= 16) { + result += 4; + i >>= 4; + } + if (i >= 4) { + result += 2; + i >>= 2; + } + if (i >= 2) { + result += 1; /*i >>= 1;*/ + } return result; } /* integer approximation for i * log2(i), helper function for LFS_ENTROPY */ static size_t ilog2i(size_t i) { size_t l; - if(i == 0) return 0; + if (i == 0) + return 0; l = ilog2(i); /* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u) linearly approximates the missing fractional part multiplied by i */ return i * l + ((i - (1u << l)) << 1u); } -static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, - const LodePNGColorMode* color, const LodePNGEncoderSettings* settings) { +static unsigned filter(unsigned char *out, const unsigned char *in, unsigned w, + unsigned h, const LodePNGColorMode *color, + const LodePNGEncoderSettings *settings) { /* For PNG filter method 0 - out must be a buffer with as size: h + (w * h * bpp + 7u) / 8u, because there are - the scanlines with 1 extra byte per scanline + out must be a buffer with as size: h + (w * h * bpp + 7u) / 8u, because there + are the scanlines with 1 extra byte per scanline */ unsigned bpp = lodepng_get_bpp(color); /*the width of a scanline in bytes, not including the filter type*/ size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u; - /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per + * pixel otherwise*/ size_t bytewidth = (bpp + 7u) / 8u; - const unsigned char* prevline = 0; + const unsigned char *prevline = 0; unsigned x, y; unsigned error = 0; LodePNGFilterStrategy strategy = settings->filter_strategy; /* - There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: - * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. - use fixed filtering, with the filter None). - * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is - not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply - all five filters and select the filter that produces the smallest sum of absolute values per row. - This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + There is a heuristic called the minimum sum of absolute differences heuristic, + suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do + not filter the image (i.e. use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without + Alpha), and the bit depth is not smaller than 8, then use adaptive filtering + heuristic as follows: independently for each row, apply all five filters and + select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and + filter_palette_zero is true. - If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, - but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum - heuristic is used. + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the + above heuristic is followed, but for "the other case", whatever strategy + filter_strategy is set to instead of the minimum sum heuristic is used. */ - if(settings->filter_palette_zero && - (color->colortype == LCT_PALETTE || color->bitdepth < 8)) strategy = LFS_ZERO; + if (settings->filter_palette_zero && + (color->colortype == LCT_PALETTE || color->bitdepth < 8)) + strategy = LFS_ZERO; - if(bpp == 0) return 31; /*error: invalid color type*/ + if (bpp == 0) + return 31; /*error: invalid color type*/ - if(strategy >= LFS_ZERO && strategy <= LFS_FOUR) { + if (strategy >= LFS_ZERO && strategy <= LFS_FOUR) { unsigned char type = (unsigned char)strategy; - for(y = 0; y != h; ++y) { - size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + for (y = 0; y != h; ++y) { + size_t outindex = + (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; out[outindex] = type; /*filter type byte*/ - filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, + bytewidth, type); prevline = &in[inindex]; } - } else if(strategy == LFS_MINSUM) { + } else if (strategy == LFS_MINSUM) { /*adaptive filtering*/ - unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + unsigned char + *attempt[5]; /*five filtering attempts, one for each filter type*/ size_t smallest = 0; unsigned char type, bestType = 0; - for(type = 0; type != 5; ++type) { - attempt[type] = (unsigned char*)lodepng_malloc(linebytes); - if(!attempt[type]) error = 83; /*alloc fail*/ + for (type = 0; type != 5; ++type) { + attempt[type] = (unsigned char *)lodepng_malloc(linebytes); + if (!attempt[type]) + error = 83; /*alloc fail*/ } - if(!error) { - for(y = 0; y != h; ++y) { + if (!error) { + for (y = 0; y != h; ++y) { /*try the 5 filter types*/ - for(type = 0; type != 5; ++type) { + for (type = 0; type != 5; ++type) { size_t sum = 0; - filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, + bytewidth, type); /*calculate the sum of the result*/ - if(type == 0) { - for(x = 0; x != linebytes; ++x) sum += (unsigned char)(attempt[type][x]); + if (type == 0) { + for (x = 0; x != linebytes; ++x) + sum += (unsigned char)(attempt[type][x]); } else { - for(x = 0; x != linebytes; ++x) { - /*For differences, each byte should be treated as signed, values above 127 are negative - (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. - This means filtertype 0 is almost never chosen, but that is justified.*/ + for (x = 0; x != linebytes; ++x) { + /*For differences, each byte should be treated as signed, values + above 127 are negative (converted to signed char). Filtertype 0 + isn't a difference though, so use unsigned there. This means + filtertype 0 is almost never chosen, but that is justified.*/ unsigned char s = attempt[type][x]; sum += s < 128 ? s : (255U - s); } } - /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ - if(type == 0 || sum < smallest) { + /*check if this is smallest sum (or if type == 0 it's the first case + * so always store the values)*/ + if (type == 0 || sum < smallest) { bestType = type; smallest = sum; } @@ -5528,37 +6531,45 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, prevline = &in[y * linebytes]; /*now fill the out values*/ - out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + out[y * (linebytes + 1)] = + bestType; /*the first byte of a scanline will be the filter type*/ + for (x = 0; x != linebytes; ++x) + out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; } } - for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); - } else if(strategy == LFS_ENTROPY) { - unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + for (type = 0; type != 5; ++type) + lodepng_free(attempt[type]); + } else if (strategy == LFS_ENTROPY) { + unsigned char + *attempt[5]; /*five filtering attempts, one for each filter type*/ size_t bestSum = 0; unsigned type, bestType = 0; unsigned count[256]; - for(type = 0; type != 5; ++type) { - attempt[type] = (unsigned char*)lodepng_malloc(linebytes); - if(!attempt[type]) error = 83; /*alloc fail*/ + for (type = 0; type != 5; ++type) { + attempt[type] = (unsigned char *)lodepng_malloc(linebytes); + if (!attempt[type]) + error = 83; /*alloc fail*/ } - if(!error) { - for(y = 0; y != h; ++y) { + if (!error) { + for (y = 0; y != h; ++y) { /*try the 5 filter types*/ - for(type = 0; type != 5; ++type) { + for (type = 0; type != 5; ++type) { size_t sum = 0; - filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, + bytewidth, type); lodepng_memset(count, 0, 256 * sizeof(*count)); - for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]]; + for (x = 0; x != linebytes; ++x) + ++count[attempt[type][x]]; ++count[type]; /*the filter type itself is part of the scanline*/ - for(x = 0; x != 256; ++x) { + for (x = 0; x != 256; ++x) { sum += ilog2i(count[x]); } - /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ - if(type == 0 || sum > bestSum) { + /*check if this is smallest sum (or if type == 0 it's the first case + * so always store the values)*/ + if (type == 0 || sum > bestSum) { bestType = type; bestSum = sum; } @@ -5567,90 +6578,108 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, prevline = &in[y * linebytes]; /*now fill the out values*/ - out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + out[y * (linebytes + 1)] = + bestType; /*the first byte of a scanline will be the filter type*/ + for (x = 0; x != linebytes; ++x) + out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; } } - for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); - } else if(strategy == LFS_PREDEFINED) { - for(y = 0; y != h; ++y) { - size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + for (type = 0; type != 5; ++type) + lodepng_free(attempt[type]); + } else if (strategy == LFS_PREDEFINED) { + for (y = 0; y != h; ++y) { + size_t outindex = + (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; unsigned char type = settings->predefined_filters[y]; out[outindex] = type; /*filter type byte*/ - filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, + bytewidth, type); prevline = &in[inindex]; } - } else if(strategy == LFS_BRUTE_FORCE) { + } else if (strategy == LFS_BRUTE_FORCE) { /*brute force filter chooser. - deflate the scanline after every filter attempt to see which one deflates best. - This is very slow and gives only slightly smaller, sometimes even larger, result*/ + deflate the scanline after every filter attempt to see which one deflates + best. This is very slow and gives only slightly smaller, sometimes even + larger, result*/ size_t size[5]; - unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + unsigned char + *attempt[5]; /*five filtering attempts, one for each filter type*/ size_t smallest = 0; unsigned type = 0, bestType = 0; - unsigned char* dummy; + unsigned char *dummy; LodePNGCompressSettings zlibsettings; - lodepng_memcpy(&zlibsettings, &settings->zlibsettings, sizeof(LodePNGCompressSettings)); - /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, - to simulate the true case where the tree is the same for the whole image. Sometimes it gives - better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare - cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + lodepng_memcpy(&zlibsettings, &settings->zlibsettings, + sizeof(LodePNGCompressSettings)); + /*use fixed tree on the attempts so that the tree is not adapted to the + filtertype on purpose, to simulate the true case where the tree is the same + for the whole image. Sometimes it gives better result with dynamic tree + anyway. Using the fixed tree sometimes gives worse, but in rare cases better + compression. It does make this a bit less slow, so it's worth doing this.*/ zlibsettings.btype = 1; - /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG - images only, so disable it*/ + /*a custom encoder likely doesn't read the btype setting and is optimized + for complete PNG images only, so disable it*/ zlibsettings.custom_zlib = 0; zlibsettings.custom_deflate = 0; - for(type = 0; type != 5; ++type) { - attempt[type] = (unsigned char*)lodepng_malloc(linebytes); - if(!attempt[type]) error = 83; /*alloc fail*/ + for (type = 0; type != 5; ++type) { + attempt[type] = (unsigned char *)lodepng_malloc(linebytes); + if (!attempt[type]) + error = 83; /*alloc fail*/ } - if(!error) { - for(y = 0; y != h; ++y) /*try the 5 filter types*/ { - for(type = 0; type != 5; ++type) { + if (!error) { + for (y = 0; y != h; ++y) /*try the 5 filter types*/ { + for (type = 0; type != 5; ++type) { unsigned testsize = (unsigned)linebytes; - /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by + testing a part of the row*/ - filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, + bytewidth, type); size[type] = 0; dummy = 0; - zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings); + zlib_compress(&dummy, &size[type], attempt[type], testsize, + &zlibsettings); lodepng_free(dummy); - /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ - if(type == 0 || size[type] < smallest) { + /*check if this is smallest size (or if type == 0 it's the first case + * so always store the values)*/ + if (type == 0 || size[type] < smallest) { bestType = type; smallest = size[type]; } } prevline = &in[y * linebytes]; - out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + out[y * (linebytes + 1)] = + bestType; /*the first byte of a scanline will be the filter type*/ + for (x = 0; x != linebytes; ++x) + out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; } } - for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); - } - else return 88; /* unknown filter strategy */ + for (type = 0; type != 5; ++type) + lodepng_free(attempt[type]); + } else + return 88; /* unknown filter strategy */ return error; } -static void addPaddingBits(unsigned char* out, const unsigned char* in, +static void addPaddingBits(unsigned char *out, const unsigned char *in, size_t olinebits, size_t ilinebits, unsigned h) { /*The opposite of the removePaddingBits function olinebits must be >= ilinebits*/ unsigned y; size_t diff = olinebits - ilinebits; size_t obp = 0, ibp = 0; /*bit pointers*/ - for(y = 0; y != h; ++y) { + for (y = 0; y != h; ++y) { size_t x; - for(x = 0; x < ilinebits; ++x) { + for (x = 0; x < ilinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } /*obp += diff; --> no, fill in some value in the padding bits too, to avoid "Use of uninitialised value of size ###" warning from valgrind*/ - for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); + for (x = 0; x != diff; ++x) + setBitOfReversedStream(&obp, out, 0); } } @@ -5665,69 +6694,84 @@ in has the following size in bits: w * h * bpp. out is possibly bigger due to padding bits between reduced images NOTE: comments about padding bits are only relevant if bpp < 8 */ -static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { +static void Adam7_interlace(unsigned char *out, const unsigned char *in, + unsigned w, unsigned h, unsigned bpp) { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; unsigned i; - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, + passstart, w, h, bpp); - if(bpp >= 8) { - for(i = 0; i != 7; ++i) { + if (bpp >= 8) { + for (i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8u; - for(y = 0; y < passh[i]; ++y) - for(x = 0; x < passw[i]; ++x) { - size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; - size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; - for(b = 0; b < bytewidth; ++b) { - out[pixeloutstart + b] = in[pixelinstart + b]; + for (y = 0; y < passh[i]; ++y) + for (x = 0; x < passw[i]; ++x) { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + + ADAM7_IX[i] + x * ADAM7_DX[i]) * + bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for (b = 0; b < bytewidth; ++b) { + out[pixeloutstart + b] = in[pixelinstart + b]; + } } - } } - } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { - for(i = 0; i != 7; ++i) { + } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit + pointers*/ + { + for (i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ - for(y = 0; y < passh[i]; ++y) - for(x = 0; x < passw[i]; ++x) { - ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; - obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); - for(b = 0; b < bpp; ++b) { - unsigned char bit = readBitFromReversedStream(&ibp, in); - setBitOfReversedStream(&obp, out, bit); + for (y = 0; y < passh[i]; ++y) + for (x = 0; x < passw[i]; ++x) { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for (b = 0; b < bpp; ++b) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } } - } } } } -/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. -return value is error**/ -static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, - unsigned w, unsigned h, - const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) { +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in +must contain the full image. return value is error**/ +static unsigned preProcessScanlines(unsigned char **out, size_t *outsize, + const unsigned char *in, unsigned w, + unsigned h, const LodePNGInfo *info_png, + const LodePNGEncoderSettings *settings) { /* - This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: - *) if no Adam7: 1) add padding bits (= possible extra bits per scanline if bpp < 8) 2) filter + This function converts the pure 2D image with the PNG's colortype, into + filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= possible extra bits per scanline if bpp + < 8) 2) filter *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter */ unsigned bpp = lodepng_get_bpp(&info_png->color); unsigned error = 0; - if(info_png->interlace_method == 0) { - *outsize = h + (h * ((w * bpp + 7u) / 8u)); /*image size plus an extra byte per scanline + possible padding bits*/ - *out = (unsigned char*)lodepng_malloc(*outsize); - if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + if (info_png->interlace_method == 0) { + *outsize = + h + (h * ((w * bpp + 7u) / 8u)); /*image size plus an extra byte per + scanline + possible padding bits*/ + *out = (unsigned char *)lodepng_malloc(*outsize); + if (!(*out) && (*outsize)) + error = 83; /*alloc fail*/ - if(!error) { + if (!error) { /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ - if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { - unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7u) / 8u)); - if(!padded) error = 83; /*alloc fail*/ - if(!error) { + if (bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { + unsigned char *padded = + (unsigned char *)lodepng_malloc(h * ((w * bpp + 7u) / 8u)); + if (!padded) + error = 83; /*alloc fail*/ + if (!error) { addPaddingBits(padded, in, ((w * bpp + 7u) / 8u) * 8u, w * bpp, h); error = filter(*out, padded, w, h, &info_png->color, settings); } @@ -5740,36 +6784,45 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const } else /*interlace_method is 1 (Adam7)*/ { unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; - unsigned char* adam7; + unsigned char *adam7; - Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, + passstart, w, h, bpp); - *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ - *out = (unsigned char*)lodepng_malloc(*outsize); - if(!(*out)) error = 83; /*alloc fail*/ + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + + possible padding bits*/ + *out = (unsigned char *)lodepng_malloc(*outsize); + if (!(*out)) + error = 83; /*alloc fail*/ - adam7 = (unsigned char*)lodepng_malloc(passstart[7]); - if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + adam7 = (unsigned char *)lodepng_malloc(passstart[7]); + if (!adam7 && passstart[7]) + error = 83; /*alloc fail*/ - if(!error) { + if (!error) { unsigned i; Adam7_interlace(adam7, in, w, h, bpp); - for(i = 0; i != 7; ++i) { - if(bpp < 8) { - unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); - if(!padded) ERROR_BREAK(83); /*alloc fail*/ + for (i = 0; i != 7; ++i) { + if (bpp < 8) { + unsigned char *padded = (unsigned char *)lodepng_malloc( + padded_passstart[i + 1] - padded_passstart[i]); + if (!padded) + ERROR_BREAK(83); /*alloc fail*/ addPaddingBits(padded, &adam7[passstart[i]], - ((passw[i] * bpp + 7u) / 8u) * 8u, passw[i] * bpp, passh[i]); - error = filter(&(*out)[filter_passstart[i]], padded, - passw[i], passh[i], &info_png->color, settings); + ((passw[i] * bpp + 7u) / 8u) * 8u, passw[i] * bpp, + passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, passw[i], + passh[i], &info_png->color, settings); lodepng_free(padded); } else { - error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], - passw[i], passh[i], &info_png->color, settings); + error = + filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); } - if(error) break; + if (error) + break; } } @@ -5780,9 +6833,10 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) { - unsigned char* inchunk = data; - while((size_t)(inchunk - data) < datasize) { +static unsigned addUnknownChunks(ucvector *out, unsigned char *data, + size_t datasize) { + unsigned char *inchunk = data; + while ((size_t)(inchunk - data) < datasize) { CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); out->allocsize = out->size; /*fix the allocsize again*/ inchunk = lodepng_chunk_next(inchunk, data + datasize); @@ -5790,7 +6844,7 @@ static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t data return 0; } -static unsigned isGrayICCProfile(const unsigned char* profile, unsigned size) { +static unsigned isGrayICCProfile(const unsigned char *profile, unsigned size) { /* It is a gray profile if bytes 16-19 are "GRAY", rgb profile if bytes 16-19 are "RGB ". We do not perform any full parsing of the ICC profile here, other @@ -5800,25 +6854,29 @@ static unsigned isGrayICCProfile(const unsigned char* profile, unsigned size) { (sadly limiting compression opportunities if the input data is grayscale RGB data), and requires using a gray color model if it is "GRAY". */ - if(size < 20) return 0; - return profile[16] == 'G' && profile[17] == 'R' && profile[18] == 'A' && profile[19] == 'Y'; + if (size < 20) + return 0; + return profile[16] == 'G' && profile[17] == 'R' && profile[18] == 'A' && + profile[19] == 'Y'; } -static unsigned isRGBICCProfile(const unsigned char* profile, unsigned size) { +static unsigned isRGBICCProfile(const unsigned char *profile, unsigned size) { /* See comment in isGrayICCProfile*/ - if(size < 20) return 0; - return profile[16] == 'R' && profile[17] == 'G' && profile[18] == 'B' && profile[19] == ' '; + if (size < 20) + return 0; + return profile[16] == 'R' && profile[17] == 'G' && profile[18] == 'B' && + profile[19] == ' '; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ -unsigned lodepng_encode(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h, - LodePNGState* state) { - unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ +unsigned lodepng_encode(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, unsigned h, + LodePNGState *state) { + unsigned char *data = 0; /*uncompressed version of the IDAT chunk data*/ size_t datasize = 0; ucvector outv = ucvector_init(NULL, 0); LodePNGInfo info; - const LodePNGInfo* info_png = &state->info_png; + const LodePNGInfo *info_png = &state->info_png; lodepng_info_init(&info); @@ -5828,61 +6886,75 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, state->error = 0; /*check input values validity*/ - if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette) - && (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) { + if ((info_png->color.colortype == LCT_PALETTE || + state->encoder.force_palette) && + (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) { state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ goto cleanup; } - if(state->encoder.zlibsettings.btype > 2) { + if (state->encoder.zlibsettings.btype > 2) { state->error = 61; /*error: invalid btype*/ goto cleanup; } - if(info_png->interlace_method > 1) { + if (info_png->interlace_method > 1) { state->error = 71; /*error: invalid interlace mode*/ goto cleanup; } - state->error = checkColorValidity(info_png->color.colortype, info_png->color.bitdepth); - if(state->error) goto cleanup; /*error: invalid color type given*/ - state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); - if(state->error) goto cleanup; /*error: invalid color type given*/ + state->error = + checkColorValidity(info_png->color.colortype, info_png->color.bitdepth); + if (state->error) + goto cleanup; /*error: invalid color type given*/ + state->error = + checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if (state->error) + goto cleanup; /*error: invalid color type given*/ /* color convert and compute scanline filter types */ lodepng_info_copy(&info, &state->info_png); - if(state->encoder.auto_convert) { + if (state->encoder.auto_convert) { LodePNGColorStats stats; lodepng_color_stats_init(&stats); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - if(info_png->iccp_defined && + if (info_png->iccp_defined && isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) { - /*the PNG specification does not allow to use palette with a GRAY ICC profile, even - if the palette has only gray colors, so disallow it.*/ + /*the PNG specification does not allow to use palette with a GRAY ICC + profile, even if the palette has only gray colors, so disallow it.*/ stats.allow_palette = 0; } - if(info_png->iccp_defined && + if (info_png->iccp_defined && isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) { - /*the PNG specification does not allow to use grayscale color with RGB ICC profile, so disallow gray.*/ + /*the PNG specification does not allow to use grayscale color with RGB ICC + * profile, so disallow gray.*/ stats.allow_greyscale = 0; } #endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ - state->error = lodepng_compute_color_stats(&stats, image, w, h, &state->info_raw); - if(state->error) goto cleanup; + state->error = + lodepng_compute_color_stats(&stats, image, w, h, &state->info_raw); + if (state->error) + goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - if(info_png->background_defined) { + if (info_png->background_defined) { /*the background chunk's color must be taken into account as well*/ unsigned r = 0, g = 0, b = 0; LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16); - lodepng_convert_rgb(&r, &g, &b, info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color); + lodepng_convert_rgb(&r, &g, &b, info_png->background_r, + info_png->background_g, info_png->background_b, + &mode16, &info_png->color); state->error = lodepng_color_stats_add(&stats, r, g, b, 65535); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } #endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ state->error = auto_choose_color(&info.color, &state->info_raw, &stats); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*also convert the background chunk*/ - if(info_png->background_defined) { - if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b, - info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) { + if (info_png->background_defined) { + if (lodepng_convert_rgb(&info.background_r, &info.background_g, + &info.background_b, info_png->background_r, + info_png->background_g, info_png->background_b, + &info.color, &info_png->color)) { state->error = 104; goto cleanup; } @@ -5890,15 +6962,18 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, #endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ } #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - if(info_png->iccp_defined) { - unsigned gray_icc = isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); - unsigned rgb_icc = isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); - unsigned gray_png = info.color.colortype == LCT_GREY || info.color.colortype == LCT_GREY_ALPHA; - if(!gray_icc && !rgb_icc) { + if (info_png->iccp_defined) { + unsigned gray_icc = + isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); + unsigned rgb_icc = + isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); + unsigned gray_png = info.color.colortype == LCT_GREY || + info.color.colortype == LCT_GREY_ALPHA; + if (!gray_icc && !rgb_icc) { state->error = 100; /* Disallowed profile color type for PNG */ goto cleanup; } - if(gray_icc != gray_png) { + if (gray_icc != gray_png) { /*Not allowed to use RGB/RGBA/palette with GRAY ICC profile or vice versa, or in case of auto_convert, it wasn't possible to find appropriate model*/ state->error = state->encoder.auto_convert ? 102 : 101; @@ -5906,23 +6981,31 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, } } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ - if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) { - unsigned char* converted; - size_t size = ((size_t)w * (size_t)h * (size_t)lodepng_get_bpp(&info.color) + 7u) / 8u; + if (!lodepng_color_mode_equal(&state->info_raw, &info.color)) { + unsigned char *converted; + size_t size = + ((size_t)w * (size_t)h * (size_t)lodepng_get_bpp(&info.color) + 7u) / + 8u; - converted = (unsigned char*)lodepng_malloc(size); - if(!converted && size) state->error = 83; /*alloc fail*/ - if(!state->error) { - state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + converted = (unsigned char *)lodepng_malloc(size); + if (!converted && size) + state->error = 83; /*alloc fail*/ + if (!state->error) { + state->error = lodepng_convert(converted, image, &info.color, + &state->info_raw, w, h); } - if(!state->error) { - state->error = preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + if (!state->error) { + state->error = preProcessScanlines(&data, &datasize, converted, w, h, + &info, &state->encoder); } lodepng_free(converted); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } else { - state->error = preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); - if(state->error) goto cleanup; + state->error = preProcessScanlines(&data, &datasize, image, w, h, &info, + &state->encoder); + if (state->error) + goto cleanup; } /* output all PNG chunks */ { @@ -5931,134 +7014,168 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*write signature and chunks*/ state->error = writeSignature(&outv); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; /*IHDR*/ - state->error = addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); - if(state->error) goto cleanup; + state->error = addChunk_IHDR(&outv, w, h, info.color.colortype, + info.color.bitdepth, info.interlace_method); + if (state->error) + goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*unknown chunks between IHDR and PLTE*/ - if(info.unknown_chunks_data[0]) { - state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); - if(state->error) goto cleanup; + if (info.unknown_chunks_data[0]) { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], + info.unknown_chunks_size[0]); + if (state->error) + goto cleanup; } /*color profile chunks must come before PLTE */ - if(info.iccp_defined) { + if (info.iccp_defined) { state->error = addChunk_iCCP(&outv, &info, &state->encoder.zlibsettings); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } - if(info.srgb_defined) { + if (info.srgb_defined) { state->error = addChunk_sRGB(&outv, &info); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } - if(info.gama_defined) { + if (info.gama_defined) { state->error = addChunk_gAMA(&outv, &info); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } - if(info.chrm_defined) { + if (info.chrm_defined) { state->error = addChunk_cHRM(&outv, &info); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*PLTE*/ - if(info.color.colortype == LCT_PALETTE) { + if (info.color.colortype == LCT_PALETTE) { state->error = addChunk_PLTE(&outv, &info.color); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } - if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) { - /*force_palette means: write suggested palette for truecolor in PLTE chunk*/ + if (state->encoder.force_palette && + (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) { + /*force_palette means: write suggested palette for truecolor in PLTE + * chunk*/ state->error = addChunk_PLTE(&outv, &info.color); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } /*tRNS (this will only add if when necessary) */ state->error = addChunk_tRNS(&outv, &info.color); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*bKGD (must come between PLTE and the IDAt chunks*/ - if(info.background_defined) { + if (info.background_defined) { state->error = addChunk_bKGD(&outv, &info); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } /*pHYs (must come before the IDAT chunks)*/ - if(info.phys_defined) { + if (info.phys_defined) { state->error = addChunk_pHYs(&outv, &info); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } /*unknown chunks between PLTE and IDAT*/ - if(info.unknown_chunks_data[1]) { - state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); - if(state->error) goto cleanup; + if (info.unknown_chunks_data[1]) { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], + info.unknown_chunks_size[1]); + if (state->error) + goto cleanup; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*IDAT (multiple IDAT chunks must be consecutive)*/ - state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); - if(state->error) goto cleanup; + state->error = + addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if (state->error) + goto cleanup; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*tIME*/ - if(info.time_defined) { + if (info.time_defined) { state->error = addChunk_tIME(&outv, &info.time); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } /*tEXt and/or zTXt*/ - for(i = 0; i != info.text_num; ++i) { - if(lodepng_strlen(info.text_keys[i]) > 79) { + for (i = 0; i != info.text_num; ++i) { + if (lodepng_strlen(info.text_keys[i]) > 79) { state->error = 66; /*text chunk too large*/ goto cleanup; } - if(lodepng_strlen(info.text_keys[i]) < 1) { + if (lodepng_strlen(info.text_keys[i]) < 1) { state->error = 67; /*text chunk too small*/ goto cleanup; } - if(state->encoder.text_compression) { - state->error = addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); - if(state->error) goto cleanup; + if (state->encoder.text_compression) { + state->error = + addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], + &state->encoder.zlibsettings); + if (state->error) + goto cleanup; } else { - state->error = addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); - if(state->error) goto cleanup; + state->error = + addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + if (state->error) + goto cleanup; } } /*LodePNG version id in text chunk*/ - if(state->encoder.add_id) { + if (state->encoder.add_id) { unsigned already_added_id_text = 0; - for(i = 0; i != info.text_num; ++i) { - const char* k = info.text_keys[i]; - /* Could use strcmp, but we're not calling or reimplementing this C library function for this use only */ - if(k[0] == 'L' && k[1] == 'o' && k[2] == 'd' && k[3] == 'e' && - k[4] == 'P' && k[5] == 'N' && k[6] == 'G' && k[7] == '\0') { + for (i = 0; i != info.text_num; ++i) { + const char *k = info.text_keys[i]; + /* Could use strcmp, but we're not calling or reimplementing this C + * library function for this use only */ + if (k[0] == 'L' && k[1] == 'o' && k[2] == 'd' && k[3] == 'e' && + k[4] == 'P' && k[5] == 'N' && k[6] == 'G' && k[7] == '\0') { already_added_id_text = 1; break; } } - if(already_added_id_text == 0) { - state->error = addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ - if(state->error) goto cleanup; + if (already_added_id_text == 0) { + state->error = addChunk_tEXt( + &outv, "LodePNG", + LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + if (state->error) + goto cleanup; } } /*iTXt*/ - for(i = 0; i != info.itext_num; ++i) { - if(lodepng_strlen(info.itext_keys[i]) > 79) { + for (i = 0; i != info.itext_num; ++i) { + if (lodepng_strlen(info.itext_keys[i]) > 79) { state->error = 66; /*text chunk too large*/ goto cleanup; } - if(lodepng_strlen(info.itext_keys[i]) < 1) { + if (lodepng_strlen(info.itext_keys[i]) < 1) { state->error = 67; /*text chunk too small*/ goto cleanup; } state->error = addChunk_iTXt( - &outv, state->encoder.text_compression, - info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], - &state->encoder.zlibsettings); - if(state->error) goto cleanup; + &outv, state->encoder.text_compression, info.itext_keys[i], + info.itext_langtags[i], info.itext_transkeys[i], + info.itext_strings[i], &state->encoder.zlibsettings); + if (state->error) + goto cleanup; } /*unknown chunks between IDAT and IEND*/ - if(info.unknown_chunks_data[2]) { - state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); - if(state->error) goto cleanup; + if (info.unknown_chunks_data[2]) { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], + info.unknown_chunks_size[2]); + if (state->error) + goto cleanup; } #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ state->error = addChunk_IEND(&outv); - if(state->error) goto cleanup; + if (state->error) + goto cleanup; } cleanup: @@ -6072,8 +7189,10 @@ cleanup: return state->error; } -unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, - unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { +unsigned lodepng_encode_memory(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, + unsigned h, LodePNGColorType colortype, + unsigned bitdepth) { unsigned error; LodePNGState state; lodepng_state_init(&state); @@ -6087,35 +7206,42 @@ unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsig return error; } -unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { +unsigned lodepng_encode32(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, unsigned h) { return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); } -unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { +unsigned lodepng_encode24(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, unsigned h) { return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); } #ifdef LODEPNG_COMPILE_DISK -unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) { - unsigned char* buffer; +unsigned lodepng_encode_file(const char *filename, const unsigned char *image, + unsigned w, unsigned h, LodePNGColorType colortype, + unsigned bitdepth) { + unsigned char *buffer; size_t buffersize; - unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); - if(!error) error = lodepng_save_file(buffer, buffersize, filename); + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, + colortype, bitdepth); + if (!error) + error = lodepng_save_file(buffer, buffersize, filename); lodepng_free(buffer); return error; } -unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { +unsigned lodepng_encode32_file(const char *filename, const unsigned char *image, + unsigned w, unsigned h) { return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); } -unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { +unsigned lodepng_encode24_file(const char *filename, const unsigned char *image, + unsigned w, unsigned h) { return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); } #endif /*LODEPNG_COMPILE_DISK*/ -void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) { +void lodepng_encoder_settings_init(LodePNGEncoderSettings *settings) { lodepng_compress_settings_init(&settings->zlibsettings); settings->filter_palette_zero = 1; settings->filter_strategy = LFS_MINSUM; @@ -6136,128 +7262,261 @@ void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) { This returns the description of a numerical error code in English. This is also the documentation of all the error codes. */ -const char* lodepng_error_text(unsigned code) { - switch(code) { - case 0: return "no error, everything went ok"; - case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ - case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ - case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ - case 13: return "problem while processing dynamic deflate block"; - case 14: return "problem while processing dynamic deflate block"; - case 15: return "problem while processing dynamic deflate block"; - /*this error could happen if there are only 0 or 1 symbols present in the huffman code:*/ - case 16: return "invalid code while processing dynamic deflate block"; - case 17: return "end of out buffer memory reached while inflating"; - case 18: return "invalid distance code while inflating"; - case 19: return "end of out buffer memory reached while inflating"; - case 20: return "invalid deflate block BTYPE encountered while decoding"; - case 21: return "NLEN is not ones complement of LEN in a deflate block"; +const char *lodepng_error_text(unsigned code) { + switch (code) { + case 0: + return "no error, everything went ok"; + case 1: + return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error + checking makes no sense yet*/ + case 10: + return "end of input memory reached without huffman end code"; /*while + huffman + decoding*/ + case 11: + return "error in code tree made it jump outside of huffman tree"; /*while + huffman + decoding*/ + case 13: + return "problem while processing dynamic deflate block"; + case 14: + return "problem while processing dynamic deflate block"; + case 15: + return "problem while processing dynamic deflate block"; + /*this error could happen if there are only 0 or 1 symbols present in the + * huffman code:*/ + case 16: + return "invalid code while processing dynamic deflate block"; + case 17: + return "end of out buffer memory reached while inflating"; + case 18: + return "invalid distance code while inflating"; + case 19: + return "end of out buffer memory reached while inflating"; + case 20: + return "invalid deflate block BTYPE encountered while decoding"; + case 21: + return "NLEN is not ones complement of LEN in a deflate block"; - /*end of out buffer memory reached while inflating: - This can happen if the inflated deflate data is longer than the amount of bytes required to fill up - all the pixels of the image, given the color depth and image dimensions. Something that doesn't - happen in a normal, well encoded, PNG image.*/ - case 22: return "end of out buffer memory reached while inflating"; - case 23: return "end of in buffer memory reached while inflating"; - case 24: return "invalid FCHECK in zlib header"; - case 25: return "invalid compression method in zlib header"; - case 26: return "FDICT encountered in zlib header while it's not used for PNG"; - case 27: return "PNG file is smaller than a PNG header"; - /*Checks the magic file header, the first 8 bytes of the PNG file*/ - case 28: return "incorrect PNG signature, it's no PNG or corrupted"; - case 29: return "first chunk is not the header chunk"; - case 30: return "chunk length too large, chunk broken off at end of file"; - case 31: return "illegal PNG color type or bpp"; - case 32: return "illegal PNG compression method"; - case 33: return "illegal PNG filter method"; - case 34: return "illegal PNG interlace method"; - case 35: return "chunk length of a chunk is too large or the chunk too small"; - case 36: return "illegal PNG filter type encountered"; - case 37: return "illegal bit depth for this color type given"; - case 38: return "the palette is too small or too big"; /*0, or more than 256 colors*/ - case 39: return "tRNS chunk before PLTE or has more entries than palette size"; - case 40: return "tRNS chunk has wrong size for grayscale image"; - case 41: return "tRNS chunk has wrong size for RGB image"; - case 42: return "tRNS chunk appeared while it was not allowed for this color type"; - case 43: return "bKGD chunk has wrong size for palette image"; - case 44: return "bKGD chunk has wrong size for grayscale image"; - case 45: return "bKGD chunk has wrong size for RGB image"; - case 48: return "empty input buffer given to decoder. Maybe caused by non-existing file?"; - case 49: return "jumped past memory while generating dynamic huffman tree"; - case 50: return "jumped past memory while generating dynamic huffman tree"; - case 51: return "jumped past memory while inflating huffman block"; - case 52: return "jumped past memory while inflating"; - case 53: return "size of zlib data too small"; - case 54: return "repeat symbol in tree while there was no value symbol yet"; - /*jumped past tree while generating huffman tree, this could be when the - tree will have more leaves than symbols after generating it out of the - given lengths. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ - case 55: return "jumped past tree while generating huffman tree"; - case 56: return "given output image colortype or bitdepth not supported for color conversion"; - case 57: return "invalid CRC encountered (checking CRC can be disabled)"; - case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; - case 59: return "requested color conversion not supported"; - case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; - case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; - /*LodePNG leaves the choice of RGB to grayscale conversion formula to the user.*/ - case 62: return "conversion from color to grayscale not supported"; - /*(2^31-1)*/ - case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; - /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ - case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; - case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; - case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; - case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; - case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; - case 71: return "invalid interlace mode given to encoder (must be 0 or 1)"; - case 72: return "while decoding, invalid compression method encountering in zTXt or iTXt chunk (it must be 0)"; - case 73: return "invalid tIME chunk size"; - case 74: return "invalid pHYs chunk size"; - /*length could be wrong, or data chopped off*/ - case 75: return "no null termination char found while decoding text chunk"; - case 76: return "iTXt chunk too short to contain required bytes"; - case 77: return "integer overflow in buffer size"; - case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ - case 79: return "failed to open file for writing"; - case 80: return "tried creating a tree of 0 symbols"; - case 81: return "lazy matching at pos 0 is impossible"; - case 82: return "color conversion to palette requested while a color isn't in palette, or index out of bounds"; - case 83: return "memory allocation failed"; - case 84: return "given image too small to contain all pixels to be encoded"; - case 86: return "impossible offset in lz77 encoding (internal bug)"; - case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; - case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; - case 89: return "text chunk keyword too short or long: must have size 1-79"; - /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ - case 90: return "windowsize must be a power of two"; - case 91: return "invalid decompressed idat size"; - case 92: return "integer overflow due to too many pixels"; - case 93: return "zero width or height is invalid"; - case 94: return "header chunk must have a size of 13 bytes"; - case 95: return "integer overflow with combined idat chunk size"; - case 96: return "invalid gAMA chunk size"; - case 97: return "invalid cHRM chunk size"; - case 98: return "invalid sRGB chunk size"; - case 99: return "invalid sRGB rendering intent"; - case 100: return "invalid ICC profile color type, the PNG specification only allows RGB or GRAY"; - case 101: return "PNG specification does not allow RGB ICC profile on gray color types and vice versa"; - case 102: return "not allowed to set grayscale ICC profile with colored pixels by PNG specification"; - case 103: return "invalid palette index in bKGD chunk. Maybe it came before PLTE chunk?"; - case 104: return "invalid bKGD color while encoding (e.g. palette index out of range)"; - case 105: return "integer overflow of bitsize"; - case 106: return "PNG file must have PLTE chunk if color type is palette"; - case 107: return "color convert from palette mode requested without setting the palette data in it"; - case 108: return "tried to add more than 256 values to a palette"; - /*this limit can be configured in LodePNGDecompressSettings*/ - case 109: return "tried to decompress zlib or deflate data larger than desired max_output_size"; - case 110: return "custom zlib or inflate decompression failed"; - case 111: return "custom zlib or deflate compression failed"; - /*max text size limit can be configured in LodePNGDecoderSettings. This error prevents - unreasonable memory consumption when decoding due to impossibly large text sizes.*/ - case 112: return "compressed text unreasonably large"; - /*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents - unreasonable memory consumption when decoding due to impossibly large ICC profile*/ - case 113: return "ICC profile unreasonably large"; + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of + bytes required to fill up all the pixels of the image, given the color depth + and image dimensions. Something that doesn't happen in a normal, well encoded, + PNG image.*/ + case 22: + return "end of out buffer memory reached while inflating"; + case 23: + return "end of in buffer memory reached while inflating"; + case 24: + return "invalid FCHECK in zlib header"; + case 25: + return "invalid compression method in zlib header"; + case 26: + return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: + return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: + return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: + return "first chunk is not the header chunk"; + case 30: + return "chunk length too large, chunk broken off at end of file"; + case 31: + return "illegal PNG color type or bpp"; + case 32: + return "illegal PNG compression method"; + case 33: + return "illegal PNG filter method"; + case 34: + return "illegal PNG interlace method"; + case 35: + return "chunk length of a chunk is too large or the chunk too small"; + case 36: + return "illegal PNG filter type encountered"; + case 37: + return "illegal bit depth for this color type given"; + case 38: + return "the palette is too small or too big"; /*0, or more than 256 colors*/ + case 39: + return "tRNS chunk before PLTE or has more entries than palette size"; + case 40: + return "tRNS chunk has wrong size for grayscale image"; + case 41: + return "tRNS chunk has wrong size for RGB image"; + case 42: + return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: + return "bKGD chunk has wrong size for palette image"; + case 44: + return "bKGD chunk has wrong size for grayscale image"; + case 45: + return "bKGD chunk has wrong size for RGB image"; + case 48: + return "empty input buffer given to decoder. Maybe caused by non-existing " + "file?"; + case 49: + return "jumped past memory while generating dynamic huffman tree"; + case 50: + return "jumped past memory while generating dynamic huffman tree"; + case 51: + return "jumped past memory while inflating huffman block"; + case 52: + return "jumped past memory while inflating"; + case 53: + return "size of zlib data too small"; + case 54: + return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lengths. They call this an oversubscribed dynamic bit lengths tree in + zlib.*/ + case 55: + return "jumped past tree while generating huffman tree"; + case 56: + return "given output image colortype or bitdepth not supported for color " + "conversion"; + case 57: + return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: + return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: + return "requested color conversion not supported"; + case 60: + return "invalid window size given in the settings of the encoder (must be " + "0-32768)"; + case 61: + return "invalid BTYPE given in the settings of the encoder (only 0, 1 and " + "2 are allowed)"; + /*LodePNG leaves the choice of RGB to grayscale conversion formula to the + * user.*/ + case 62: + return "conversion from color to grayscale not supported"; + /*(2^31-1)*/ + case 63: + return "length of a chunk too long, max allowed for PNG is 2147483647 " + "bytes per chunk"; + /*this would result in the inability of a deflated block to ever contain an + * end code. It must be at least 1.*/ + case 64: + return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: + return "the length of a text chunk keyword given to the encoder is longer " + "than the maximum of 79 bytes"; + case 67: + return "the length of a text chunk keyword given to the encoder is smaller " + "than the minimum of 1 byte"; + case 68: + return "tried to encode a PLTE chunk with a palette that has less than 1 " + "or more than 256 colors"; + case 69: + return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: + return "invalid interlace mode given to encoder (must be 0 or 1)"; + case 72: + return "while decoding, invalid compression method encountering in zTXt or " + "iTXt chunk (it must be 0)"; + case 73: + return "invalid tIME chunk size"; + case 74: + return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: + return "no null termination char found while decoding text chunk"; + case 76: + return "iTXt chunk too short to contain required bytes"; + case 77: + return "integer overflow in buffer size"; + case 78: + return "failed to open file for reading"; /*file doesn't exist or couldn't + be opened for reading*/ + case 79: + return "failed to open file for writing"; + case 80: + return "tried creating a tree of 0 symbols"; + case 81: + return "lazy matching at pos 0 is impossible"; + case 82: + return "color conversion to palette requested while a color isn't in " + "palette, or index out of bounds"; + case 83: + return "memory allocation failed"; + case 84: + return "given image too small to contain all pixels to be encoded"; + case 86: + return "impossible offset in lz77 encoding (internal bug)"; + case 87: + return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB " + "is not defined"; + case 88: + return "invalid filter strategy given for " + "LodePNGEncoderSettings.filter_strategy"; + case 89: + return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead + * of %) makes encoding 12% faster.*/ + case 90: + return "windowsize must be a power of two"; + case 91: + return "invalid decompressed idat size"; + case 92: + return "integer overflow due to too many pixels"; + case 93: + return "zero width or height is invalid"; + case 94: + return "header chunk must have a size of 13 bytes"; + case 95: + return "integer overflow with combined idat chunk size"; + case 96: + return "invalid gAMA chunk size"; + case 97: + return "invalid cHRM chunk size"; + case 98: + return "invalid sRGB chunk size"; + case 99: + return "invalid sRGB rendering intent"; + case 100: + return "invalid ICC profile color type, the PNG specification only allows " + "RGB or GRAY"; + case 101: + return "PNG specification does not allow RGB ICC profile on gray color " + "types and vice versa"; + case 102: + return "not allowed to set grayscale ICC profile with colored pixels by " + "PNG specification"; + case 103: + return "invalid palette index in bKGD chunk. Maybe it came before PLTE " + "chunk?"; + case 104: + return "invalid bKGD color while encoding (e.g. palette index out of " + "range)"; + case 105: + return "integer overflow of bitsize"; + case 106: + return "PNG file must have PLTE chunk if color type is palette"; + case 107: + return "color convert from palette mode requested without setting the " + "palette data in it"; + case 108: + return "tried to add more than 256 values to a palette"; + /*this limit can be configured in LodePNGDecompressSettings*/ + case 109: + return "tried to decompress zlib or deflate data larger than desired " + "max_output_size"; + case 110: + return "custom zlib or inflate decompression failed"; + case 111: + return "custom zlib or deflate compression failed"; + /*max text size limit can be configured in LodePNGDecoderSettings. This error + prevents unreasonable memory consumption when decoding due to impossibly large + text sizes.*/ + case 112: + return "compressed text unreasonably large"; + /*max ICC size limit can be configured in LodePNGDecoderSettings. This error + prevents unreasonable memory consumption when decoding due to impossibly large + ICC profile*/ + case 113: + return "ICC profile unreasonably large"; } return "unknown error code"; } @@ -6273,87 +7532,94 @@ const char* lodepng_error_text(unsigned code) { namespace lodepng { #ifdef LODEPNG_COMPILE_DISK -unsigned load_file(std::vector& buffer, const std::string& filename) { +unsigned load_file(std::vector &buffer, + const std::string &filename) { long size = lodepng_filesize(filename.c_str()); - if(size < 0) return 78; + if (size < 0) + return 78; buffer.resize((size_t)size); - return size == 0 ? 0 : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str()); + return size == 0 + ? 0 + : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str()); } -/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ -unsigned save_file(const std::vector& buffer, const std::string& filename) { - return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str()); +/*write given buffer to the file, overwriting the file, it doesn't append to + * it.*/ +unsigned save_file(const std::vector &buffer, + const std::string &filename) { + return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), + filename.c_str()); } #endif /* LODEPNG_COMPILE_DISK */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER -unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGDecompressSettings& settings) { - unsigned char* buffer = 0; +unsigned decompress(std::vector &out, const unsigned char *in, + size_t insize, const LodePNGDecompressSettings &settings) { + unsigned char *buffer = 0; size_t buffersize = 0; - unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings); - if(buffer) { + unsigned error = + zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings); + if (buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } -unsigned decompress(std::vector& out, const std::vector& in, - const LodePNGDecompressSettings& settings) { +unsigned decompress(std::vector &out, + const std::vector &in, + const LodePNGDecompressSettings &settings) { return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); } #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER -unsigned compress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGCompressSettings& settings) { - unsigned char* buffer = 0; +unsigned compress(std::vector &out, const unsigned char *in, + size_t insize, const LodePNGCompressSettings &settings) { + unsigned char *buffer = 0; size_t buffersize = 0; unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); - if(buffer) { + if (buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } -unsigned compress(std::vector& out, const std::vector& in, - const LodePNGCompressSettings& settings) { +unsigned compress(std::vector &out, + const std::vector &in, + const LodePNGCompressSettings &settings) { return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); } #endif /* LODEPNG_COMPILE_ENCODER */ #endif /* LODEPNG_COMPILE_ZLIB */ - #ifdef LODEPNG_COMPILE_PNG -State::State() { - lodepng_state_init(this); -} +State::State() { lodepng_state_init(this); } -State::State(const State& other) { +State::State(const State &other) { lodepng_state_init(this); lodepng_state_copy(this, &other); } -State::~State() { - lodepng_state_cleanup(this); -} +State::~State() { lodepng_state_cleanup(this); } -State& State::operator=(const State& other) { +State &State::operator=(const State &other) { lodepng_state_copy(this, &other); return *this; } #ifdef LODEPNG_COMPILE_DECODER -unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, - size_t insize, LodePNGColorType colortype, unsigned bitdepth) { - unsigned char* buffer = 0; - unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); - if(buffer && !error) { +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + const unsigned char *in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth) { + unsigned char *buffer = 0; + unsigned error = + lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if (buffer && !error) { State state; state.info_raw.colortype = colortype; state.info_raw.bitdepth = bitdepth; @@ -6364,17 +7630,18 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const return error; } -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) { - return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + const std::vector &in, + LodePNGColorType colortype, unsigned bitdepth) { + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), + colortype, bitdepth); } -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const unsigned char* in, size_t insize) { - unsigned char* buffer = NULL; +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + State &state, const unsigned char *in, size_t insize) { + unsigned char *buffer = NULL; unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); - if(buffer && !error) { + if (buffer && !error) { size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); out.insert(out.end(), &buffer[0], &buffer[buffersize]); } @@ -6382,79 +7649,85 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, return error; } -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const std::vector& in) { +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + State &state, const std::vector &in) { return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); } #ifdef LODEPNG_COMPILE_DISK -unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, - LodePNGColorType colortype, unsigned bitdepth) { +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + const std::string &filename, LodePNGColorType colortype, + unsigned bitdepth) { std::vector buffer; /* safe output values in case error happens */ w = h = 0; unsigned error = load_file(buffer, filename); - if(error) return error; + if (error) + return error; return decode(out, w, h, buffer, colortype, bitdepth); } #endif /* LODEPNG_COMPILE_DECODER */ #endif /* LODEPNG_COMPILE_DISK */ #ifdef LODEPNG_COMPILE_ENCODER -unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) { - unsigned char* buffer; +unsigned encode(std::vector &out, const unsigned char *in, + unsigned w, unsigned h, LodePNGColorType colortype, + unsigned bitdepth) { + unsigned char *buffer; size_t buffersize; - unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); - if(buffer) { + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, + colortype, bitdepth); + if (buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, +unsigned encode(std::vector &out, + const std::vector &in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { - if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + if (lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) + return 84; return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); } -unsigned encode(std::vector& out, - const unsigned char* in, unsigned w, unsigned h, - State& state) { - unsigned char* buffer; +unsigned encode(std::vector &out, const unsigned char *in, + unsigned w, unsigned h, State &state) { + unsigned char *buffer; size_t buffersize; unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); - if(buffer) { + if (buffer) { out.insert(out.end(), &buffer[0], &buffer[buffersize]); lodepng_free(buffer); } return error; } -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, - State& state) { - if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; +unsigned encode(std::vector &out, + const std::vector &in, unsigned w, unsigned h, + State &state) { + if (lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) + return 84; return encode(out, in.empty() ? 0 : &in[0], w, h, state); } #ifdef LODEPNG_COMPILE_DISK -unsigned encode(const std::string& filename, - const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth) { +unsigned encode(const std::string &filename, const unsigned char *in, + unsigned w, unsigned h, LodePNGColorType colortype, + unsigned bitdepth) { std::vector buffer; unsigned error = encode(buffer, in, w, h, colortype, bitdepth); - if(!error) error = save_file(buffer, filename); + if (!error) + error = save_file(buffer, filename); return error; } -unsigned encode(const std::string& filename, - const std::vector& in, unsigned w, unsigned h, +unsigned encode(const std::string &filename, + const std::vector &in, unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { - if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + if (lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) + return 84; return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); } #endif /* LODEPNG_COMPILE_DISK */ diff --git a/include/rd7.hpp b/include/rd7.hpp index 412ef0c..4f0f898 100644 --- a/include/rd7.hpp +++ b/include/rd7.hpp @@ -1,5 +1,5 @@ #pragma once +#include #include -#include -#include \ No newline at end of file +#include \ No newline at end of file diff --git a/include/renderd7/Color.hpp b/include/renderd7/Color.hpp index 79d51c0..0615223 100644 --- a/include/renderd7/Color.hpp +++ b/include/renderd7/Color.hpp @@ -26,6 +26,6 @@ public: uint8_t m_r, m_g, m_b, m_a; }; std::string RGB2Hex(int r, int g, int b); -uint32_t Hex(const std::string color, uint8_t a = 255); +uint32_t Hex(const std::string &color, uint8_t a = 255); } // namespace Color } // namespace RenderD7 \ No newline at end of file diff --git a/include/renderd7/ResultDecoder.hpp b/include/renderd7/ResultDecoder.hpp index dec2861..3b3cd04 100644 --- a/include/renderd7/ResultDecoder.hpp +++ b/include/renderd7/ResultDecoder.hpp @@ -1,27 +1,25 @@ #pragma once -#include #include <3ds.h> +#include -namespace RenderD7 -{ - class ResultDecoder - { - public: - ResultDecoder(){} - ~ResultDecoder(){} - void Load(Result rescode); - void Load(std::string rescode); - std::string GetCode(); - std::string GetLevel(); - int GetLevelInt(); - std::string GetModule(); - int GetModuleInt(); - std::string GetDescription(); - int GetDescriptionInt(); - std::string GetSummary(); - int GetSummaryInt(); +namespace RenderD7 { +class ResultDecoder { +public: + ResultDecoder() {} + ~ResultDecoder() {} + void Load(Result rescode); + void Load(std::string rescode); + std::string GetCode(); + std::string GetLevel(); + int GetLevelInt(); + std::string GetModule(); + int GetModuleInt(); + std::string GetDescription(); + int GetDescriptionInt(); + std::string GetSummary(); + int GetSummaryInt(); - private: - Result m_rescode; - }; -} \ No newline at end of file +private: + Result m_rescode; +}; +} // namespace RenderD7 \ No newline at end of file diff --git a/include/renderd7/StealConsole.hpp b/include/renderd7/StealConsole.hpp index 51d4923..a14a869 100644 --- a/include/renderd7/StealConsole.hpp +++ b/include/renderd7/StealConsole.hpp @@ -2,7 +2,6 @@ #include #include - namespace RenderD7 { class StealConsole { public: diff --git a/include/renderd7/external/fs.h b/include/renderd7/external/fs.h index 517d43c..210c4ba 100644 --- a/include/renderd7/external/fs.h +++ b/include/renderd7/external/fs.h @@ -7,7 +7,8 @@ extern FS_Archive archive, sdmc_archive, nand_archive; Result FS_OpenArchive(FS_Archive *archive, FS_ArchiveID id); Result FS_CloseArchive(FS_Archive archive); Result FS_OpenDir(Handle *handle, FS_Archive archive, const char *path); -Result FS_OpenFile(Handle *handle, FS_Archive archive, const char *path, u32 flags, u32 attributes); +Result FS_OpenFile(Handle *handle, FS_Archive archive, const char *path, + u32 flags, u32 attributes); Result FS_MakeDir(FS_Archive archive, const char *path); Result FS_CreateFile(FS_Archive archive, const char *path, u64 size); Result FS_RecursiveMakeDir(FS_Archive archive, const char *path); @@ -20,10 +21,13 @@ u64 FS_GetUsedStorage(FS_SystemMediaType media_type); Result FS_RemoveFile(FS_Archive archive, const char *path); Result FS_RemoveDir(FS_Archive archive, const char *path); Result FS_RemoveDirRecursive(FS_Archive archive, const char *path); -Result FS_RenameFile(FS_Archive archive, const char *old_filename, const char *new_filename); -Result FS_RenameDir(FS_Archive archive, const char *old_dirname, const char *new_dirname); +Result FS_RenameFile(FS_Archive archive, const char *old_filename, + const char *new_filename); +Result FS_RenameDir(FS_Archive archive, const char *old_dirname, + const char *new_dirname); Result FS_Read(FS_Archive archive, const char *path, u64 size, void *buf); -Result FS_Write(FS_Archive archive, const char *path, const void *buf, u32 size); +Result FS_Write(FS_Archive archive, const char *path, const void *buf, + u32 size); char *FS_GetFileTimestamp(const char *path); -Result makeDirs(const char * path); -Result openFile(Handle* fileHandle, const char * path, bool write); +Result makeDirs(const char *path); +Result openFile(Handle *fileHandle, const char *path, bool write); diff --git a/include/renderd7/external/libnsbmp/libnsbmp.h b/include/renderd7/external/libnsbmp/libnsbmp.h index 7e90b4a..8f47daf 100644 --- a/include/renderd7/external/libnsbmp/libnsbmp.h +++ b/include/renderd7/external/libnsbmp/libnsbmp.h @@ -16,129 +16,130 @@ #define libnsbmp_h_ #include -#include #include +#include /* bmp flags */ -#define BMP_NEW 0 +#define BMP_NEW 0 /** image is opaque (as opposed to having an alpha mask) */ -#define BMP_OPAQUE (1 << 0) +#define BMP_OPAQUE (1 << 0) /** memory should be wiped */ -#define BMP_CLEAR_MEMORY (1 << 1) +#define BMP_CLEAR_MEMORY (1 << 1) /** * error return values */ typedef enum { - BMP_OK = 0, - BMP_INSUFFICIENT_MEMORY = 1, - BMP_INSUFFICIENT_DATA = 2, - BMP_DATA_ERROR = 3 + BMP_OK = 0, + BMP_INSUFFICIENT_MEMORY = 1, + BMP_INSUFFICIENT_DATA = 2, + BMP_DATA_ERROR = 3 } bmp_result; /** * encoding types */ typedef enum { - BMP_ENCODING_RGB = 0, - BMP_ENCODING_RLE8 = 1, - BMP_ENCODING_RLE4 = 2, - BMP_ENCODING_BITFIELDS = 3 + BMP_ENCODING_RGB = 0, + BMP_ENCODING_RLE8 = 1, + BMP_ENCODING_RLE4 = 2, + BMP_ENCODING_BITFIELDS = 3 } bmp_encoding; /* API for Bitmap callbacks */ -typedef void* (*bmp_bitmap_cb_create)(int width, int height, unsigned int state); +typedef void *(*bmp_bitmap_cb_create)(int width, int height, + unsigned int state); typedef void (*bmp_bitmap_cb_destroy)(void *bitmap); -typedef unsigned char* (*bmp_bitmap_cb_get_buffer)(void *bitmap); +typedef unsigned char *(*bmp_bitmap_cb_get_buffer)(void *bitmap); typedef size_t (*bmp_bitmap_cb_get_bpp)(void *bitmap); /** * The Bitmap callbacks function table */ typedef struct bmp_bitmap_callback_vt_s { - /** Callback to allocate bitmap storage. */ - bmp_bitmap_cb_create bitmap_create; - /** Called to free bitmap storage. */ - bmp_bitmap_cb_destroy bitmap_destroy; - /** Return a pointer to the pixel data in a bitmap. */ - bmp_bitmap_cb_get_buffer bitmap_get_buffer; - /** Find the width of a pixel row in bytes. */ - bmp_bitmap_cb_get_bpp bitmap_get_bpp; + /** Callback to allocate bitmap storage. */ + bmp_bitmap_cb_create bitmap_create; + /** Called to free bitmap storage. */ + bmp_bitmap_cb_destroy bitmap_destroy; + /** Return a pointer to the pixel data in a bitmap. */ + bmp_bitmap_cb_get_buffer bitmap_get_buffer; + /** Find the width of a pixel row in bytes. */ + bmp_bitmap_cb_get_bpp bitmap_get_bpp; } bmp_bitmap_callback_vt; /** * bitmap image */ typedef struct bmp_image { - /** callbacks for bitmap functions */ - bmp_bitmap_callback_vt bitmap_callbacks; - /** pointer to BMP data */ - uint8_t *bmp_data; - /** width of BMP (valid after _analyse) */ - uint32_t width; - /** heigth of BMP (valid after _analyse) */ - uint32_t height; - /** whether the image has been decoded */ - bool decoded; - /** decoded image */ - void *bitmap; + /** callbacks for bitmap functions */ + bmp_bitmap_callback_vt bitmap_callbacks; + /** pointer to BMP data */ + uint8_t *bmp_data; + /** width of BMP (valid after _analyse) */ + uint32_t width; + /** heigth of BMP (valid after _analyse) */ + uint32_t height; + /** whether the image has been decoded */ + bool decoded; + /** decoded image */ + void *bitmap; - /* Internal members are listed below */ - /** total number of bytes of BMP data available */ - uint32_t buffer_size; - /** pixel encoding type */ - bmp_encoding encoding; - /** offset of bitmap data */ - uint32_t bitmap_offset; - /** bits per pixel */ - uint16_t bpp; - /** number of colours */ - uint32_t colours; - /** colour table */ - uint32_t *colour_table; - /** whether to use bmp's limited transparency */ - bool limited_trans; - /** colour to display for "transparent" pixels when using limited - * transparency - */ - uint32_t trans_colour; - /** scanlines are top to bottom */ - bool reversed; - /** image is part of an ICO, mask follows */ - bool ico; - /** true if the bitmap does not contain an alpha channel */ - bool opaque; - /** four bitwise mask */ - uint32_t mask[4]; - /** four bitwise shifts */ - int32_t shift[4]; - /** colour representing "transparency" in the bitmap */ - uint32_t transparent_index; + /* Internal members are listed below */ + /** total number of bytes of BMP data available */ + uint32_t buffer_size; + /** pixel encoding type */ + bmp_encoding encoding; + /** offset of bitmap data */ + uint32_t bitmap_offset; + /** bits per pixel */ + uint16_t bpp; + /** number of colours */ + uint32_t colours; + /** colour table */ + uint32_t *colour_table; + /** whether to use bmp's limited transparency */ + bool limited_trans; + /** colour to display for "transparent" pixels when using limited + * transparency + */ + uint32_t trans_colour; + /** scanlines are top to bottom */ + bool reversed; + /** image is part of an ICO, mask follows */ + bool ico; + /** true if the bitmap does not contain an alpha channel */ + bool opaque; + /** four bitwise mask */ + uint32_t mask[4]; + /** four bitwise shifts */ + int32_t shift[4]; + /** colour representing "transparency" in the bitmap */ + uint32_t transparent_index; } bmp_image; typedef struct ico_image { - bmp_image bmp; - struct ico_image *next; + bmp_image bmp; + struct ico_image *next; } ico_image; /** * icon image collection */ typedef struct ico_collection { - /** callbacks for bitmap functions */ - bmp_bitmap_callback_vt bitmap_callbacks; - /** width of largest BMP */ - uint16_t width; - /** heigth of largest BMP */ - uint16_t height; + /** callbacks for bitmap functions */ + bmp_bitmap_callback_vt bitmap_callbacks; + /** width of largest BMP */ + uint16_t width; + /** heigth of largest BMP */ + uint16_t height; - /* Internal members are listed below */ - /** pointer to ICO data */ - uint8_t *ico_data; - /** total number of bytes of ICO data available */ - uint32_t buffer_size; - /** root of linked list of images */ - ico_image *first; + /* Internal members are listed below */ + /** pointer to ICO data */ + uint8_t *ico_data; + /** total number of bytes of ICO data available */ + uint32_t buffer_size; + /** root of linked list of images */ + ico_image *first; } ico_collection; /** diff --git a/include/renderd7/external/libnsbmp/log.h b/include/renderd7/external/libnsbmp/log.h index b63f084..8732ee0 100644 --- a/include/renderd7/external/libnsbmp/log.h +++ b/include/renderd7/external/libnsbmp/log.h @@ -13,15 +13,21 @@ #define _LIBNSBMP_LOG_H_ #ifdef NDEBUG -# define LOG(x) ((void) 0) +#define LOG(x) ((void)0) #else -# ifdef __GNUC__ -# define LOG(x) do { printf x, fputc('\n', stdout)); } while (0) -# elif defined(__CC_NORCROFT) -# define LOG(x) do { printf x, fputc('\n', stdout)); } while (0) -# else -# define LOG(x) do { printf x, fputc('\n', stdout)); } while (0) -# endif +#ifdef __GNUC__ +#define LOG(x) \ + do { printf x, fputc('\n', stdout)); \ + } while (0) +#elif defined(__CC_NORCROFT) +#define LOG(x) \ + do { printf x, fputc('\n', stdout)); \ + } while (0) +#else +#define LOG(x) \ + do { printf x, fputc('\n', stdout)); \ + } while (0) +#endif #endif #endif diff --git a/include/renderd7/external/lodepng.h b/include/renderd7/external/lodepng.h index 6801cb7..a567767 100644 --- a/include/renderd7/external/lodepng.h +++ b/include/renderd7/external/lodepng.h @@ -28,7 +28,7 @@ freely, subject to the following restrictions: #include /*for size_t*/ -extern const char* LODEPNG_VERSION_STRING; +extern const char *LODEPNG_VERSION_STRING; /* The following #defines are used to create code sections. They can be disabled @@ -65,7 +65,8 @@ the custom_zlib field of the compress and decompress settings*/ #define LODEPNG_COMPILE_DISK #endif -/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and + * unknown chunks*/ #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS #define LODEPNG_COMPILE_ANCILLARY_CHUNKS #endif @@ -75,14 +76,15 @@ the custom_zlib field of the compress and decompress settings*/ #define LODEPNG_COMPILE_ERROR_TEXT #endif -/*Compile the default allocators (C's free, malloc and realloc). If you disable this, -you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your -source files with custom allocators.*/ +/*Compile the default allocators (C's free, malloc and realloc). If you disable +this, you can define the functions lodepng_free, lodepng_malloc and +lodepng_realloc in your source files with custom allocators.*/ #ifndef LODEPNG_NO_COMPILE_ALLOCATORS #define LODEPNG_COMPILE_ALLOCATORS #endif -/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +/*compile the C++ version (you can disable the C++ wrapper here even when + * compiling for C++)*/ #ifdef __cplusplus #ifndef LODEPNG_NO_COMPILE_CPP #define LODEPNG_COMPILE_CPP @@ -90,23 +92,24 @@ source files with custom allocators.*/ #endif #ifdef LODEPNG_COMPILE_CPP -#include #include +#include #endif /*LODEPNG_COMPILE_CPP*/ #ifdef LODEPNG_COMPILE_PNG /*The PNG color types (also used for raw image).*/ typedef enum LodePNGColorType { - LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/ - LCT_RGB = 2, /*RGB: 8,16 bit*/ - LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/ - LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/ - /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid - byte value from 0 to 255 that could be present in an invalid PNG file header. Do - not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use - the valid color type names above, or numeric values like 1 or 7 when checking for - particular disallowed color type byte values, or cast to integer to print it.*/ + LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/ + /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any + invalid byte value from 0 to 255 that could be present in an invalid PNG file + header. Do not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead + either use the valid color type names above, or numeric values like 1 or 7 + when checking for particular disallowed color type byte values, or cast to + integer to print it.*/ LCT_MAX_OCTET_VALUE = 255 } LodePNGColorType; @@ -122,42 +125,42 @@ w: Output parameter. Pointer to width of pixel data. h: Output parameter. Pointer to height of pixel data. in: Memory buffer with the PNG file. insize: size of the in buffer. -colortype: the desired color type for the raw output image. See explanation on PNG color types. -bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. -Return value: LodePNG error code (0 means no error). +colortype: the desired color type for the raw output image. See explanation on +PNG color types. bitdepth: the desired bit depth for the raw output image. See +explanation on PNG color types. Return value: LodePNG error code (0 means no +error). */ -unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, - const unsigned char* in, size_t insize, +unsigned lodepng_decode_memory(unsigned char **out, unsigned *w, unsigned *h, + const unsigned char *in, size_t insize, LodePNGColorType colortype, unsigned bitdepth); /*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ -unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, - const unsigned char* in, size_t insize); +unsigned lodepng_decode32(unsigned char **out, unsigned *w, unsigned *h, + const unsigned char *in, size_t insize); /*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ -unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, - const unsigned char* in, size_t insize); +unsigned lodepng_decode24(unsigned char **out, unsigned *w, unsigned *h, + const unsigned char *in, size_t insize); #ifdef LODEPNG_COMPILE_DISK /* Load PNG from disk, from file with given name. Same as the other decode functions, but instead takes a filename as input. */ -unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, - const char* filename, - LodePNGColorType colortype, unsigned bitdepth); +unsigned lodepng_decode_file(unsigned char **out, unsigned *w, unsigned *h, + const char *filename, LodePNGColorType colortype, + unsigned bitdepth); /*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ -unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, - const char* filename); +unsigned lodepng_decode32_file(unsigned char **out, unsigned *w, unsigned *h, + const char *filename); /*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ -unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, - const char* filename); +unsigned lodepng_decode24_file(unsigned char **out, unsigned *w, unsigned *h, + const char *filename); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_DECODER*/ - #ifdef LODEPNG_COMPILE_ENCODER /* Converts raw pixel data into a PNG image in memory. The colortype and bitdepth @@ -168,24 +171,26 @@ out: Output parameter. Pointer to buffer that will contain the PNG image data. Must be freed after usage with free(*out). outsize: Output parameter. Pointer to the size in bytes of the out buffer. image: The raw pixel data to encode. The size of this buffer should be - w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. -w: width of the raw pixel data in pixels. -h: height of the raw pixel data in pixels. -colortype: the color type of the raw input image. See explanation on PNG color types. -bitdepth: the bit depth of the raw input image. See explanation on PNG color types. -Return value: LodePNG error code (0 means no error). + w * h * (bytes per pixel), bytes per pixel depends on colortype and +bitdepth. w: width of the raw pixel data in pixels. h: height of the raw pixel +data in pixels. colortype: the color type of the raw input image. See +explanation on PNG color types. bitdepth: the bit depth of the raw input image. +See explanation on PNG color types. Return value: LodePNG error code (0 means no +error). */ -unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth); +unsigned lodepng_encode_memory(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, + unsigned h, LodePNGColorType colortype, + unsigned bitdepth); -/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ -unsigned lodepng_encode32(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h); +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw + * image.*/ +unsigned lodepng_encode32(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, unsigned h); /*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ -unsigned lodepng_encode24(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h); +unsigned lodepng_encode24(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DISK /* @@ -193,39 +198,38 @@ Converts raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! */ -unsigned lodepng_encode_file(const char* filename, - const unsigned char* image, unsigned w, unsigned h, - LodePNGColorType colortype, unsigned bitdepth); +unsigned lodepng_encode_file(const char *filename, const unsigned char *image, + unsigned w, unsigned h, LodePNGColorType colortype, + unsigned bitdepth); /*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ -unsigned lodepng_encode32_file(const char* filename, - const unsigned char* image, unsigned w, unsigned h); +unsigned lodepng_encode32_file(const char *filename, const unsigned char *image, + unsigned w, unsigned h); /*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ -unsigned lodepng_encode24_file(const char* filename, - const unsigned char* image, unsigned w, unsigned h); +unsigned lodepng_encode24_file(const char *filename, const unsigned char *image, + unsigned w, unsigned h); #endif /*LODEPNG_COMPILE_DISK*/ #endif /*LODEPNG_COMPILE_ENCODER*/ - #ifdef LODEPNG_COMPILE_CPP namespace lodepng { #ifdef LODEPNG_COMPILE_DECODER /*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const unsigned char* in, size_t insize, +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + const unsigned char *in, size_t insize, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const std::vector& in, +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + const std::vector &in, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* Converts PNG file from disk to raw pixel data in memory. Same as the other decode functions, but instead takes a filename as input. */ -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - const std::string& filename, +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + const std::string &filename, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_DECODER */ @@ -233,11 +237,11 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, #ifdef LODEPNG_COMPILE_ENCODER /*Same as lodepng_encode_memory, but encodes to an std::vector. colortype is that of the raw input data. The output PNG color type will be auto chosen.*/ -unsigned encode(std::vector& out, - const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, +unsigned encode(std::vector &out, const unsigned char *in, + unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, + unsigned bitdepth = 8); +unsigned encode(std::vector &out, + const std::vector &in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #ifdef LODEPNG_COMPILE_DISK /* @@ -245,11 +249,11 @@ Converts 32-bit RGBA raw pixel data into a PNG file on disk. Same as the other encode functions, but instead takes a filename as output. NOTE: This overwrites existing files without warning! */ -unsigned encode(const std::string& filename, - const unsigned char* in, unsigned w, unsigned h, - LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -unsigned encode(const std::string& filename, - const std::vector& in, unsigned w, unsigned h, +unsigned encode(const std::string &filename, const unsigned char *in, + unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, + unsigned bitdepth = 8); +unsigned encode(const std::string &filename, + const std::vector &in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_ENCODER */ @@ -259,41 +263,44 @@ unsigned encode(const std::string& filename, #ifdef LODEPNG_COMPILE_ERROR_TEXT /*Returns an English description of the numerical error code.*/ -const char* lodepng_error_text(unsigned code); +const char *lodepng_error_text(unsigned code); #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ #ifdef LODEPNG_COMPILE_DECODER /*Settings for zlib decompression*/ typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; struct LodePNGDecompressSettings { - /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */ - unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ - unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ + /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc + */ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if + the Adler32 checksum is corrupted*/ + unsigned + ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ - /*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding, - return an error, output a data size > max_output_size and all the data up to that point. This is - not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is - ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones. - Set to 0 to impose no limit (the default).*/ + /*Maximum decompressed size, beyond this the decoder may (and is encouraged + to) stop decoding, return an error, output a data size > max_output_size and + all the data up to that point. This is not hard limit nor a guarantee, but can + prevent excessive memory usage. This setting is ignored by the PNG decoder, + but is used by the deflate/zlib decoder and can be used by custom ones. Set to + 0 to impose no limit (the default).*/ size_t max_output_size; /*use custom zlib decoder instead of built in one (default: null). Should return 0 if success, any non-0 if error (numeric value not exposed).*/ - unsigned (*custom_zlib)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGDecompressSettings*); + unsigned (*custom_zlib)(unsigned char **, size_t *, const unsigned char *, + size_t, const LodePNGDecompressSettings *); /*use custom deflate decoder instead of built in one (default: null) - if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate). - Should return 0 if success, any non-0 if error (numeric value not exposed).*/ - unsigned (*custom_inflate)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGDecompressSettings*); + if custom_zlib is not null, custom_inflate is ignored (the zlib format uses + deflate). Should return 0 if success, any non-0 if error (numeric value not + exposed).*/ + unsigned (*custom_inflate)(unsigned char **, size_t *, const unsigned char *, + size_t, const LodePNGDecompressSettings *); - const void* custom_context; /*optional custom settings for custom functions*/ + const void *custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGDecompressSettings lodepng_default_decompress_settings; -void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +void lodepng_decompress_settings_init(LodePNGDecompressSettings *settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER @@ -304,29 +311,33 @@ between speed and compression ratio. typedef struct LodePNGCompressSettings LodePNGCompressSettings; struct LodePNGCompressSettings /*deflate = compress*/ { /*LZ77 related settings*/ - unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ - unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ - unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ - unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ - unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ - unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). + Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper + compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more + but is slower. Default value: 2048.*/ + unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better + for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for + best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit + slower. Default: true*/ /*use custom zlib encoder instead of built in one (default: null)*/ - unsigned (*custom_zlib)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGCompressSettings*); + unsigned (*custom_zlib)(unsigned char **, size_t *, const unsigned char *, + size_t, const LodePNGCompressSettings *); /*use custom deflate encoder instead of built in one (default: null) if custom_zlib is used, custom_deflate is ignored since only the built in zlib function will call custom_deflate*/ - unsigned (*custom_deflate)(unsigned char**, size_t*, - const unsigned char*, size_t, - const LodePNGCompressSettings*); + unsigned (*custom_deflate)(unsigned char **, size_t *, const unsigned char *, + size_t, const LodePNGCompressSettings *); - const void* custom_context; /*optional custom settings for custom functions*/ + const void *custom_context; /*optional custom settings for custom functions*/ }; extern const LodePNGCompressSettings lodepng_default_compress_settings; -void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +void lodepng_compress_settings_init(LodePNGCompressSettings *settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_PNG @@ -337,8 +348,10 @@ format, and is used both for PNG and raw image data in LodePNG. */ typedef struct LodePNGColorMode { /*header (IHDR)*/ - LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ - unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation + further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation + further in this header file*/ /* palette (PLTE and tRNS) @@ -355,112 +368,128 @@ typedef struct LodePNGColorMode { The palette is only supported for color type 3. */ - unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/ - size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/ + unsigned char *palette; /*palette in RGBARGBA... order. Must be either 0, or + when allocated must have 1024 bytes*/ + size_t palettesize; /*palette size in number of colors (amount of used bytes + is 4 * palettesize)*/ /* transparent color key (tRNS) - This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. - For grayscale PNGs, r, g and b will all 3 be set to the same. + This color uses the same bit depth as the bitdepth value in this struct, which + can be 1-bit to 16-bit. For grayscale PNGs, r, g and b will all 3 be set to + the same. When decoding, by default you can ignore this information, since LodePNG sets pixels with this key to transparent already in the raw RGBA output. The color key is only supported for color types 0 and 2. */ - unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ - unsigned key_r; /*red/grayscale component of color key*/ - unsigned key_g; /*green component of color key*/ - unsigned key_b; /*blue component of color key*/ + unsigned + key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/grayscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ } LodePNGColorMode; /*init, cleanup and copy functions to use with this struct*/ -void lodepng_color_mode_init(LodePNGColorMode* info); -void lodepng_color_mode_cleanup(LodePNGColorMode* info); +void lodepng_color_mode_init(LodePNGColorMode *info); +void lodepng_color_mode_cleanup(LodePNGColorMode *info); /*return value is error code (0 means no error)*/ -unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); +unsigned lodepng_color_mode_copy(LodePNGColorMode *dest, + const LodePNGColorMode *source); /* Makes a temporary LodePNGColorMode that does not need cleanup (no palette) */ -LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth); +LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, + unsigned bitdepth); -void lodepng_palette_clear(LodePNGColorMode* info); +void lodepng_palette_clear(LodePNGColorMode *info); /*add 1 color to the palette*/ -unsigned lodepng_palette_add(LodePNGColorMode* info, - unsigned char r, unsigned char g, unsigned char b, unsigned char a); +unsigned lodepng_palette_add(LodePNGColorMode *info, unsigned char r, + unsigned char g, unsigned char b, unsigned char a); -/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ -unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the total amount of bits per pixel, based on colortype and bitdepth in the + * struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode *info); /*get the amount of color channels used, based on colortype in the struct. If a palette is used, it counts as 1 channel.*/ -unsigned lodepng_get_channels(const LodePNGColorMode* info); +unsigned lodepng_get_channels(const LodePNGColorMode *info); /*is it a grayscale type? (only colortype 0 or 4)*/ -unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +unsigned lodepng_is_greyscale_type(const LodePNGColorMode *info); /*has it got an alpha channel? (only colortype 2 or 6)*/ -unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +unsigned lodepng_is_alpha_type(const LodePNGColorMode *info); /*has it got a palette? (only colortype 3)*/ -unsigned lodepng_is_palette_type(const LodePNGColorMode* info); -/*only returns true if there is a palette and there is a value in the palette with alpha < 255. -Loops through the palette to check this.*/ -unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +unsigned lodepng_is_palette_type(const LodePNGColorMode *info); +/*only returns true if there is a palette and there is a value in the palette +with alpha < 255. Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode *info); /* -Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. -Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). -Returns false if the image can only have opaque pixels. -In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, -or if "key_defined" is true. +Check if the given color info indicates the possibility of having non-opaque +pixels in the PNG image. Returns true if the image can have translucent or +invisible pixels (it still be opaque if it doesn't use such pixels). Returns +false if the image can only have opaque pixels. In detail, it returns true only +if it's a color type with alpha, or has a palette with non-opaque values, or if +"key_defined" is true. */ -unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); -/*Returns the byte size of a raw image buffer with given width, height and color mode*/ -size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); +unsigned lodepng_can_have_alpha(const LodePNGColorMode *info); +/*Returns the byte size of a raw image buffer with given width, height and color + * mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, + const LodePNGColorMode *color); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*The information of a Time chunk in PNG.*/ typedef struct LodePNGTime { - unsigned year; /*2 bytes used (0-65535)*/ - unsigned month; /*1-12*/ - unsigned day; /*1-31*/ - unsigned hour; /*0-23*/ - unsigned minute; /*0-59*/ - unsigned second; /*0-60 (to allow for leap seconds)*/ + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ } LodePNGTime; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /*Information about the PNG image, except pixels, width and height.*/ typedef struct LodePNGInfo { /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ - unsigned compression_method;/*compression method of the original file. Always 0.*/ - unsigned filter_method; /*filter method of the original file*/ - unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/ - LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + unsigned + compression_method; /*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file: 0=none, + 1=Adam7*/ + LodePNGColorMode + color; /*color type and bits, palette and transparency of the PNG file*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /* Suggested background color chunk (bKGD) - This uses the same color mode and bit depth as the PNG (except no alpha channel), - with values truncated to the bit depth in the unsigned integer. + This uses the same color mode and bit depth as the PNG (except no alpha + channel), with values truncated to the bit depth in the unsigned integer. - For grayscale and palette PNGs, the value is stored in background_r. The values - in background_g and background_b are then unused. + For grayscale and palette PNGs, the value is stored in background_r. The + values in background_g and background_b are then unused. - So when decoding, you may get these in a different color mode than the one you requested - for the raw pixels. + So when decoding, you may get these in a different color mode than the one you + requested for the raw pixels. - When encoding with auto_convert, you must use the color model defined in info_png.color for - these values. The encoder normally ignores info_png.color when auto_convert is on, but will - use it to interpret these values (and convert copies of them to its chosen color model). + When encoding with auto_convert, you must use the color model defined in + info_png.color for these values. The encoder normally ignores info_png.color + when auto_convert is on, but will use it to interpret these values (and + convert copies of them to its chosen color model). - When encoding, avoid setting this to an expensive color, such as a non-gray value - when the image is gray, or the compression will be worse since it will be forced to - write the PNG with a more expensive color mode (when auto_convert is on). + When encoding, avoid setting this to an expensive color, such as a non-gray + value when the image is gray, or the compression will be worse since it will + be forced to write the PNG with a more expensive color mode (when auto_convert + is on). - The decoder does not use this background color to edit the color of pixels. This is a - completely optional metadata feature. + The decoder does not use this background color to edit the color of pixels. + This is a completely optional metadata feature. */ unsigned background_defined; /*is a suggested background color given?*/ - unsigned background_r; /*red/gray/palette component of suggested background color*/ - unsigned background_g; /*green component of suggested background color*/ - unsigned background_b; /*blue component of suggested background color*/ + unsigned + background_r; /*red/gray/palette component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ /* Non-international text chunks (tEXt and zTXt) @@ -469,9 +498,10 @@ typedef struct LodePNGInfo { text_strings, while text_keys are keywords that give a short description what the actual text represents, e.g. Title, Author, Description, or anything else. - All the string fields below including strings, keys, names and language tags are null terminated. - The PNG specification uses null characters for the keys, names and tags, and forbids null - characters to appear in the main text which is why we can use null termination everywhere here. + All the string fields below including strings, keys, names and language tags + are null terminated. The PNG specification uses null characters for the keys, + names and tags, and forbids null characters to appear in the main text which + is why we can use null termination everywhere here. A keyword is minimum 1 character and maximum 79 characters long (plus the additional null terminator). It's discouraged to use a single line length @@ -482,9 +512,10 @@ typedef struct LodePNGInfo { Standard text chunk keywords and strings are encoded using Latin-1. */ - size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ - char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ - char** text_strings; /*the actual text*/ + size_t text_num; /*the amount of texts in these char** buffers (there may be + more texts in itext)*/ + char **text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char **text_strings; /*the actual text*/ /* International text chunks (iTXt) @@ -494,38 +525,45 @@ typedef struct LodePNGInfo { keys must be 1-79 characters (plus the additional null terminator), the other strings are any length. */ - size_t itext_num; /*the amount of international texts in this PNG*/ - char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ - char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ - char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ - char** itext_strings; /*the actual international text - UTF-8 string*/ + size_t itext_num; /*the amount of international texts in this PNG*/ + char **itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char **itext_langtags; /*language tag for this text's language, ISO/IEC 646 + string, e.g. ISO 639 language tag*/ + char **itext_transkeys; /*keyword translated to the international language - + UTF-8 string*/ + char **itext_strings; /*the actual international text - UTF-8 string*/ /*time chunk (tIME)*/ unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ LodePNGTime time; /*phys chunk (pHYs)*/ - unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ - unsigned phys_x; /*pixels per unit in x direction*/ - unsigned phys_y; /*pixels per unit in y direction*/ - unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are + undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ /* Color profile related chunks: gAMA, cHRM, sRGB, iCPP - LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color - profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please + LodePNG does not apply any color conversions on pixels in the encoder or + decoder and does not interpret these color profile values. It merely passes on + the information. If you wish to use color profiles and convert colors, please use these values with a color management library. - See the PNG, ICC and sRGB specifications for more information about the meaning of these values. + See the PNG, ICC and sRGB specifications for more information about the + meaning of these values. */ /* gAMA chunk: optional, overridden by sRGB or iCCP if those are present. */ - unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 = present). */ + unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 + = present). */ unsigned gama_gamma; /* Gamma exponent times 100000 */ /* cHRM chunk: optional, overridden by sRGB or iCCP if those are present. */ - unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 = present). */ + unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 + = present). */ unsigned chrm_white_x; /* White Point x times 100000 */ unsigned chrm_white_y; /* White Point y times 100000 */ unsigned chrm_red_x; /* Red x times 100000 */ @@ -538,100 +576,121 @@ typedef struct LodePNGInfo { /* sRGB chunk: optional. May not appear at the same time as iCCP. If gAMA is also present gAMA must contain value 45455. - If cHRM is also present cHRM must contain respectively 31270,32900,64000,33000,30000,60000,15000,6000. + If cHRM is also present cHRM must contain respectively + 31270,32900,64000,33000,30000,60000,15000,6000. */ - unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 = present). */ - unsigned srgb_intent; /* Rendering intent: 0=perceptual, 1=rel. colorimetric, 2=saturation, 3=abs. colorimetric */ + unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 + = present). */ + unsigned srgb_intent; /* Rendering intent: 0=perceptual, 1=rel. colorimetric, + 2=saturation, 3=abs. colorimetric */ /* iCCP chunk: optional. May not appear at the same time as sRGB. - LodePNG does not parse or use the ICC profile (except its color space header field for an edge case), a - separate library to handle the ICC data (not included in LodePNG) format is needed to use it for color - management and conversions. + LodePNG does not parse or use the ICC profile (except its color space header + field for an edge case), a separate library to handle the ICC data (not + included in LodePNG) format is needed to use it for color management and + conversions. - For encoding, if iCCP is present, gAMA and cHRM are recommended to be added as well with values that match the ICC - profile as closely as possible, if you wish to do this you should provide the correct values for gAMA and cHRM and - enable their '_defined' flags since LodePNG will not automatically compute them from the ICC profile. + For encoding, if iCCP is present, gAMA and cHRM are recommended to be added as + well with values that match the ICC profile as closely as possible, if you + wish to do this you should provide the correct values for gAMA and cHRM and + enable their '_defined' flags since LodePNG will not automatically compute + them from the ICC profile. - For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-gray - PNG color types and a "GRAY" profile for gray PNG color types. If you disable auto_convert, you must ensure - the ICC profile type matches your requested color type, else the encoder gives an error. If auto_convert is - enabled (the default), and the ICC profile is not a good match for the pixel data, this will result in an encoder - error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of the pixel - data if the pixels could be encoded as grayscale but the ICC profile is RGB. + For encoding, the ICC profile is required by the PNG specification to be an + "RGB" profile for non-gray PNG color types and a "GRAY" profile for gray PNG + color types. If you disable auto_convert, you must ensure the ICC profile type + matches your requested color type, else the encoder gives an error. If + auto_convert is enabled (the default), and the ICC profile is not a good match + for the pixel data, this will result in an encoder error if the pixel data has + non-gray pixels for a GRAY profile, or a silent less-optimal compression of + the pixel data if the pixels could be encoded as grayscale but the ICC profile + is RGB. - To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so - make sure you compute it carefully to avoid the above problems. + To avoid this do not set an ICC profile in the image unless there is a good + reason for it, and when doing so make sure you compute it carefully to avoid + the above problems. */ - unsigned iccp_defined; /* Whether an iCCP chunk is present (0 = not present, 1 = present). */ - char* iccp_name; /* Null terminated string with profile name, 1-79 bytes */ + unsigned iccp_defined; /* Whether an iCCP chunk is present (0 = not present, 1 + = present). */ + char *iccp_name; /* Null terminated string with profile name, 1-79 bytes */ /* The ICC profile in iccp_profile_size bytes. Don't allocate this buffer yourself. Use the init/cleanup functions correctly and use lodepng_set_icc and lodepng_clear_icc. */ - unsigned char* iccp_profile; + unsigned char *iccp_profile; unsigned iccp_profile_size; /* The size of iccp_profile in bytes */ /* End of color profile related chunks */ - /* unknown chunks: chunks not known by LodePNG, passed on byte for byte. - There are 3 buffers, one for each position in the PNG where unknown chunks can appear. - Each buffer contains all unknown chunks for that position consecutively. - The 3 positions are: - 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. + There are 3 buffers, one for each position in the PNG where unknown chunks can + appear. Each buffer contains all unknown chunks for that position + consecutively. The 3 positions are: 0: between IHDR and PLTE, 1: between PLTE + and IDAT, 2: between IDAT and IEND. - For encoding, do not store critical chunks or known chunks that are enabled with a "_defined" flag - above in here, since the encoder will blindly follow this and could then encode an invalid PNG file - (such as one with two IHDR chunks or the disallowed combination of sRGB with iCCP). But do use - this if you wish to store an ancillary chunk that is not supported by LodePNG (such as sPLT or hIST), - or any non-standard PNG chunk. + For encoding, do not store critical chunks or known chunks that are enabled + with a "_defined" flag above in here, since the encoder will blindly follow + this and could then encode an invalid PNG file (such as one with two IHDR + chunks or the disallowed combination of sRGB with iCCP). But do use this if + you wish to store an ancillary chunk that is not supported by LodePNG (such as + sPLT or hIST), or any non-standard PNG chunk. - Do not allocate or traverse this data yourself. Use the chunk traversing functions declared - later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + Do not allocate or traverse this data yourself. Use the chunk traversing + functions declared later, such as lodepng_chunk_next and lodepng_chunk_append, + to read/write this struct. */ - unsigned char* unknown_chunks_data[3]; - size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + unsigned char *unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given + for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGInfo; /*init, cleanup and copy functions to use with this struct*/ -void lodepng_info_init(LodePNGInfo* info); -void lodepng_info_cleanup(LodePNGInfo* info); +void lodepng_info_init(LodePNGInfo *info); +void lodepng_info_cleanup(LodePNGInfo *info); /*return value is error code (0 means no error)*/ -unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); +unsigned lodepng_info_copy(LodePNGInfo *dest, const LodePNGInfo *source); #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS -unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ -void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +unsigned lodepng_add_text(LodePNGInfo *info, const char *key, + const char *str); /*push back both texts at once*/ +void lodepng_clear_text(LodePNGInfo *info); /*use this to clear the texts again + after you filled them in*/ -unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, - const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ -void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ +unsigned +lodepng_add_itext(LodePNGInfo *info, const char *key, const char *langtag, + const char *transkey, + const char *str); /*push back the 4 texts of 1 chunk at once*/ +void lodepng_clear_itext(LodePNGInfo *info); /*use this to clear the itexts + again after you filled them in*/ /*replaces if exists*/ -unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size); -void lodepng_clear_icc(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ -#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +unsigned lodepng_set_icc(LodePNGInfo *info, const char *name, + const unsigned char *profile, unsigned profile_size); +void lodepng_clear_icc(LodePNGInfo *info); /*use this to clear the texts again + after you filled them in*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ /* Converts raw buffer from one color type to another color type, based on LodePNGColorMode structs to describe the input and output color type. -See the reference manual at the end of this header file to see which color conversions are supported. -return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) -The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel -of the output color type (lodepng_get_bpp). -For < 8 bpp images, there should not be padding bits at the end of scanlines. -For 16-bit per channel colors, uses big endian format like PNG does. -Return value is LodePNG error code +See the reference manual at the end of this header file to see which color +conversions are supported. return value = LodePNG error code (0 if all went ok, +an error if the conversion isn't supported) The out buffer must have size (w * h +* bpp + 7) / 8, where bpp is the bits per pixel of the output color type +(lodepng_get_bpp). For < 8 bpp images, there should not be padding bits at the +end of scanlines. For 16-bit per channel colors, uses big endian format like PNG +does. Return value is LodePNG error code */ -unsigned lodepng_convert(unsigned char* out, const unsigned char* in, - const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, - unsigned w, unsigned h); +unsigned lodepng_convert(unsigned char *out, const unsigned char *in, + const LodePNGColorMode *mode_out, + const LodePNGColorMode *mode_in, unsigned w, + unsigned h); #ifdef LODEPNG_COMPILE_DECODER /* @@ -639,111 +698,139 @@ Settings for the decoder. This contains settings for the PNG and the Zlib decoder, but not the Info settings from the Info structs. */ typedef struct LodePNGDecoderSettings { - LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + LodePNGDecompressSettings + zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ - /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */ - unsigned ignore_crc; /*ignore CRC checksums*/ + /* Check LodePNGDecompressSettings for more ignorable errors such as + * ignore_adler32 */ + unsigned ignore_crc; /*ignore CRC checksums*/ unsigned ignore_critical; /*ignore unknown critical chunks*/ - unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/ - /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable - errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some - strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters - in string keys, etc... */ + unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND + chunk, too large chunk, ...)*/ + /* TODO: make a system involving warnings with levels and a strict mode + instead. Other potentially recoverable errors: srgb rendering intent value, + size of content of ancillary chunks, more than 79 characters for some + strings, placement/combination rules for ancillary chunks, crc of unknown + chunks, allowed characters in string keys, etc... */ - unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + unsigned color_convert; /*whether to convert the PNG to the color type you + want. Default: yes*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS - unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, + they're stored in the unknown chunks*/ - /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, + * useful for a png editor)*/ unsigned remember_unknown_chunks; - /* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned, - unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size. - By default it is a value that prevents unreasonably large strings from hogging memory. */ + /* maximum size for decompressed text chunks. If a text chunk's text is larger + than this, an error is returned, unless reading text chunks is disabled or + this limit is set higher or disabled. Set to 0 to allow any size. By default + it is a value that prevents unreasonably large strings from hogging memory. */ size_t max_text_size; - /* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to - 0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any + /* maximum size for compressed ICC chunks. If the ICC profile is larger than + this, an error will be returned. Set to 0 to allow any size. By default this + is a value that prevents ICC profiles that would be much larger than any legitimate profile could be to hog memory. */ size_t max_icc_size; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGDecoderSettings; -void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +void lodepng_decoder_settings_init(LodePNGDecoderSettings *settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER -/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +/*automatically use color type with less bits per pixel if losslessly possible. + * Default: AUTO*/ typedef enum LodePNGFilterStrategy { /*every filter at zero*/ LFS_ZERO = 0, - /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/ + /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but + for testing*/ LFS_ONE = 1, LFS_TWO = 2, LFS_THREE = 3, LFS_FOUR = 4, - /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ + /*Use filter that gives minimum sum, as described in the official PNG filter + heuristic.*/ LFS_MINSUM, - /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending - on the image, this is better or worse than minsum.*/ + /*Use the filter type that gives smallest Shannon entropy for this scanline. + Depending on the image, this is better or worse than minsum.*/ LFS_ENTROPY, /* Brute-force-search PNG filters by compressing each filter for each scanline. Experimental, very slow, and only rarely gives better compression than MINSUM. */ LFS_BRUTE_FORCE, - /*use predefined_filters buffer: you specify the filter type for each scanline*/ + /*use predefined_filters buffer: you specify the filter type for each + scanline*/ LFS_PREDEFINED } LodePNGFilterStrategy; -/*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...), -which helps decide which color model to use for encoding. -Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +/*Gives characteristics about the integer RGBA colors of the image (count, alpha +channel usage, bit depth, ...), which helps decide which color model to use for +encoding. Used internally by default if "auto_convert" is enabled. Public +because it's useful for custom algorithms.*/ typedef struct LodePNGColorStats { unsigned colored; /*not grayscale*/ - unsigned key; /*image is not opaque and color key is possible instead of full alpha*/ - unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/ + unsigned key; /*image is not opaque and color key is possible instead of full + alpha*/ + unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte + is duplicated, e.g. 65535 means 255*/ unsigned short key_g; unsigned short key_b; - unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/ - unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/ - unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/ - unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/ + unsigned + alpha; /*image is not opaque and alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or + allow_palette is disabled.*/ + unsigned char + palette[1024]; /*Remembers up to the first 256 RGBA colors, in no + particular order, only valid when numcolors is valid*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale + only. 16 if 16-bit per channel required.*/ size_t numpixels; /*user settings for computing/using the stats*/ - unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/ - unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/ + unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype + in auto_choose_color, and don't count numcolors*/ + unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the + image only has gray colors*/ } LodePNGColorStats; -void lodepng_color_stats_init(LodePNGColorStats* stats); +void lodepng_color_stats_init(LodePNGColorStats *stats); /*Get a LodePNGColorStats of the image. The stats must already have been inited. Returns error code (e.g. alloc fail) or 0 if ok.*/ -unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, - const unsigned char* image, unsigned w, unsigned h, - const LodePNGColorMode* mode_in); +unsigned lodepng_compute_color_stats(LodePNGColorStats *stats, + const unsigned char *image, unsigned w, + unsigned h, + const LodePNGColorMode *mode_in); /*Settings for the encoder.*/ typedef struct LodePNGEncoderSettings { - LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + LodePNGCompressSettings + zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ - unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + unsigned auto_convert; /*automatically choose output PNG color type. Default: + true*/ - /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than - 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to - completely follow the official PNG heuristic, filter_palette_zero must be true and - filter_strategy must be LFS_MINSUM*/ + /*If true, follows the official PNG heuristic: if the PNG uses a palette or + lower than 8 bit depth, set all filters to zero. Otherwise use the + filter_strategy. Note that to completely follow the official PNG heuristic, + filter_palette_zero must be true and filter_strategy must be LFS_MINSUM*/ unsigned filter_palette_zero; - /*Which filter strategy to use when not using zeroes due to filter_palette_zero. - Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + /*Which filter strategy to use when not using zeroes due to + filter_palette_zero. Set filter_palette_zero to 0 to ensure always using your + chosen strategy. Default: LFS_MINSUM*/ LodePNGFilterStrategy filter_strategy; - /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with - the same length as the amount of scanlines in the image, and each value must <= 5. You - have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero - must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ - const unsigned char* predefined_filters; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to + a buffer with the same length as the amount of scanlines in the image, and + each value must <= 5. You have to cleanup this buffer, LodePNG will never free + it. Don't forget that filter_palette_zero must be set to 0 to ensure this is + also used on palette or low bitdepth images.*/ + const unsigned char *predefined_filters; /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). If colortype is 3, PLTE is _always_ created.*/ @@ -751,52 +838,53 @@ typedef struct LodePNGEncoderSettings { #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS /*add LodePNG identifier and version as a text chunk, for debugging*/ unsigned add_id; - /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use + * compression in iTXt chunks*/ unsigned text_compression; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ } LodePNGEncoderSettings; -void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +void lodepng_encoder_settings_init(LodePNGEncoderSettings *settings); #endif /*LODEPNG_COMPILE_ENCODER*/ - #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) /*The settings, state and information for extended encoding and decoding.*/ typedef struct LodePNGState { #ifdef LODEPNG_COMPILE_DECODER LodePNGDecoderSettings decoder; /*the decoding settings*/ -#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER LodePNGEncoderSettings encoder; /*the encoding settings*/ -#endif /*LODEPNG_COMPILE_ENCODER*/ - LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ - LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to + get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ unsigned error; } LodePNGState; /*init, cleanup and copy functions to use with this struct*/ -void lodepng_state_init(LodePNGState* state); -void lodepng_state_cleanup(LodePNGState* state); -void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); -#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ +void lodepng_state_init(LodePNGState *state); +void lodepng_state_cleanup(LodePNGState *state); +void lodepng_state_copy(LodePNGState *dest, const LodePNGState *source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) \ + */ #ifdef LODEPNG_COMPILE_DECODER /* -Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and -getting much more information about the PNG image and color mode. +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings +and getting much more information about the PNG image and color mode. */ -unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize); +unsigned lodepng_decode(unsigned char **out, unsigned *w, unsigned *h, + LodePNGState *state, const unsigned char *in, + size_t insize); /* Read the PNG header, but not the actual data. This returns only the information that is in the IHDR chunk of the PNG, such as width, height and color type. The information is placed in the info_png field of the LodePNGState. */ -unsigned lodepng_inspect(unsigned* w, unsigned* h, - LodePNGState* state, - const unsigned char* in, size_t insize); +unsigned lodepng_inspect(unsigned *w, unsigned *h, LodePNGState *state, + const unsigned char *in, size_t insize); #endif /*LODEPNG_COMPILE_DECODER*/ /* @@ -811,14 +899,15 @@ Requirements: &in[pos] must point to start of a chunk, must use regular lodepng_inspect first since format of most other chunks depends on IHDR, and if there is a PLTE chunk, that one must be inspected before tRNS or bKGD. */ -unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, - const unsigned char* in, size_t insize); +unsigned lodepng_inspect_chunk(LodePNGState *state, size_t pos, + const unsigned char *in, size_t insize); #ifdef LODEPNG_COMPILE_ENCODER -/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ -unsigned lodepng_encode(unsigned char** out, size_t* outsize, - const unsigned char* image, unsigned w, unsigned h, - LodePNGState* state); +/*This function allocates the out buffer with standard malloc and stores the + * size in *outsize.*/ +unsigned lodepng_encode(unsigned char **out, size_t *outsize, + const unsigned char *image, unsigned w, unsigned h, + LodePNGState *state); #endif /*LODEPNG_COMPILE_ENCODER*/ /* @@ -830,13 +919,13 @@ The chunk pointer always points to the beginning of the chunk itself, that is the first byte of the 4 length bytes. In the PNG file format, chunks have the following format: --4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer) --4 bytes chunk type (ASCII a-z,A-Z only, see below) --length bytes of data (may be 0 bytes if length was 0) --4 bytes of CRC, computed on chunk name + data +-4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 +bytes longer) -4 bytes chunk type (ASCII a-z,A-Z only, see below) -length bytes +of data (may be 0 bytes if length was 0) -4 bytes of CRC, computed on chunk name ++ data -The first chunk starts at the 8th byte of the PNG file, the entire rest of the file -exists out of concatenated chunks with the above format. +The first chunk starts at the 8th byte of the PNG file, the entire rest of the +file exists out of concatenated chunks with the above format. PNG standard chunk ASCII naming conventions: -First byte: uppercase = critical, lowercase = ancillary @@ -850,73 +939,83 @@ Gets the length of the data of the chunk. Total chunk length has 12 bytes more. There must be at least 4 bytes to read from. If the result value is too large, it may be corrupt data. */ -unsigned lodepng_chunk_length(const unsigned char* chunk); +unsigned lodepng_chunk_length(const unsigned char *chunk); /*puts the 4-byte type in null terminated string*/ -void lodepng_chunk_type(char type[5], const unsigned char* chunk); +void lodepng_chunk_type(char type[5], const unsigned char *chunk); /*check if the type is the given type*/ -unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); +unsigned char lodepng_chunk_type_equals(const unsigned char *chunk, + const char *type); -/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ -unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG + * standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char *chunk); /*0: public, 1: private (see PNG standard)*/ -unsigned char lodepng_chunk_private(const unsigned char* chunk); +unsigned char lodepng_chunk_private(const unsigned char *chunk); -/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ -unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG + * standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char *chunk); -/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ -unsigned char* lodepng_chunk_data(unsigned char* chunk); -const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); +/*get pointer to the data of the chunk, where the input points to the header of + * the chunk*/ +unsigned char *lodepng_chunk_data(unsigned char *chunk); +const unsigned char *lodepng_chunk_data_const(const unsigned char *chunk); /*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ -unsigned lodepng_chunk_check_crc(const unsigned char* chunk); +unsigned lodepng_chunk_check_crc(const unsigned char *chunk); -/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ -void lodepng_chunk_generate_crc(unsigned char* chunk); +/*generates the correct CRC from the data and puts it in the last 4 bytes of the + * chunk*/ +void lodepng_chunk_generate_crc(unsigned char *chunk); /* Iterate to next chunks, allows iterating through all chunks of the PNG file. -Input must be at the beginning of a chunk (result of a previous lodepng_chunk_next call, -or the 8th byte of a PNG file which always has the first chunk), or alternatively may -point to the first byte of the PNG file (which is not a chunk but the magic header, the -function will then skip over it and return the first real chunk). -Will output pointer to the start of the next chunk, or at or beyond end of the file if there -is no more chunk after this or possibly if the chunk is corrupt. -Start this process at the 8th byte of the PNG file. -In a non-corrupt PNG file, the last chunk should have name "IEND". +Input must be at the beginning of a chunk (result of a previous +lodepng_chunk_next call, or the 8th byte of a PNG file which always has the +first chunk), or alternatively may point to the first byte of the PNG file +(which is not a chunk but the magic header, the function will then skip over it +and return the first real chunk). Will output pointer to the start of the next +chunk, or at or beyond end of the file if there is no more chunk after this or +possibly if the chunk is corrupt. Start this process at the 8th byte of the PNG +file. In a non-corrupt PNG file, the last chunk should have name "IEND". */ -unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end); -const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end); +unsigned char *lodepng_chunk_next(unsigned char *chunk, unsigned char *end); +const unsigned char *lodepng_chunk_next_const(const unsigned char *chunk, + const unsigned char *end); -/*Finds the first chunk with the given type in the range [chunk, end), or returns NULL if not found.*/ -unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]); -const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]); +/*Finds the first chunk with the given type in the range [chunk, end), or + * returns NULL if not found.*/ +unsigned char *lodepng_chunk_find(unsigned char *chunk, unsigned char *end, + const char type[5]); +const unsigned char *lodepng_chunk_find_const(const unsigned char *chunk, + const unsigned char *end, + const char type[5]); /* -Appends chunk to the data in out. The given chunk should already have its chunk header. -The out variable and outsize are updated to reflect the new reallocated buffer. -Returns error code (0 if it went ok) +Appends chunk to the data in out. The given chunk should already have its chunk +header. The out variable and outsize are updated to reflect the new reallocated +buffer. Returns error code (0 if it went ok) */ -unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk); +unsigned lodepng_chunk_append(unsigned char **out, size_t *outsize, + const unsigned char *chunk); /* -Appends new chunk to out. The chunk to append is given by giving its length, type -and data separately. The type is a 4-letter string. -The out variable and outsize are updated to reflect the new reallocated buffer. -Returne error code (0 if it went ok) +Appends new chunk to out. The chunk to append is given by giving its length, +type and data separately. The type is a 4-letter string. The out variable and +outsize are updated to reflect the new reallocated buffer. Returne error code (0 +if it went ok) */ -unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, - const char* type, const unsigned char* data); - +unsigned lodepng_chunk_create(unsigned char **out, size_t *outsize, + unsigned length, const char *type, + const unsigned char *data); /*Calculate CRC32 of buffer*/ -unsigned lodepng_crc32(const unsigned char* buf, size_t len); +unsigned lodepng_crc32(const unsigned char *buf, size_t len); #endif /*LODEPNG_COMPILE_PNG*/ - #ifdef LODEPNG_COMPILE_ZLIB /* This zlib part can be used independently to zlib compress and decompress a @@ -925,10 +1024,11 @@ part of zlib that is required for PNG, it does not support dictionaries. */ #ifdef LODEPNG_COMPILE_DECODER -/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ -unsigned lodepng_inflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings); +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer + * must be freed after use.*/ +unsigned lodepng_inflate(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGDecompressSettings *settings); /* Decompresses Zlib data. Reallocates the out buffer and appends the data. The @@ -936,9 +1036,9 @@ data must be according to the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ -unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGDecompressSettings* settings); +unsigned lodepng_zlib_decompress(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGDecompressSettings *settings); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER @@ -949,21 +1049,23 @@ The data is output in the format of the zlib specification. Either, *out must be NULL and *outsize must be 0, or, *out must be a valid buffer and *outsize its size in bytes. out must be freed by user after usage. */ -unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings); +unsigned lodepng_zlib_compress(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGCompressSettings *settings); /* Find length-limited Huffman code for given frequencies. This function is in the public interface only for tests, it's used internally by lodepng_deflate. */ -unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, +unsigned lodepng_huffman_code_lengths(unsigned *lengths, + const unsigned *frequencies, size_t numcodes, unsigned maxbitlen); -/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ -unsigned lodepng_deflate(unsigned char** out, size_t* outsize, - const unsigned char* in, size_t insize, - const LodePNGCompressSettings* settings); +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after + * use.*/ +unsigned lodepng_deflate(unsigned char **out, size_t *outsize, + const unsigned char *in, size_t insize, + const LodePNGCompressSettings *settings); #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ @@ -977,7 +1079,8 @@ outsize: output parameter, size of the allocated out buffer filename: the path to the file to load return value: error code (0 means ok) */ -unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); +unsigned lodepng_load_file(unsigned char **out, size_t *outsize, + const char *filename); /* Save a file from buffer to disk. Warning, if it exists, this function overwrites @@ -987,39 +1090,40 @@ buffersize: size of the buffer to write filename: the path to the file to save to return value: error code (0 means ok) */ -unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +unsigned lodepng_save_file(const unsigned char *buffer, size_t buffersize, + const char *filename); #endif /*LODEPNG_COMPILE_DISK*/ #ifdef LODEPNG_COMPILE_CPP -/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated + * memory buffers. */ namespace lodepng { #ifdef LODEPNG_COMPILE_PNG class State : public LodePNGState { - public: - State(); - State(const State& other); - ~State(); - State& operator=(const State& other); +public: + State(); + State(const State &other); + ~State(); + State &operator=(const State &other); }; #ifdef LODEPNG_COMPILE_DECODER -/* Same as other lodepng::decode, but using a State for more settings and information. */ -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const unsigned char* in, size_t insize); -unsigned decode(std::vector& out, unsigned& w, unsigned& h, - State& state, - const std::vector& in); +/* Same as other lodepng::decode, but using a State for more settings and + * information. */ +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + State &state, const unsigned char *in, size_t insize); +unsigned decode(std::vector &out, unsigned &w, unsigned &h, + State &state, const std::vector &in); #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER -/* Same as other lodepng::encode, but using a State for more settings and information. */ -unsigned encode(std::vector& out, - const unsigned char* in, unsigned w, unsigned h, - State& state); -unsigned encode(std::vector& out, - const std::vector& in, unsigned w, unsigned h, - State& state); +/* Same as other lodepng::encode, but using a State for more settings and + * information. */ +unsigned encode(std::vector &out, const unsigned char *in, + unsigned w, unsigned h, State &state); +unsigned encode(std::vector &out, + const std::vector &in, unsigned w, unsigned h, + State &state); #endif /*LODEPNG_COMPILE_ENCODER*/ #ifdef LODEPNG_COMPILE_DISK @@ -1027,35 +1131,45 @@ unsigned encode(std::vector& out, Load a file from disk into an std::vector. return value: error code (0 means ok) */ -unsigned load_file(std::vector& buffer, const std::string& filename); +unsigned load_file(std::vector &buffer, + const std::string &filename); /* -Save the binary data in an std::vector to a file on disk. The file is overwritten -without warning. +Save the binary data in an std::vector to a file on disk. The file is +overwritten without warning. */ -unsigned save_file(const std::vector& buffer, const std::string& filename); +unsigned save_file(const std::vector &buffer, + const std::string &filename); #endif /* LODEPNG_COMPILE_DISK */ #endif /* LODEPNG_COMPILE_PNG */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER /* Zlib-decompress an unsigned char buffer */ -unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +unsigned decompress(std::vector &out, const unsigned char *in, + size_t insize, + const LodePNGDecompressSettings &settings = + lodepng_default_decompress_settings); /* Zlib-decompress an std::vector */ -unsigned decompress(std::vector& out, const std::vector& in, - const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +unsigned decompress(std::vector &out, + const std::vector &in, + const LodePNGDecompressSettings &settings = + lodepng_default_decompress_settings); #endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER /* Zlib-compress an unsigned char buffer */ -unsigned compress(std::vector& out, const unsigned char* in, size_t insize, - const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +unsigned compress(std::vector &out, const unsigned char *in, + size_t insize, + const LodePNGCompressSettings &settings = + lodepng_default_compress_settings); /* Zlib-compress an std::vector */ -unsigned compress(std::vector& out, const std::vector& in, - const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +unsigned compress(std::vector &out, + const std::vector &in, + const LodePNGCompressSettings &settings = + lodepng_default_compress_settings); #endif /* LODEPNG_COMPILE_ENCODER */ #endif /* LODEPNG_COMPILE_ZLIB */ } /* namespace lodepng */ @@ -1063,24 +1177,26 @@ unsigned compress(std::vector& out, const std::vector (2^31)-1 -[ ] partial decoding (stream processing) -[X] let the "isFullyOpaque" function check color keys and transparent palettes too -[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" -[ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58) -[ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... -[ ] error messages with line numbers (and version) -[ ] errors in state instead of as return code? -[ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk -[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes -[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... -[ ] allow user to give data (void*) to custom allocator -[X] provide alternatives for C library functions not present on some platforms (memcpy, ...) +[.] test if there are no memory leaks or security exploits - done a lot but +needs to be checked often +[.] check compatibility with various compilers - done but needs to be redone +for every newer version [X] converting color to 16-bit per channel types [X] +support color profile chunk types (but never let them touch RGB values by +default) [ ] support all public PNG chunk types (almost done except sBIT, sPLT +and hIST) [ ] make sure encoder generates no chunks with size > (2^31)-1 [ ] +partial decoding (stream processing) [X] let the "isFullyOpaque" function check +color keys and transparent palettes too [X] better name for the variables +"codes", "codesD", "codelengthcodes", "clcl" and "lldl" [ ] allow treating some +errors like warnings, when image is recoverable (e.g. 69, 57, 58) [ ] make +warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit +chunk, no null terminator in text, ... [ ] error messages with line numbers (and +version) [ ] errors in state instead of as return code? [ ] new errors/warnings +like suspiciously big decompressed ztxt or iccp chunk [ ] let the C++ wrapper +catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for +premultiplied alpha, padding bits or not, ... [ ] allow user to give data +(void*) to custom allocator [X] provide alternatives for C library functions not +present on some platforms (memcpy, ...) */ #endif /*LODEPNG_H inclusion guard*/ @@ -1141,7 +1257,8 @@ extra functionality. LodePNG exists out of two files: -lodepng.h: the header file for both C and C++ --lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on +your usage If you want to start using LodePNG right away without reading this doc, get the examples from the LodePNG website to see how to use it in code, or check the @@ -1166,18 +1283,23 @@ begin), life-critical systems, ... The following features are supported by the decoder: -*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, - or the same color type as the PNG -*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- +or 32-bit color raw image, or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same +color type as the raw image *) Adam7 interlace and deinterlace for any color type -*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk -*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) loading the image from harddisk or decoding it from a buffer from other +sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes +and color keying *) zlib decompression (inflate) *) zlib compression (deflate) *) CRC32 and ADLER32 checksums -*) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only, - plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system. -*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) colorimetric color profile conversions: currently experimentally available in +lodepng_util.cpp only, plus alternatively ability to pass on chroma/gamma/ICC +profile information to other color management system. +*) handling of unknown chunks, allowing making a PNG editor that stores custom +and unknown chunks. *) the following chunks are supported by both encoder and decoder: IHDR: header information PLTE: color palette @@ -1201,11 +1323,10 @@ The following features are supported by the decoder: The following features are _not_ supported: *) some features needed to make a conformant PNG-Editor might be still missing. -*) partial loading/stream processing. All data must be available and is processed in one call. -*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG: - sBIT - hIST - sPLT +*) partial loading/stream processing. All data must be available and is +processed in one call. +*) The following public chunks are not (yet) supported but treated as unknown +chunks by LodePNG: sBIT hIST sPLT 2. C and C++ version @@ -1239,10 +1360,11 @@ When using LodePNG, care has to be taken with the C version of LodePNG, as well as the C-style structs when working with C++. The following conventions are used for all C-style structs: --if a struct has a corresponding init function, always call the init function when making a new one --if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks --if a struct has a corresponding copy function, use the copy function instead of "=". - The destination must also be inited already. +-if a struct has a corresponding init function, always call the init function +when making a new one -if a struct has a corresponding cleanup function, call it +before the struct disappears to avoid memory leaks -if a struct has a +corresponding copy function, use the copy function instead of "=". The +destination must also be inited already. 4. Decoding @@ -1258,16 +1380,19 @@ various lodepng::decode functions, and lodepng::State can be used for advanced features. When using the LodePNGState, it uses the following fields for decoding: -*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here -*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get -*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) +in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image +(the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the +decoder to use LodePNGInfo info_png -------------------- -After decoding, this contains extra information of the PNG image, except the actual -pixels, width and height because these are already gotten directly from the decoder -functions. +After decoding, this contains extra information of the PNG image, except the +actual pixels, width and height because these are already gotten directly from +the decoder functions. It contains for example the original color type of the PNG image, text comments, suggested background color, etc... More details about the LodePNGInfo struct are @@ -1313,9 +1438,12 @@ since the encoder input is trusted, the decoder input (a PNG image that could be forged by anyone) is not trusted. When using the LodePNGState, it uses the following fields for encoding: -*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. -*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has -*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to +be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the +input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the +encoder to use LodePNGInfo info_png -------------------- @@ -1363,10 +1491,11 @@ can encode the colors of all pixels without information loss. chunk if force_palette is true. This can used as suggested palette to convert to by viewers that don't support more than 256 colors (if those still exist) *) add_id: add text chunk "Encoder: LodePNG " to the image. -*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. - zTXt chunks use zlib compression on the text. This gives a smaller result on - large texts but a larger result on small texts (such as a single program name). - It's all tEXt or all zTXt though, there's no separate setting per text yet. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt +chunks. zTXt chunks use zlib compression on the text. This gives a smaller +result on large texts but a larger result on small texts (such as a single +program name). It's all tEXt or all zTXt though, there's no separate setting per +text yet. 6. color conversions @@ -1445,19 +1574,19 @@ sometimes result in an error. To avoid some confusion: -the decoder converts from PNG to raw image -the encoder converts from raw image to PNG --the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image --the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG --when encoding, the color type in LodePNGInfo is ignored if auto_convert - is enabled, it is automatically generated instead --when decoding, the color type in LodePNGInfo is set by the decoder to that of the original - PNG image, but it can be ignored since the raw image has the color type you requested instead --if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion - between the color types is done if the color types are supported. If it is not - supported, an error is returned. If the types are the same, no conversion is done. --even though some conversions aren't supported, LodePNG supports loading PNGs from any - colortype and saving PNGs to any colortype, sometimes it just requires preparing - the raw image correctly before encoding. --both encoder and decoder use the same color converter. +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw +image -the colortype and bitdepth in the color field of LodePNGInfo info_png, +are those of the PNG -when encoding, the color type in LodePNGInfo is ignored if +auto_convert is enabled, it is automatically generated instead -when decoding, +the color type in LodePNGInfo is set by the decoder to that of the original PNG +image, but it can be ignored since the raw image has the color type you +requested instead -if the color type of the LodePNGColorMode and PNG image +aren't the same, a conversion between the color types is done if the color types +are supported. If it is not supported, an error is returned. If the types are +the same, no conversion is done. -even though some conversions aren't supported, +LodePNG supports loading PNGs from any colortype and saving PNGs to any +colortype, sometimes it just requires preparing the raw image correctly before +encoding. -both encoder and decoder use the same color converter. The function lodepng_convert does the color conversion. It is available in the interface but normally isn't needed since the encoder and decoder already call @@ -1469,8 +1598,8 @@ the result will look ugly because only the red channel is taken (it assumes all three channels are the same in this case so ignores green and blue). The reason no error is given is to allow converting from three-channel grayscale images to one-channel even if there are numerical imprecisions. --anything to palette when the palette does not have an exact match for a from-color -in it: in this case an error is thrown +-anything to palette when the palette does not have an exact match for a +from-color in it: in this case an error is thrown Supported color conversions: -anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA @@ -1490,13 +1619,14 @@ info_raw are then ignored. 6.3. padding bits ----------------- -In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines -have a bit amount that isn't a multiple of 8, then padding bits are used so that each -scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. -The raw input image you give to the encoder, and the raw output image you get from the decoder -will NOT have these padding bits, e.g. in the case of a 1-bit image with a width -of 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte, -not the first bit of a new byte. +In the PNG file format, if a less than 8-bit per pixel color type is used and +the scanlines have a bit amount that isn't a multiple of 8, then padding bits +are used so that each scanline starts at a fresh byte. But that is NOT true for +the LodePNG raw input and output. The raw input image you give to the encoder, +and the raw output image you get from the decoder will NOT have these padding +bits, e.g. in the case of a 1-bit image with a width of 7 pixels, the first +pixel of the second scanline will the 8th bit of the first byte, not the first +bit of a new byte. 6.4. A note about 16-bits per channel and endianness ---------------------------------------------------- @@ -1570,7 +1700,8 @@ unsigned lodepng_chunk_length(const unsigned char* chunk): Get the length of the chunk's data. The total chunk length is this length + 12. void lodepng_chunk_type(char type[5], const unsigned char* chunk): -unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* +type): Get the type of the chunk or compare if it's a certain type @@ -1578,11 +1709,12 @@ unsigned char lodepng_chunk_critical(const unsigned char* chunk): unsigned char lodepng_chunk_private(const unsigned char* chunk): unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): -Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). -Check if the chunk is private (public chunks are part of the standard, private ones not). -Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical -chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your -program doesn't handle that type of unknown chunk. +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and +IEND are). Check if the chunk is private (public chunks are part of the +standard, private ones not). Check if the chunk is safe to copy. If it's not, +then, when modifying data in a critical chunk, unsafe to copy chunks of the old +image may NOT be saved in the new one if your program doesn't handle that type +of unknown chunk. unsigned char* lodepng_chunk_data(unsigned char* chunk): const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): @@ -1597,18 +1729,19 @@ Check if the crc is correct or generate a correct one. unsigned char* lodepng_chunk_next(unsigned char* chunk): const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): -Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these -functions do no boundary checking of the allocated data whatsoever, so make sure there is enough -data available in the buffer to be able to go to the next chunk. +Iterate to the next chunk. This works if you have a buffer with consecutive +chunks. Note that these functions do no boundary checking of the allocated data +whatsoever, so make sure there is enough data available in the buffer to be able +to go to the next chunk. -unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk): -unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, - const char* type, const unsigned char* data): +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const +unsigned char* chunk): unsigned lodepng_chunk_create(unsigned char** out, +size_t* outsize, unsigned length, const char* type, const unsigned char* data): -These functions are used to create new chunks that are appended to the data in *out that has -length *outsize. The append function appends an existing chunk to the new data. The create -function creates a new chunk with the given parameters and appends it. Type is the 4-letter -name of the chunk. +These functions are used to create new chunks that are appended to the data in +*out that has length *outsize. The append function appends an existing chunk to +the new data. The create function creates a new chunk with the given parameters +and appends it. Type is the 4-letter name of the chunk. 8.2. chunks in info_png ----------------------- @@ -1724,9 +1857,11 @@ int main(int argc, char *argv[]) { unsigned error = lodepng::decode(image, width, height, filename); //if there's an error, display it - if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + if(error) std::cout << "decoder error " << error << ": " << +lodepng_error_text(error) << std::endl; - //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... + //the pixels are now in the vector "image", 4 bytes per pixel, ordered +RGBARGBA..., use it as texture, draw it, ... } 10.2. decoder C example @@ -1761,10 +1896,10 @@ state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums state.decoder.zlibsettings.custom_...: use custom inflate function state.decoder.ignore_crc: ignore CRC checksums state.decoder.ignore_critical: ignore unknown critical chunks -state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors -state.decoder.color_convert: convert internal PNG color to chosen one -state.decoder.read_text_chunks: whether to read in text metadata chunks -state.decoder.remember_unknown_chunks: whether to read in unknown chunks +state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption +causes other errors state.decoder.color_convert: convert internal PNG color to +chosen one state.decoder.read_text_chunks: whether to read in text metadata +chunks state.decoder.remember_unknown_chunks: whether to read in unknown chunks state.info_raw.colortype: desired color type for decoded image state.info_raw.bitdepth: desired bit depth for decoded image state.info_raw....: more color settings, see struct LodePNGColorMode @@ -1930,18 +2065,20 @@ https://github.com/lvandeve/lodepng *) 29 dec 2006: Added support for encoding images without alpha channel, and cleaned out code as well as making certain parts faster. *) 28 dec 2006: Added "Settings" to the encoder. -*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. - Removed some code duplication in the decoder. Fixed little bug in an example. -*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. - Fixed a bug of the decoder with 16-bit per color. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller +files now. Removed some code duplication in the decoder. Fixed little bug in an +example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first +parameter. Fixed a bug of the decoder with 16-bit per color. *) 15 okt 2006: Changed documentation structure *) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the given image buffer, however for now it's not compressed. *) 08 sep 2006: (!) Changed to interface with a Decoder class -*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different - way. Renamed decodePNG to decodePNGGeneric. +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in +different way. Renamed decodePNG to decodePNGGeneric. *) 29 jul 2006: (!) Changed the interface: image info is now returned as a - struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit +clumsy. *) 28 jul 2006: Cleaned the code and added new error checks. Corrected terminology "deflate" into "inflate". *) 23 jun 2006: Added SDL example in the documentation in the header, this diff --git a/include/renderd7/external/stb_image.h b/include/renderd7/external/stb_image.h index d60371b..2b5ad6b 100644 --- a/include/renderd7/external/stb_image.h +++ b/include/renderd7/external/stb_image.h @@ -3,7 +3,8 @@ Do this: #define STB_IMAGE_IMPLEMENTATION - before you include this file in *one* C or C++ file to create the implementation. + before you include this file in *one* C or C++ file to create the +implementation. // i.e. it should look like this: #include ... @@ -13,15 +14,16 @@ #include "stb_image.h" You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. - And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using +malloc,realloc,free QUICK NOTES: Primarily of interest to game developers and other people who can avoid problematic images and only need the trivial interface - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8/16-bit-per-channel + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as +stock IJG lib) PNG 1/2/4/8/16-bit-per-channel TGA (not sure what subset, if a subset) BMP non-1bpp, non-RLE @@ -48,23 +50,19 @@ LICENSE RECENT REVISION HISTORY: - 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes - 2.26 (2020-07-13) many minor fixes - 2.25 (2020-02-02) fix warnings - 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically - 2.23 (2019-08-11) fix clang static analysis warning - 2.22 (2019-03-04) gif fixes, fix warnings - 2.21 (2019-02-25) fix typo in comment - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings - 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes - 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug +fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings 2.24 +(2020-02-02) fix warnings; thread-local failure_reason and flip_vertically 2.23 +(2019-08-11) fix clang static analysis warning 2.22 (2019-03-04) gif fixes, fix +warnings 2.21 (2019-02-25) fix typo in comment 2.20 (2019-02-07) support utf8 +filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix +warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) bugfix, 1-bit BMP, +16-bitness query, fix warnings 2.16 (2017-07-23) all functions have 16-bit +variants; optimizations; bugfixes 2.15 (2017-03-18) fix png-1,2,4; all Imagenet +JPGs; no runtime SSE detection on GCC 2.14 (2017-03-03) remove deprecated +STBI_JPEG_OLD; fixes for Imagenet JPGs 2.13 (2016-12-04) experimental 16-bit +API, only for PNG so far; fixes 2.12 (2016-04-02) fix typo in 2.11 PSD fix that +caused crashes 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 RGB-format JPEG; remove white matting in PSD; allocate large structures on the stack; correct channel count for PNG & BMP @@ -87,40 +85,39 @@ RECENT REVISION HISTORY: github:urraka (animated gif) Junggon Kim (PNM comments) Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) socks-the-fox (16-bit PNG) - Jeremy Sawicki (handle all ImageNet JPGs) - Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Jeremy Sawicki (handle all ImageNet +JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen Carmelo J Fdez-Aguera Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski - Phil Jordan Dave Moore Roy Eltham - Hayaki Saito Nathan Reed Won Chun - Luke Graham Johan Duparc Nick Verigakis the Horde3D community - Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Eugene Golushkov Laurent Gomila Cort Stratton github:snagar - Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex - Cass Everitt Ryamond Barbiero github:grim210 - Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw - Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus - Josh Tobin Matthew Gregan github:poppolopoppo - Julian Raschke Gregory Mullen Christian Floisand github:darealshinji - Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 - Brad Weinberger Matvey Cherevko github:mosra - Luca Sas Alexander Veselov Zack Middleton [reserved] - Ryan C. Gordon [reserved] [reserved] - DO NOT ADD YOUR NAME HERE + Marc LeBlanc David Woo Guillaume George Martins +Mozeiko Christpher Lloyd Jerry Jansson Joseph Thomson Blazej +Dariusz Roszkowski Phil Jordan Dave Moore Roy +Eltham Hayaki Saito Nathan Reed Won Chun Luke Graham Johan +Duparc Nick Verigakis the Horde3D community Thomas Ruf Ronny +Chevalier github:rlyeh Janez Zemva John +Bartholomew Michal Cichon github:romigrou Jonathan Blow Ken +Hamada Tero Hanninen github:svdijk Eugene Golushkov Laurent +Gomila Cort Stratton github:snagar Aruelien Pocheville Sergio +Gonzalez Thibault Reuille github:Zelex Cass Everitt Ryamond +Barbiero github:grim210 Paul Du Bois Engin +Manap Aldo Culquicondor github:sammyhw Philipp Wiesemann Dale +Weiler Oriol Ferrer Mesia github:phprus Josh Tobin Matthew Gregan +github:poppolopoppo Julian Raschke Gregory Mullen Christian +Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR +Smith github:Michaelangel007 Brad Weinberger Matvey Cherevko +github:mosra Luca Sas Alexander Veselov Zack Middleton +[reserved] Ryan C. Gordon [reserved] [reserved] DO NOT ADD YOUR NAME +HERE Jacko Dirks - To add your name to the credits, pick a random blank space in the middle and fill it. - 80% of merge conflicts on stb PRs are due to people adding their name at the end - of the credits. + To add your name to the credits, pick a random blank space in the middle and +fill it. 80% of merge conflicts on stb PRs are due to people adding their name +at the end of the credits. */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -139,14 +136,15 @@ RECENT REVISION HISTORY: // // ... process data if not NULL ... // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel -// // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) +// // ... but 'n' will always be the number that it would have been if you +// said 0 stbi_image_free(data) // // Standard parameters: // int *x -- outputs image width in pixels // int *y -- outputs image height in pixels // int *channels_in_file -- outputs # of image components in image file -// int desired_channels -- if non-zero, # of image components requested in result +// int desired_channels -- if non-zero, # of image components requested in +// result // // The return value from an image loader is an 'unsigned char *' which points // to the pixel data, or NULL on an allocation failure or if the image is @@ -174,8 +172,8 @@ RECENT REVISION HISTORY: // and *x, *y, *channels_in_file will be unchanged. The function // stbi_failure_reason() can be queried for an extremely brief, end-user // unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS -// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly -// more user-friendly ones. +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get +// slightly more user-friendly ones. // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // @@ -225,11 +223,12 @@ RECENT REVISION HISTORY: // 2. easy to maintain // 3. good performance // -// Sometimes I let "good performance" creep up in priority over "easy to maintain", -// and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy-to-use ones. Nevertheless, it's important -// to keep in mind that from the standpoint of you, a client of this library, -// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// Sometimes I let "good performance" creep up in priority over "easy to +// maintain", and for best performance I may provide less-easy-to-use APIs that +// give higher performance, in addition to the easy-to-use ones. Nevertheless, +// it's important to keep in mind that from the standpoint of you, a client of +// this library, all you care about is #1 and #3, and stb libraries DO NOT +// emphasize #3 above all. // // Some secondary priorities arise directly from the first two, some of which // provide more explicit reasons why performance can't be emphasized. @@ -248,7 +247,8 @@ RECENT REVISION HISTORY: // overhead. // // The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the +// end). // // =========================================================================== // @@ -276,10 +276,11 @@ RECENT REVISION HISTORY: // HDR image support (disable by defining STBI_NO_HDR) // // stb_image supports loading HDR images in general, and currently the Radiance -// .HDR file format specifically. You can still load any file through the existing -// interface; if you attempt to load an HDR file, it will be automatically remapped -// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; -// both of these constants can be reconfigured through this interface: +// .HDR file format specifically. You can still load any file through the +// existing interface; if you attempt to load an HDR file, it will be +// automatically remapped to LDR, assuming gamma 2.2 and an arbitrary scale +// factor defaulting to 1; both of these constants can be reconfigured through +// this interface: // // stbi_hdr_to_ldr_gamma(2.2f); // stbi_hdr_to_ldr_scale(1.0f); @@ -370,14 +371,13 @@ RECENT REVISION HISTORY: #define STBI_VERSION 1 -enum -{ - STBI_default = 0, // only used for desired_channels +enum { + STBI_default = 0, // only used for desired_channels - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 }; #include @@ -405,11 +405,13 @@ extern "C" { // load image by filename, open file, or memory buffer // -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data +typedef struct { + int (*read)(void *user, char *data, + int size); // fill 'data' with 'size' bytes. return number of + // bytes actually read + void (*skip)(void *user, int n); // skip the next 'n' bytes, or 'unget' the + // last -n bytes if negative + int (*eof)(void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; //////////////////////////////////// @@ -417,21 +419,33 @@ typedef struct // 8-bits-per-channel interface // -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, + int *y, int *channels_in_file, + int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, + void *user, int *x, int *y, + int *channels_in_file, + int desired_channels); #ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); -// for stbi_load_from_file, file pointer is left pointing immediately after image +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, + int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, + int *channels_in_file, + int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after +// image #endif #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, + int **delays, int *x, int *y, int *z, + int *comp, int req_comp); #endif #ifdef STBI_WINDOWS_UTF8 -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, + const wchar_t *input); #endif //////////////////////////////////// @@ -439,12 +453,20 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch // 16-bits-per-channel interface // -STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, + int *x, int *y, int *channels_in_file, + int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, + void *user, int *x, int *y, + int *channels_in_file, + int desired_channels); #ifndef STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, + int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, + int *channels_in_file, + int desired_channels); #endif //////////////////////////////////// @@ -452,85 +474,106 @@ STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_i // float-per-channel interface // #ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, + int *y, int *channels_in_file, + int desired_channels); +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, + void *user, int *x, int *y, + int *channels_in_file, + int desired_channels); - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); - #endif +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, + int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, + int *channels_in_file, + int desired_channels); +#endif #endif #ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); +STBIDEF void stbi_hdr_to_ldr_scale(float scale); #endif // STBI_NO_HDR #ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); +STBIDEF void stbi_ldr_to_hdr_scale(float scale); #endif // STBI_NO_LINEAR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, + void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); +STBIDEF int stbi_is_hdr(char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); #endif // STBI_NO_STDIO - // get a VERY brief reason for failure // on most compilers (and ALL modern mainstream compilers) this is threadsafe -STBIDEF const char *stbi_failure_reason (void); +STBIDEF const char *stbi_failure_reason(void); // free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); +STBIDEF void stbi_image_free(void *retval_from_stbi_load); // get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, + int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, + int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, + void *user); #ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit (char const *filename); -STBIDEF int stbi_is_16_bit_from_file(FILE *f); +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit(char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); #endif - - // for image formats that explicitly notate that they have premultiplied alpha, // we just return the colors as stored in the file. set this flag to force // unpremultiplication. results are undefined if the unpremultiply overflow. -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); +STBIDEF void +stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); // indicate whether we should process iphone images back to canonical format, // or just pass them through "as-is" STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); -// flip the image vertically, so the first pixel in the output array is the bottom left +// flip the image vertically, so the first pixel in the output array is the +// bottom left STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); -// as above, but only applies to images loaded on the thread that calls the function -// this function is only available if your compiler supports thread-local variables; -// calling it will fail to link if your compiler doesn't -STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); -STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); -STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); +// as above, but only applies to images loaded on the thread that calls the +// function this function is only available if your compiler supports +// thread-local variables; calling it will fail to link if your compiler doesn't +STBIDEF void +stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void +stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void +stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, + int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, + int len, + int initial_size, + int *outlen, + int parse_header); STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - -STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, + const char *ibuffer, int ilen); +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, + int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, + const char *ibuffer, int ilen); #ifdef __cplusplus } @@ -543,52 +586,53 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #ifdef STB_IMAGE_IMPLEMENTATION -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || \ + defined(STBI_ONLY_BMP) || defined(STBI_ONLY_TGA) || \ + defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) || \ + defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || \ + defined(STBI_ONLY_PNM) || defined(STBI_ONLY_ZLIB) +#ifndef STBI_ONLY_JPEG +#define STBI_NO_JPEG +#endif +#ifndef STBI_ONLY_PNG +#define STBI_NO_PNG +#endif +#ifndef STBI_ONLY_BMP +#define STBI_NO_BMP +#endif +#ifndef STBI_ONLY_PSD +#define STBI_NO_PSD +#endif +#ifndef STBI_ONLY_TGA +#define STBI_NO_TGA +#endif +#ifndef STBI_ONLY_GIF +#define STBI_NO_GIF +#endif +#ifndef STBI_ONLY_HDR +#define STBI_NO_HDR +#endif +#ifndef STBI_ONLY_PIC +#define STBI_NO_PIC +#endif +#ifndef STBI_ONLY_PNM +#define STBI_NO_PNM +#endif #endif -#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && \ + !defined(STBI_NO_ZLIB) #define STBI_NO_ZLIB #endif - +#include #include #include // ptrdiff_t on osx #include #include -#include #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include // ldexp, pow +#include // ldexp, pow #endif #ifndef STBI_NO_STDIO @@ -606,55 +650,55 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define STBI_EXTERN extern #endif - #ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif +#ifdef __cplusplus +#define stbi_inline inline #else - #define stbi_inline __forceinline +#define stbi_inline +#endif +#else +#define stbi_inline __forceinline #endif #ifndef STBI_NO_THREAD_LOCALS - #if defined(__cplusplus) && __cplusplus >= 201103L - #define STBI_THREAD_LOCAL thread_local - #elif defined(__GNUC__) && __GNUC__ < 5 - #define STBI_THREAD_LOCAL __thread - #elif defined(_MSC_VER) - #define STBI_THREAD_LOCAL __declspec(thread) - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) - #define STBI_THREAD_LOCAL _Thread_local - #endif +#if defined(__cplusplus) && __cplusplus >= 201103L +#define STBI_THREAD_LOCAL thread_local +#elif defined(__GNUC__) && __GNUC__ < 5 +#define STBI_THREAD_LOCAL __thread +#elif defined(_MSC_VER) +#define STBI_THREAD_LOCAL __declspec(thread) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \ + !defined(__STDC_NO_THREADS__) +#define STBI_THREAD_LOCAL _Thread_local +#endif - #ifndef STBI_THREAD_LOCAL - #if defined(__GNUC__) - #define STBI_THREAD_LOCAL __thread - #endif - #endif +#ifndef STBI_THREAD_LOCAL +#if defined(__GNUC__) +#define STBI_THREAD_LOCAL __thread +#endif +#endif #endif #ifdef _MSC_VER typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; -typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; #else #include typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; +typedef int16_t stbi__int16; typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; +typedef int32_t stbi__int32; #endif // should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; +typedef unsigned char validate_uint32[sizeof(stbi__uint32) == 4 ? 1 : -1]; #ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) +#define STBI_NOTUSED(v) (void)(v) #else -#define STBI_NOTUSED(v) (void)sizeof(v) +#define STBI_NOTUSED(v) (void)sizeof(v) #endif #ifdef _MSC_VER @@ -662,27 +706,30 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #endif #ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) +#define stbi_lrot(x, y) _lrotl(x, y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) +#define stbi_lrot(x, y) (((x) << (y)) | ((x) >> (-(y)&31))) #endif -#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +#if defined(STBI_MALLOC) && defined(STBI_FREE) && \ + (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) // ok -#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && \ + !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) // ok #else -#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#error \ + "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." #endif #ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,newsz) realloc(p,newsz) -#define STBI_FREE(p) free(p) +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p, newsz) realloc(p, newsz) +#define STBI_FREE(p) free(p) #endif #ifndef STBI_REALLOC_SIZED -#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#define STBI_REALLOC_SIZED(p, oldsz, newsz) STBI_REALLOC(p, newsz) #endif // x86/x64 detection @@ -692,7 +739,8 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #define STBI__X86_TARGET #endif -#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && \ + !defined(STBI_NO_SIMD) // gcc doesn't support sse2 intrinsics unless you compile with -msse2, // which in turn means it gets to use SSE2 everywhere. This is unfortunate, // but previous attempts to provide the SSE2 functions with runtime @@ -703,8 +751,10 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #define STBI_NO_SIMD #endif -#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) -// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && \ + !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid +// STBI__X64_TARGET // // 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the // Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. @@ -714,44 +764,43 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; // See https://github.com/nothings/stb/issues/81 for more information. // // So default to no SSE2 on 32-bit MinGW. If you've read this far and added -// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +// -mstackrealign to your build settings, feel free to #define +// STBI_MINGW_ENABLE_SSE2. #define STBI_NO_SIMD #endif -#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#if !defined(STBI_NO_SIMD) && \ + (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) #define STBI_SSE2 #include #ifdef _MSC_VER -#if _MSC_VER >= 1400 // not VC6 -#include // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) { + int info[4]; + __cpuid(info, 1); + return info[3]; } #else -static int stbi__cpuid3(void) -{ - int res; - __asm { +static int stbi__cpuid3(void) { + int res; + __asm { mov eax,1 cpuid mov res,edx - } - return res; + } + return res; } #endif #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; +static int stbi__sse2_available(void) { + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; } #endif @@ -759,12 +808,11 @@ static int stbi__sse2_available(void) #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) -static int stbi__sse2_available(void) -{ - // If we're even attempting to compile this on GCC/Clang, that means - // -msse2 is on, which means the compiler is allowed to use SSE2 - // instructions at will, and so are we. - return 1; +static int stbi__sse2_available(void) { + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; } #endif @@ -799,190 +847,180 @@ static int stbi__sse2_available(void) // stbi__context structure is our basic context used by all images, so it // contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; +typedef struct { + stbi__uint32 img_x, img_y; + int img_n, img_out_n; - stbi_io_callbacks io; - void *io_user_data; + stbi_io_callbacks io; + void *io_user_data; - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; - int callback_already_read; + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; } stbi__context; - static void stbi__refill_buffer(stbi__context *s); // initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->callback_already_read = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *)buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *)buffer + len; } // initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->callback_already_read = 0; - s->img_buffer = s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); - s->img_buffer_original_end = s->img_buffer_end; +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, + void *user) { + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; } #ifndef STBI_NO_STDIO -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); +static int stbi__stdio_read(void *user, char *data, int size) { + return (int)fread(data, 1, size, (FILE *)user); } -static void stbi__stdio_skip(void *user, int n) -{ - int ch; - fseek((FILE*) user, n, SEEK_CUR); - ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ - if (ch != EOF) { - ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ - } +static void stbi__stdio_skip(void *user, int n) { + int ch; + fseek((FILE *)user, n, SEEK_CUR); + ch = fgetc((FILE *)user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *)user); /* push byte back onto stream if valid. */ + } } -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user) || ferror((FILE *) user); +static int stbi__stdio_eof(void *user) { + return feof((FILE *)user) || ferror((FILE *)user); } -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, +static stbi_io_callbacks stbi__stdio_callbacks = { + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, }; -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +static void stbi__start_file(stbi__context *s, FILE *f) { + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *)f); } -//static void stop_file(stbi__context *s) { } +// static void stop_file(stbi__context *s) { } #endif // !STBI_NO_STDIO -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; - s->img_buffer_end = s->img_buffer_original_end; +static void stbi__rewind(stbi__context *s) { + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 + // bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; } -enum -{ - STBI_ORDER_RGB, - STBI_ORDER_BGR -}; +enum { STBI_ORDER_RGB, STBI_ORDER_BGR }; -typedef struct -{ - int bits_per_channel; - int num_channels; - int channel_order; +typedef struct { + int bits_per_channel; + int num_channels; + int channel_order; } stbi__result_info; #ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__png_is16(stbi__context *s); +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); #endif #ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__psd_is16(stbi__context *s); +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); #endif #ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, + int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__pnm_is16(stbi__context *s); +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); #endif static #ifdef STBI_THREAD_LOCAL -STBI_THREAD_LOCAL + STBI_THREAD_LOCAL #endif -const char *stbi__g_failure_reason; + const char *stbi__g_failure_reason; -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} +STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } #ifndef STBI_NO_FAILURE_STRINGS -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; +static int stbi__err(const char *str) { + stbi__g_failure_reason = str; + return 0; } #endif -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} +static void *stbi__malloc(size_t size) { return STBI_MALLOC(size); } // stb_image uses ints pervasively, including for offset calculations. // therefore the largest decoded image size we can support with the @@ -996,70 +1034,72 @@ static void *stbi__malloc(size_t size) // return 1 if the sum is valid, 0 on overflow. // negative terms are considered invalid. -static int stbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - // now 0 <= b <= INT_MAX, hence also - // 0 <= INT_MAX - b <= INTMAX. - // And "a + b <= INT_MAX" (which might overflow) is the - // same as a <= INT_MAX - b (no overflow) - return a <= INT_MAX - b; +static int stbi__addsizes_valid(int a, int b) { + if (b < 0) + return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; } // returns 1 if the product is valid, 0 on overflow. // negative factors are considered invalid. -static int stbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; // mul-by-0 is always safe - // portable way to check for no overflows in a*b - return a <= INT_MAX/b; +static int stbi__mul2sizes_valid(int a, int b) { + if (a < 0 || b < 0) + return 0; + if (b == 0) + return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX / b; } -#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || \ + !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow -static int stbi__mad2sizes_valid(int a, int b, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +static int stbi__mad2sizes_valid(int a, int b, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a * b, add); } #endif // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow -static int stbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); +static int stbi__mad3sizes_valid(int a, int b, int c, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && + stbi__addsizes_valid(a * b * c, add); } -// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't +// overflow #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) -static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && + stbi__mul2sizes_valid(a * b * c, d) && + stbi__addsizes_valid(a * b * c * d, add); } #endif -#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || \ + !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // mallocs with size overflow checking -static void *stbi__malloc_mad2(int a, int b, int add) -{ - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); +static void *stbi__malloc_mad2(int a, int b, int add) { + if (!stbi__mad2sizes_valid(a, b, add)) + return NULL; + return stbi__malloc(a * b + add); } #endif -static void *stbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); +static void *stbi__malloc_mad3(int a, int b, int c, int add) { + if (!stbi__mad3sizes_valid(a, b, c, add)) + return NULL; + return stbi__malloc(a * b * c + add); } #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) -static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) -{ - if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; - return stbi__malloc(a*b*c*d + add); +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { + if (!stbi__mad4sizes_valid(a, b, c, d, add)) + return NULL; + return stbi__malloc(a * b * c * d + add); } #endif @@ -1068,423 +1108,465 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) // stbi__errpuc - error returning pointer to unsigned char #ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 +#define stbi__err(x, y) 0 #elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) +#define stbi__err(x, y) stbi__err(y) #else - #define stbi__err(x,y) stbi__err(x) +#define stbi__err(x, y) stbi__err(x) #endif -#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpf(x, y) ((float *)(size_t)(stbi__err(x, y) ? NULL : NULL)) +#define stbi__errpuc(x, y) \ + ((unsigned char *)(size_t)(stbi__err(x, y) ? NULL : NULL)) -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); +STBIDEF void stbi_image_free(void *retval_from_stbi_load) { + STBI_FREE(retval_from_stbi_load); } #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); #endif #ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif static int stbi__vertically_flip_on_load_global = 0; -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } #ifndef STBI_THREAD_LOCAL -#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global #else -static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, + stbi__vertically_flip_on_load_set; -STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load_local = flag_true_if_should_flip; - stbi__vertically_flip_on_load_set = 1; +STBIDEF void +stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) { + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; } -#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ - ? stbi__vertically_flip_on_load_local \ - : stbi__vertically_flip_on_load_global) +#define stbi__vertically_flip_on_load \ + (stbi__vertically_flip_on_load_set ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) #endif // STBI_THREAD_LOCAL -static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields - ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed - ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order - ri->num_channels = 0; +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri, int bpc) { + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = + 8; // default is 8 so most paths don't have to be changed + ri->channel_order = + STBI_ORDER_RGB; // all current input & output are this, but this is here + // so we can add BGR order + ri->num_channels = 0; - // test the formats with a very explicit header first (at least a FOURCC - // or distinctive magic number first) - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); - #else - STBI_NOTUSED(bpc); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); - #endif +// test the formats with a very explicit header first (at least a FOURCC +// or distinctive magic number first) +#ifndef STBI_NO_PNG + if (stbi__png_test(s)) + return stbi__png_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) + return stbi__bmp_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_GIF + if (stbi__gif_test(s)) + return stbi__gif_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PSD + if (stbi__psd_test(s)) + return stbi__psd_load(s, x, y, comp, req_comp, ri, bpc); +#else + STBI_NOTUSED(bpc); +#endif +#ifndef STBI_NO_PIC + if (stbi__pic_test(s)) + return stbi__pic_load(s, x, y, comp, req_comp, ri); +#endif - // then the formats that can end up attempting to load with just 1 or 2 - // bytes matching expectations; these are prone to false positives, so - // try them later - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); - #endif +// then the formats that can end up attempting to load with just 1 or 2 +// bytes matching expectations; these are prone to false positives, so +// try them later +#ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) + return stbi__jpeg_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) + return stbi__pnm_load(s, x, y, comp, req_comp, ri); +#endif - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif +#ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x, y, comp, req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } +#endif - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp, ri); - #endif +#ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s, x, y, comp, req_comp, ri); +#endif - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); + return stbi__errpuc("unknown image type", + "Image not of any known type, or corrupt"); } -static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi_uc *reduced; +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, + int channels) { + int i; + int img_len = w * h * channels; + stbi_uc *reduced; - reduced = (stbi_uc *) stbi__malloc(img_len); - if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + reduced = (stbi_uc *)stbi__malloc(img_len); + if (reduced == NULL) + return stbi__errpuc("outofmem", "Out of memory"); - for (i = 0; i < img_len; ++i) - reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + for (i = 0; i < img_len; ++i) + reduced[i] = + (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient + // approx of 16->8 bit scaling - STBI_FREE(orig); - return reduced; + STBI_FREE(orig); + return reduced; } -static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi__uint16 *enlarged; +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, + int channels) { + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; - enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); - if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + enlarged = (stbi__uint16 *)stbi__malloc(img_len * 2); + if (enlarged == NULL) + return (stbi__uint16 *)stbi__errpuc("outofmem", "Out of memory"); - for (i = 0; i < img_len; ++i) - enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + + orig[i]); // replicate to high and low byte, + // maps 0->0, 255->0xffff - STBI_FREE(orig); - return enlarged; + STBI_FREE(orig); + return enlarged; } -static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) -{ - int row; - size_t bytes_per_row = (size_t)w * bytes_per_pixel; - stbi_uc temp[2048]; - stbi_uc *bytes = (stbi_uc *)image; +static void stbi__vertical_flip(void *image, int w, int h, + int bytes_per_pixel) { + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; - for (row = 0; row < (h>>1); row++) { - stbi_uc *row0 = bytes + row*bytes_per_row; - stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; - // swap row0 with row1 - size_t bytes_left = bytes_per_row; - while (bytes_left) { - size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); - memcpy(temp, row0, bytes_copy); - memcpy(row0, row1, bytes_copy); - memcpy(row1, temp, bytes_copy); - row0 += bytes_copy; - row1 += bytes_copy; - bytes_left -= bytes_copy; - } - } + for (row = 0; row < (h >> 1); row++) { + stbi_uc *row0 = bytes + row * bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1) * bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = + (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } } #ifndef STBI_NO_GIF -static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) -{ - int slice; - int slice_size = w * h * bytes_per_pixel; +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, + int bytes_per_pixel) { + int slice; + int slice_size = w * h * bytes_per_pixel; - stbi_uc *bytes = (stbi_uc *)image; - for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; - } + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } } #endif -static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, + int *y, int *comp, + int req_comp) { + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); - if (result == NULL) - return NULL; + if (result == NULL) + return NULL; - // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. - STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + // it is the responsibility of the loaders to make sure we get either 8 or 16 + // bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); - if (ri.bits_per_channel != 8) { - result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 8; - } + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *)result, *x, *y, + req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } - // @TODO: move stbi__convert_format to here + // @TODO: move stbi__convert_format to here - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); - } + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } - return (unsigned char *) result; + return (unsigned char *)result; } -static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, + int *y, int *comp, + int req_comp) { + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); - if (result == NULL) - return NULL; + if (result == NULL) + return NULL; - // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. - STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + // it is the responsibility of the loaders to make sure we get either 8 or 16 + // bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); - if (ri.bits_per_channel != 16) { - result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 16; - } + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *)result, *x, *y, + req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } - // @TODO: move stbi__convert_format16 to here - // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to + // keep more precision - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); - } + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } - return (stbi__uint16 *) result; + return (stbi__uint16 *)result; } #if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) -static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) -{ - if (stbi__vertically_flip_on_load && result != NULL) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); - } +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, + int req_comp) { + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } } #endif #ifndef STBI_NO_STDIO #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) -STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar( + unsigned int cp, unsigned long flags, const char *str, int cbmb, + wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte( + unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, + char *str, int cbmb, const char *defchar, int *used_default); #endif #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) -STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) -{ - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, + const wchar_t *input) { + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, + (int)bufferlen, NULL, NULL); } #endif -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; +static FILE *stbi__fopen(char const *filename, char const *mode) { + FILE *f; #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) - wchar_t wMode[64]; - wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) - return 0; + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, + sizeof(wFilename) / sizeof(*wFilename))) + return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) - return 0; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, + sizeof(wMode) / sizeof(*wMode))) + return 0; #if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else - f = _wfopen(wFilename, wMode); + f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; + if (0 != fopen_s(&f, filename, mode)) + f = 0; #else - f = fopen(filename, mode); + f = fopen(filename, mode); #endif - return f; + return f; } - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, + int req_comp) { + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) + return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; } -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, + int req_comp) { + unsigned char *result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } -STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint16 *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, + int req_comp) { + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_16bit(&s, x, y, comp, req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } -STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - stbi__uint16 *result; - if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file_16(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, + int req_comp) { + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) + return (stbi_us *)stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f, x, y, comp, req_comp); + fclose(f); + return result; } +#endif //! STBI_NO_STDIO -#endif //!STBI_NO_STDIO - -STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, + int *x, int *y, int *channels_in_file, + int desired_channels) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, + desired_channels); } -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, + void *user, int *x, int *y, + int *channels_in_file, + int desired_channels) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, + desired_channels); } -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, + int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, + void *user, int *x, int *y, int *comp, + int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, + int **delays, int *x, int *y, int *z, + int *comp, int req_comp) { + unsigned char *result; + stbi__context s; + stbi__start_mem(&s, buffer, len); - result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); - if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); - } + result = + (unsigned char *)stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices(result, *x, *y, *z, *comp); + } - return result; + return result; } #endif #ifndef STBI_NO_LINEAR -static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - stbi__result_info ri; - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); - if (hdr_data) - stbi__float_postprocess(hdr_data,x,y,comp,req_comp); - return hdr_data; - } - #endif - data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, + int req_comp) { + unsigned char *data; +#ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s, x, y, comp, req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data, x, y, comp, req_comp); + return hdr_data; + } +#endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", + "Image not of any known type, or corrupt"); } -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, + int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__loadf_main(&s, x, y, comp, req_comp); } -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, + void *user, int *x, int *y, int *comp, + int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, + int req_comp) { + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) + return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; } -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, + int req_comp) { + stbi__context s; + stbi__start_file(&s, f); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #endif // !STBI_NO_STDIO @@ -1494,222 +1576,219 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_ // defined, for API simplicity; if STBI_NO_LINEAR is defined, it always // reports false! -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; +#endif } #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; +STBIDEF int stbi_is_hdr(char const *filename) { + FILE *f = stbi__fopen(filename, "rb"); + int result = 0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; } -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - long pos = ftell(f); - int res; - stbi__context s; - stbi__start_file(&s,f); - res = stbi__hdr_test(&s); - fseek(f, pos, SEEK_SET); - return res; - #else - STBI_NOTUSED(f); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_file(FILE *f) { +#ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s, f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; +#else + STBI_NOTUSED(f); + return 0; +#endif } #endif // !STBI_NO_STDIO -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(clbk); - STBI_NOTUSED(user); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, + void *user) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; +#endif } #ifndef STBI_NO_LINEAR -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; +static float stbi__l2h_gamma = 2.2f, stbi__l2h_scale = 1.0f; -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } #endif -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } +static float stbi__h2l_gamma_i = 1.0f / 2.2f, stbi__h2l_scale_i = 1.0f; +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { + stbi__h2l_gamma_i = 1 / gamma; +} +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { + stbi__h2l_scale_i = 1 / scale; +} ////////////////////////////////////////////////////////////////////////////// // // Common code used by all image loaders // -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; +enum { STBI__SCAN_load = 0, STBI__SCAN_type, STBI__SCAN_header }; -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } +static void stbi__refill_buffer(stbi__context *s) { + int n = (s->io.read)(s->io_user_data, (char *)s->buffer_start, s->buflen); + s->callback_already_read += (int)(s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + 1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } } -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; +stbi_inline static stbi_uc stbi__get8(stbi__context *s) { + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; } -#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && \ + defined(STBI_NO_PNM) // nothing #else -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } - - return s->img_buffer >= s->img_buffer_end; -} -#endif - -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) -// nothing -#else -static void stbi__skip(stbi__context *s, int n) -{ - if (n == 0) return; // already there! - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; -} -#endif - -#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) -// nothing -#else -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; - - memcpy(buffer, s->img_buffer, blen); - - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } - - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else +stbi_inline static int stbi__at_eof(stbi__context *s) { + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) + return 1; + } + + return s->img_buffer >= s->img_buffer_end; } #endif -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && \ + defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && \ + defined(STBI_NO_PIC) // nothing #else -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); +static void stbi__skip(stbi__context *s, int n) { + if (n == 0) + return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && \ + defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { + if (s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char *)buffer + blen, n - blen); + res = (count == (n - blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer + n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && \ + defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) { + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) // nothing #else -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); +static stbi__uint32 stbi__get32be(stbi__context *s) { + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); } #endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing #else -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); +static int stbi__get16le(stbi__context *s) { + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); } #endif #ifndef STBI_NO_BMP -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - z += (stbi__uint32)stbi__get16le(s) << 16; - return z; +static stbi__uint32 stbi__get32le(stbi__context *s) { + stbi__uint32 z = stbi__get16le(s); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings +#define STBI__BYTECAST(x) \ + ((stbi_uc)((x)&255)) // truncate int to byte without warnings -#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && \ + defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && \ + defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing #else ////////////////////////////////////////////////////////////////////////////// @@ -1723,169 +1802,281 @@ static stbi__uint32 stbi__get32le(stbi__context *s) // assume data buffer is malloced, so malloc a new one and free that one // only failure mode is malloc failing -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +static stbi_uc stbi__compute_y(int r, int g, int b) { + return (stbi_uc)(((r * 77) + (g * 150) + (29 * b)) >> 8); } #endif -#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && \ + defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && \ + defined(STBI_NO_PNM) // nothing #else -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, + int req_comp, unsigned int x, + unsigned int y) { + int i, j; + unsigned char *good; - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + if (req_comp == img_n) + return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } + good = (unsigned char *)stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; + for (j = 0; j < (int)y; ++j) { + unsigned char *src = data + j * x * img_n; + unsigned char *dest = good + j * x * req_comp; - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); +#define STBI__COMBO(a, b) ((a)*8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for (i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp + // components; avoid switch per pixel, so use switch per scanline and + // massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { + dest[0] = src[0]; + dest[1] = 255; } - #undef STBI__CASE - } + break; + STBI__CASE(1, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(1, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = 255; + } + break; + STBI__CASE(2, 1) { dest[0] = src[0]; } + break; + STBI__CASE(2, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(2, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = src[1]; + } + break; + STBI__CASE(3, 4) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = 255; + } + break; + STBI__CASE(3, 1) { dest[0] = stbi__compute_y(src[0], src[1], src[2]); } + break; + STBI__CASE(3, 2) { + dest[0] = stbi__compute_y(src[0], src[1], src[2]); + dest[1] = 255; + } + break; + STBI__CASE(4, 1) { dest[0] = stbi__compute_y(src[0], src[1], src[2]); } + break; + STBI__CASE(4, 2) { + dest[0] = stbi__compute_y(src[0], src[1], src[2]); + dest[1] = src[3]; + } + break; + STBI__CASE(4, 3) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + } + break; + default: + STBI_ASSERT(0); + STBI_FREE(data); + STBI_FREE(good); + return stbi__errpuc("unsupported", "Unsupported format conversion"); + } +#undef STBI__CASE + } - STBI_FREE(data); - return good; + STBI_FREE(data); + return good; } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) // nothing #else -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) -{ - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { + return (stbi__uint16)(((r * 77) + (g * 150) + (29 * b)) >> 8); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) // nothing #else -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - stbi__uint16 *good; +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, + int req_comp, unsigned int x, + unsigned int y) { + int i, j; + stbi__uint16 *good; - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + if (req_comp == img_n) + return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - } + good = (stbi__uint16 *)stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *)stbi__errpuc("outofmem", "Out of memory"); + } - for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; + for (j = 0; j < (int)y; ++j) { + stbi__uint16 *src = data + j * x * img_n; + stbi__uint16 *dest = good + j * x * req_comp; - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); +#define STBI__COMBO(a, b) ((a)*8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for (i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp + // components; avoid switch per pixel, so use switch per scanline and + // massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { + dest[0] = src[0]; + dest[1] = 0xffff; } - #undef STBI__CASE - } + break; + STBI__CASE(1, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(1, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = 0xffff; + } + break; + STBI__CASE(2, 1) { dest[0] = src[0]; } + break; + STBI__CASE(2, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(2, 4) { + dest[0] = dest[1] = dest[2] = src[0]; + dest[3] = src[1]; + } + break; + STBI__CASE(3, 4) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = 0xffff; + } + break; + STBI__CASE(3, 1) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); } + break; + STBI__CASE(3, 2) { + dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); + dest[1] = 0xffff; + } + break; + STBI__CASE(4, 1) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); } + break; + STBI__CASE(4, 2) { + dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); + dest[1] = src[3]; + } + break; + STBI__CASE(4, 3) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + } + break; + default: + STBI_ASSERT(0); + STBI_FREE(data); + STBI_FREE(good); + return (stbi__uint16 *)stbi__errpuc("unsupported", + "Unsupported format conversion"); + } +#undef STBI__CASE + } - STBI_FREE(data); - return good; + STBI_FREE(data); + return good; } #endif #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output; - if (!data) return NULL; - output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - } - if (n < comp) { - for (i=0; i < x*y; ++i) { - output[i*comp + n] = data[i*comp + n]/255.0f; - } - } - STBI_FREE(data); - return output; +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { + int i, k, n; + float *output; + if (!data) + return NULL; + output = (float *)stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { + STBI_FREE(data); + return stbi__errpf("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if (comp & 1) + n = comp; + else + n = comp - 1; + for (i = 0; i < x * y; ++i) { + for (k = 0; k < n; ++k) { + output[i * comp + k] = + (float)(pow(data[i * comp + k] / 255.0f, stbi__l2h_gamma) * + stbi__l2h_scale); + } + } + if (n < comp) { + for (i = 0; i < x * y; ++i) { + output[i * comp + n] = data[i * comp + n] / 255.0f; + } + } + STBI_FREE(data); + return output; } #endif #ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output; - if (!data) return NULL; - output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; +#define stbi__float2int(x) ((int)(x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) { + int i, k, n; + stbi_uc *output; + if (!data) + return NULL; + output = (stbi_uc *)stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if (comp & 1) + n = comp; + else + n = comp - 1; + for (i = 0; i < x * y; ++i) { + for (k = 0; k < n; ++k) { + float z = (float)pow(data[i * comp + k] * stbi__h2l_scale_i, + stbi__h2l_gamma_i) * + 255 + + 0.5f; + if (z < 0) + z = 0; + if (z > 255) + z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + if (k < comp) { + float z = data[i * comp + k] * 255 + 0.5f; + if (z < 0) + z = 0; + if (z > 255) + z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + } + STBI_FREE(data); + return output; } #endif @@ -1913,749 +2104,790 @@ static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) #ifndef STBI_NO_JPEG // huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' +typedef struct { + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' } stbi__huffman; -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi__uint16 dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; +typedef struct { + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; + // sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; + // definition of jpeg image component + struct { + int id; + int h, v; + int tq; + int hd, ha; + int dc_pred; - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; + int x, y, w2, h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - int jfif; - int app14_color_transform; // Adobe APP14 tag - int rgb; + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; - int scan_n, order[4]; - int restart_interval, todo; + int scan_n, order[4]; + int restart_interval, todo; -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); + // kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, + const stbi_uc *pcb, const stbi_uc *pcr, int count, + int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, + stbi_uc *in_far, int w, int hs); } stbi__jpeg; -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0; - unsigned int code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; +static int stbi__build_huffman(stbi__huffman *h, int *count) { + int i, j, k = 0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i = 0; i < 16; ++i) + for (j = 0; j < count[i]; ++j) + h->size[k++] = (stbi_uc)(i + 1); + h->size[k] = 0; - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for (j = 1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16)(code++); + if (code - 1 >= (1u << j)) + return stbi__err("bad code lengths", "Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16 - j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i = 0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS - s); + int m = 1 << (FAST_BITS - s); + for (j = 0; j < m; ++j) { + h->fast[c + j] = (stbi_uc)i; } - } - return 1; + } + } + return 1; } // build a table that decodes both magnitude and value of small ACs in // one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) { + int i; + for (i = 0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (~0U << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); - } + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) + k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16)((k * 256) + (run * 16) + (len + magbits)); } - } + } + } } -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - unsigned int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) { + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) + c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char)c; + j->nomore = 1; + return; } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); } // (1 << n) - 1 -static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; +static const stbi__uint32 stbi__bmask[17] = { + 0, 1, 3, 7, 15, 31, 63, 127, 255, + 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535}; // decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) { + unsigned int temp; + int c, k; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } - - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) return -1; - } + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } - if (k > j->code_bits) - return -1; + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k = FAST_BITS + 1;; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + if (k > j->code_bits) + return -1; - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & + stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; } // bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); +stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) { + unsigned int k; + int sgn; + if (j->code_bits < n) + stbi__grow_buffer_unsafe(j); - sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & (sgn - 1)); + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear + // (positive), 1 if MSB set (negative) + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { + unsigned int k; + if (j->code_bits < n) + stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; } -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { + unsigned int k; + if (j->code_bits < 1) + stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; } // given a value that's at position X in the zigzag stream, // where does it appear in the 8x8 matrix coded as row-major? -static const stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; +static const stbi_uc stbi__jpeg_dezigzag[64 + 15] = { + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, + 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, + 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63}; // decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) -{ - int diff,dc,k; - int t; +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], + stbi__huffman *hdc, stbi__huffman *hac, + stbi__int16 *fac, int b, + stbi__uint16 *dequant) { + int diff, dc, k; + int t; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) + return stbi__err("bad huffman code", "Corrupt JPEG"); - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); + // 0 all the ac values now so we can do it 32-bits at a time + memset(data, 0, 64 * sizeof(data[0])); - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short)(dc * dequant[0]); - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c, r, s; + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) + break; // end block + k += 16; } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) * dequant[zig]); } - } while (k < 64); - return 1; + } + } while (k < 64); + return 1; } -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], + stbi__huffman *hdc, int b) { + int diff, dc; + int t; + if (j->spec_end != 0) + return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - diff = t ? stbi__extend_receive(j, t) : 0; + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data, 0, 64 * sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) + return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * (1 << j->succ_low)); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short)(dc * (1 << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short)(1 << j->succ_low); + } + return 1; } // @OPTIMIZE: store non-zigzagged during the decode passes, // and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], + stbi__huffman *hac, + stbi__int16 *fac) { + int k; + if (j->spec_start == 0) + return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - if (j->succ_high == 0) { - int shift = j->succ_low; + if (j->succ_high == 0) { + int shift = j->succ_low; - if (j->eob_run) { - --j->eob_run; - return 1; + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c, r, s; + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) * (1 << shift)); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) * (1 << shift)); + } } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + short bit = (short)(1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit) == 0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { k = j->spec_start; do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * (1 << shift)); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); + int r, s; + int rs = stbi__jpeg_huff_decode( + j, hac); // @OPTIMIZE see if we can use the fast path here, + // advance-by-r is so slow, eh + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) + return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit) == 0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short)s; + break; } - } + --r; + } + } } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients - - short bit = (short) (1 << j->succ_low); - - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else { - // r=15 s=0 should write 16 0s, so we just do - // a run of 15 0s and then write s (which is 0), - // so we don't have to do anything special here - } - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } - - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k++]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } else { - if (r == 0) { - *p = (short) s; - break; - } - --r; - } - } - } while (k <= j->spec_end); - } - } - return 1; + } + } + return 1; } // take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; +stbi_inline static stbi_uc stbi__clamp(int x) { + // trick to use a single test to catch both cases + if ((unsigned int)x > 255) { + if (x < 0) + return 0; + if (x > 255) + return 255; + } + return (stbi_uc)x; } -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) * 4096) +#define stbi__f2f(x) ((int)(((x)*4096 + 0.5))) +#define stbi__fsh(x) ((x)*4096) // derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; +#define STBI__IDCT_1D(s0, s1, s2, s3, s4, s5, s6, s7) \ + int t0, t1, t2, t3, p1, p2, p3, p4, p5, x0, x1, x2, x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2 + p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3 * stbi__f2f(-1.847759065f); \ + t3 = p1 + p2 * stbi__f2f(0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2 + p3); \ + t1 = stbi__fsh(p2 - p3); \ + x0 = t0 + t3; \ + x3 = t0 - t3; \ + x1 = t1 + t2; \ + x2 = t1 - t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0 + t2; \ + p4 = t1 + t3; \ + p1 = t0 + t3; \ + p2 = t1 + t2; \ + p5 = (p3 + p4) * stbi__f2f(1.175875602f); \ + t0 = t0 * stbi__f2f(0.298631336f); \ + t1 = t1 * stbi__f2f(2.053119869f); \ + t2 = t2 * stbi__f2f(3.072711026f); \ + t3 = t3 * stbi__f2f(1.501321110f); \ + p1 = p5 + p1 * stbi__f2f(-0.899976223f); \ + p2 = p5 + p2 * stbi__f2f(-2.562915447f); \ + p3 = p3 * stbi__f2f(-1.961570560f); \ + p4 = p4 * stbi__f2f(-0.390180644f); \ + t3 += p1 + p4; \ + t2 += p2 + p3; \ + t1 += p2 + p4; \ + t0 += p1 + p3; -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) { + int i, val[64], *v = val; + stbi_uc *o; + short *d = data; - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0]*4; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } + // columns + for (i = 0; i < 8; ++i, ++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[8] == 0 && d[16] == 0 && d[24] == 0 && d[32] == 0 && d[40] == 0 && + d[48] == 0 && d[56] == 0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] * 4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[0], d[8], d[16], d[24], d[32], d[40], d[48], d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; + x1 += 512; + x2 += 512; + x3 += 512; + v[0] = (x0 + t3) >> 10; + v[56] = (x0 - t3) >> 10; + v[8] = (x1 + t2) >> 10; + v[48] = (x1 - t2) >> 10; + v[16] = (x2 + t1) >> 10; + v[40] = (x2 - t1) >> 10; + v[24] = (x3 + t0) >> 10; + v[32] = (x3 - t0) >> 10; + } + } - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } + for (i = 0, v = val, o = out; i < 8; ++i, v += 8, o += out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128 << 17); + x1 += 65536 + (128 << 17); + x2 += 65536 + (128 << 17); + x3 += 65536 + (128 << 17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0 + t3) >> 17); + o[7] = stbi__clamp((x0 - t3) >> 17); + o[1] = stbi__clamp((x1 + t2) >> 17); + o[6] = stbi__clamp((x1 - t2) >> 17); + o[2] = stbi__clamp((x2 + t1) >> 17); + o[5] = stbi__clamp((x2 - t1) >> 17); + o[3] = stbi__clamp((x3 + t0) >> 17); + o[4] = stbi__clamp((x3 - t0) >> 17); + } } #ifdef STBI_SSE2 // sse2 integer IDCT. not the fastest possible implementation but it // produces bit-identical results to the generic C version so it's // fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) +// dot product constant: even elems=x, odd elems=y +#define dct_const(x, y) _mm_setr_epi16((x), (y), (x), (y), (x), (y), (x), (y)) - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) +// out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) +// out(1) = c1[even]*x + c1[odd]*y +#define dct_rot(out0, out1, x, y, c0, c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x), (y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x), (y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) +// out = in << 12 (in 16-bit, out 32-bit) +#define dct_widen(out, in) \ + __m128i out##_l = \ + _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = \ + _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) +// wide add +#define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) +// wide sub +#define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } +// butterfly a/b, add bias, then shift by "s" and pack +#define dct_bfly32o(out0, out1, a, b, bias, s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = \ + _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = \ + _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) +// 8-bit interleave step (for transposes) +#define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) +// 16-bit interleave step (for transposes) +#define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } +#define dct_pass(bias, shift) \ + { \ + /* even part */ \ + dct_rot(t2e, t3e, row2, row6, rot0_0, rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o, y2o, row7, row3, rot2_0, rot2_1); \ + dct_rot(y1o, y3o, row5, row1, rot3_0, rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o, y5o, sum17, sum35, rot1_0, rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0, row7, x0, x7, bias, shift); \ + dct_bfly32o(row1, row6, x1, x6, bias, shift); \ + dct_bfly32o(row2, row5, x2, x5, bias, shift); \ + dct_bfly32o(row3, row4, x3, x4, bias, shift); \ + } - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), + stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f(0.765366865f), + stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), + stbi__f2f(1.175875602f)); + __m128i rot1_1 = + dct_const(stbi__f2f(1.175875602f), + stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f(0.298631336f), + stbi__f2f(-1.961570560f)); + __m128i rot2_1 = + dct_const(stbi__f2f(-1.961570560f), + stbi__f2f(-1.961570560f) + stbi__f2f(3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f(2.053119869f), + stbi__f2f(-0.390180644f)); + __m128i rot3_1 = + dct_const(stbi__f2f(-0.390180644f), + stbi__f2f(-0.390180644f) + stbi__f2f(1.501321110f)); - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128 << 17)); - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + // load + row0 = _mm_load_si128((const __m128i *)(data + 0 * 8)); + row1 = _mm_load_si128((const __m128i *)(data + 1 * 8)); + row2 = _mm_load_si128((const __m128i *)(data + 2 * 8)); + row3 = _mm_load_si128((const __m128i *)(data + 3 * 8)); + row4 = _mm_load_si128((const __m128i *)(data + 4 * 8)); + row5 = _mm_load_si128((const __m128i *)(data + 5 * 8)); + row6 = _mm_load_si128((const __m128i *)(data + 6 * 8)); + row7 = _mm_load_si128((const __m128i *)(data + 7 * 8)); - // column pass - dct_pass(bias_0, 10); + // column pass + dct_pass(bias_0, 10); - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } - // row pass - dct_pass(bias_1, 17); + // row pass + dct_pass(bias_1, 17); - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } + // store + _mm_storel_epi64((__m128i *)out, p0); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p0, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p2); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p2, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p1); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p1, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p3); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p3, 0x4e)); + } #undef dct_const #undef dct_rot @@ -2674,198 +2906,236 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) // NEON integer IDCT. should produce bit-identical // results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f(0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f(1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f(0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f(2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f(3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f(1.501321110f)); -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) // wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) // wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) // butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } +#define dct_bfly32o(out0, out1, a, b, shiftop, s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0, row7, x0, x7, shiftop, shift); \ + dct_bfly32o(row1, row6, x1, x6, shiftop, shift); \ + dct_bfly32o(row2, row5, x2, x5, shiftop, shift); \ + dct_bfly32o(row3, row4, x3, x4, shiftop, shift); \ + } - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); + // load + row0 = vld1q_s16(data + 0 * 8); + row1 = vld1q_s16(data + 1 * 8); + row2 = vld1q_s16(data + 2 * 8); + row3 = vld1q_s16(data + 3 * 8); + row4 = vld1q_s16(data + 4 * 8); + row5 = vld1q_s16(data + 5 * 8); + row6 = vld1q_s16(data + 6 * 8); + row7 = vld1q_s16(data + 7 * 8); - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - // column pass - dct_pass(vrshrn_n_s32, 10); + // column pass + dct_pass(vrshrn_n_s32, 10); - // 16bit 8x8 transpose - { + // 16bit 8x8 transpose + { // these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. // whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } +#define dct_trn16(x, y) \ + { \ + int16x8x2_t t = vtrnq_s16(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn32(x, y) \ + { \ + int32x4x2_t t = \ + vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); \ + x = vreinterpretq_s16_s32(t.val[0]); \ + y = vreinterpretq_s16_s32(t.val[1]); \ + } +#define dct_trn64(x, y) \ + { \ + int16x8_t x0 = x; \ + int16x8_t y0 = y; \ + x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); \ + y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); \ + } - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); #undef dct_trn16 #undef dct_trn32 #undef dct_trn64 - } + } - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) \ + { \ + uint8x8x2_t t = vtrn_u8(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn8_16(x, y) \ + { \ + uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); \ + x = vreinterpret_u8_u16(t.val[0]); \ + y = vreinterpret_u8_u16(t.val[1]); \ + } +#define dct_trn8_32(x, y) \ + { \ + uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); \ + x = vreinterpret_u8_u32(t.val[0]); \ + y = vreinterpret_u8_u32(t.val[1]); \ + } - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); + // store + vst1_u8(out, p0); + out += out_stride; + vst1_u8(out, p1); + out += out_stride; + vst1_u8(out, p2); + out += out_stride; + vst1_u8(out, p3); + out += out_stride; + vst1_u8(out, p4); + out += out_stride; + vst1_u8(out, p5); + out += out_stride; + vst1_u8(out, p6); + out += out_stride; + vst1_u8(out, p7); #undef dct_trn8_8 #undef dct_trn8_16 #undef dct_trn8_32 - } + } #undef dct_long_mul #undef dct_long_mac @@ -2878,1146 +3148,1297 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) #endif // STBI_NEON -#define STBI__MARKER_none 0xff +#define STBI__MARKER_none 0xff // if there's a pending marker from the entropy stream, return that // otherwise, fetch from the stream and get a marker. if there's no // marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); // consume repeated 0xff fill bytes - return x; +static stbi_uc stbi__get_marker(stbi__jpeg *j) { + stbi_uc x; + if (j->marker != STBI__MARKER_none) { + x = j->marker; + j->marker = STBI__MARKER_none; + return x; + } + x = stbi__get8(j->s); + if (x != 0xff) + return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; } // in each scan, we'll have scan_n components, and the order // of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) // after a restart interval, stbi__jpeg_reset the entropy decoder and // the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels +static void stbi__jpeg_reset(stbi__jpeg *j) { + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = + j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels } -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) { + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i, j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc + z->img_comp[n].hd, + z->huff_ac + ha, z->fast_ac[ha], n, + z->dequant[z->img_comp[n].tq])) + return 0; + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + + i * 8, + z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } -} - -static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; -} - -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } -} - -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); - - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; - - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4, sixteen = (p != 0); - int t = q & 15,i; - if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); - - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); - L -= (sixteen ? 129 : 65); - } - return L==0; - - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } - - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - L = stbi__get16be(z->s); - if (L < 2) { - if (m == 0xFE) - return stbi__err("bad COM len","Corrupt JPEG"); - else - return stbi__err("bad APP len","Corrupt JPEG"); - } - L -= 2; - - if (m == 0xE0 && L >= 5) { // JFIF APP0 segment - static const unsigned char tag[5] = {'J','F','I','F','\0'}; - int ok = 1; - int i; - for (i=0; i < 5; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 5; - if (ok) - z->jfif = 1; - } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment - static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; - int ok = 1; - int i; - for (i=0; i < 6; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 6; - if (ok) { - stbi__get8(z->s); // version - stbi__get16be(z->s); // flags0 - stbi__get16be(z->s); // flags1 - z->app14_color_transform = stbi__get8(z->s); // color transform - L -= 6; - } - } - - stbi__skip(z->s, L); return 1; - } + } else { // interleaved + int i, j, k, x, y; + STBI_SIMD_ALIGN(short, data[64]); + for (j = 0; j < z->img_mcu_y; ++j) { + for (i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y = 0; y < z->img_comp[n].v; ++y) { + for (x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x) * 8; + int y2 = (j * z->img_comp[n].v + y) * 8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, + z->huff_dc + z->img_comp[n].hd, + z->huff_ac + ha, z->fast_ac[ha], n, + z->dequant[z->img_comp[n].tq])) + return 0; + z->idct_block_kernel(z->img_comp[n].data + + z->img_comp[n].w2 * y2 + x2, + z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i, j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + short *data = + z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc( + z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], + z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i, j, k, x, y; + for (j = 0; j < z->img_mcu_y; ++j) { + for (i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y = 0; y < z->img_comp[n].v; ++y) { + for (x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x); + int y2 = (j * z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc( + z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} - return stbi__err("unknown marker","Corrupt JPEG"); +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) { + int i; + for (i = 0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) { + if (z->progressive) { + // dequantize and idct the data + int i, j, n; + for (n = 0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + short *data = + z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + + i * 8, + z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) { + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker", "Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) + return stbi__err("bad DRI len", "Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s) - 2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15, i; + if (p != 0 && p != 1) + return stbi__err("bad DQT type", "Corrupt JPEG"); + if (t > 3) + return stbi__err("bad DQT table", "Corrupt JPEG"); + + for (i = 0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = + (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L == 0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s) - 2; + while (L > 0) { + stbi_uc *v; + int sizes[16], i, n = 0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) + return stbi__err("bad DHT header", "Corrupt JPEG"); + for (i = 0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc + th, sizes)) + return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac + th, sizes)) + return 0; + v = z->huff_ac[th].values; + } + for (i = 0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L == 0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len", "Corrupt JPEG"); + else + return stbi__err("bad APP len", "Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J', 'F', 'I', 'F', '\0'}; + int ok = 1; + int i; + for (i = 0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A', 'd', 'o', 'b', 'e', '\0'}; + int ok = 1; + int i; + for (i = 0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker", "Corrupt JPEG"); } // after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } +static int stbi__process_scan_header(stbi__jpeg *z) { + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int)z->s->img_n) + return stbi__err("bad SOS component count", "Corrupt JPEG"); + if (Ls != 6 + 2 * z->scan_n) + return stbi__err("bad SOS len", "Corrupt JPEG"); + for (i = 0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) + return 0; // no match + z->img_comp[which].hd = q >> 4; + if (z->img_comp[which].hd > 3) + return stbi__err("bad DC huff", "Corrupt JPEG"); + z->img_comp[which].ha = q & 15; + if (z->img_comp[which].ha > 3) + return stbi__err("bad AC huff", "Corrupt JPEG"); + z->order[i] = which; + } - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || + z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) + return stbi__err("bad SOS", "Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) + return stbi__err("bad SOS", "Corrupt JPEG"); + z->spec_end = 63; + } + } - return 1; + return 1; } -static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) -{ - int i; - for (i=0; i < ncomp; ++i) { - if (z->img_comp[i].raw_data) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - z->img_comp[i].data = NULL; - } - if (z->img_comp[i].raw_coeff) { - STBI_FREE(z->img_comp[i].raw_coeff); - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].coeff = 0; - } - if (z->img_comp[i].linebuf) { - STBI_FREE(z->img_comp[i].linebuf); - z->img_comp[i].linebuf = NULL; - } - } - return why; -} - -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - c = stbi__get8(s); - if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); - s->img_n = c; - for (i=0; i < c; ++i) { +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) { + int i; + for (i = 0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } - - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); - - z->rgb = 0; - for (i=0; i < s->img_n; ++i) { - static const unsigned char rgb[3] = { 'R', 'G', 'B' }; - z->img_comp[i].id = stbi__get8(s); - if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) - ++z->rgb; - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } - - if (scan != STBI__SCAN_load) return 1; - - if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); - - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } - - // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios - // and I've never seen a non-corrupted JPEG file actually use them - for (i=0; i < s->img_n; ++i) { - if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); - if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); - } - - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - // these sizes can't be more than 17 bits - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; - - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - // - // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) - // so these muls can't overflow with 32-bit ints (which we require) - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); z->img_comp[i].linebuf = NULL; - z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); - if (z->img_comp[i].raw_data == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - if (z->progressive) { - // w2, h2 are multiples of 8 (see above) - z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; - z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; - z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); - if (z->img_comp[i].raw_coeff == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } - } + } + } + return why; +} - return 1; +static int stbi__process_frame_header(stbi__jpeg *z, int scan) { + stbi__context *s = z->s; + int Lf, p, i, q, h_max = 1, v_max = 1, c; + Lf = stbi__get16be(s); + if (Lf < 11) + return stbi__err("bad SOF len", "Corrupt JPEG"); // JPEG + p = stbi__get8(s); + if (p != 8) + return stbi__err("only 8-bit", + "JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); + if (s->img_y == 0) + return stbi__err( + "no header height", + "JPEG format not supported: delayed height"); // Legal, but we don't + // handle it--but neither + // does IJG + s->img_x = stbi__get16be(s); + if (s->img_x == 0) + return stbi__err("0 width", "Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) + return stbi__err("too large", "Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) + return stbi__err("too large", "Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) + return stbi__err("bad component count", "Corrupt JPEG"); + s->img_n = c; + for (i = 0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8 + 3 * s->img_n) + return stbi__err("bad SOF len", "Corrupt JPEG"); + + z->rgb = 0; + for (i = 0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = {'R', 'G', 'B'}; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); + if (!z->img_comp[i].h || z->img_comp[i].h > 4) + return stbi__err("bad H", "Corrupt JPEG"); + z->img_comp[i].v = q & 15; + if (!z->img_comp[i].v || z->img_comp[i].v > 4) + return stbi__err("bad V", "Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); + if (z->img_comp[i].tq > 3) + return stbi__err("bad TQ", "Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) + return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) + return stbi__err("too large", "Image too large to decode"); + + for (i = 0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) + h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) + v_max = z->img_comp[i].v; + } + + // check that plane subsampling factors are integer ratios; our resamplers + // can't deal with fractional ratios and I've never seen a non-corrupted JPEG + // file actually use them + for (i = 0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) + return stbi__err("bad H", "Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) + return stbi__err("bad V", "Corrupt JPEG"); + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w - 1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h - 1) / z->img_mcu_h; + + for (i = 0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max - 1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max - 1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked + // earlier) so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = + stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i + 1, + stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = + (stbi_uc *)(((size_t)z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3( + z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components( + z, i + 1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = + (short *)(((size_t)z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; } // use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) -#define stbi__SOF_progressive(x) ((x) == 0xc2) +#define stbi__SOF_progressive(x) ((x) == 0xc2) -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->jfif = 0; - z->app14_color_transform = -1; // valid values are 0,1,2 - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) + return stbi__err("no SOI", "Corrupt JPEG"); + if (scan == STBI__SCAN_type) + return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z, m)) + return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) + return stbi__err("no SOF", "Corrupt JPEG"); m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) + return 0; + return 1; } // decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - for (m = 0; m < 4; m++) { - j->img_comp[m].raw_data = NULL; - j->img_comp[m].raw_coeff = NULL; - } - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else if (stbi__DNL(m)) { - int Ld = stbi__get16be(j->s); - stbi__uint32 NL = stbi__get16be(j->s); - if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); - if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); - } else { - if (!stbi__process_marker(j, m)) return 0; +static int stbi__decode_jpeg_image(stbi__jpeg *j) { + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) + return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) + return 0; + if (!stbi__parse_entropy_coded_data(j)) + return 0; + if (j->marker == STBI__MARKER_none) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below + // will fail and we'll eventually return 0 } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) + return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) + return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) + return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; } // static jfif-centered resampling (across block boundaries) typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); + int w, int hs); -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) +#define stbi__div4(x) ((stbi_uc)((x) >> 2)) -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, + int w, int hs) { + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; } -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; +static stbi_uc *stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, + stbi_uc *in_far, int w, int hs) { + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i = 0; i < w; ++i) + out[i] = stbi__div4(3 * in_near[i] + in_far[i] + 2); + return out; } -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; +static stbi_uc *stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, + stbi_uc *in_far, int w, int hs) { + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; + out[0] = input[0]; + out[1] = stbi__div4(input[0] * 3 + input[1] + 2); + for (i = 1; i < w - 1; ++i) { + int n = 3 * input[i] + 2; + out[i * 2 + 0] = stbi__div4(n + input[i - 1]); + out[i * 2 + 1] = stbi__div4(n + input[i + 1]); + } + out[i * 2 + 0] = stbi__div4(input[w - 2] * 3 + input[w - 1] + 2); + out[i * 2 + 1] = input[w - 1]; - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); - return out; + return out; } -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) +#define stbi__div16(x) ((stbi_uc)((x) >> 4)) -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, + stbi_uc *in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i, t0, t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + t1 = 3 * in_near[0] + in_far[0]; + out[0] = stbi__div4(t1 + 2); + for (i = 1; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, + stbi_uc *in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i = 0, t0, t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } + if (w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { + t1 = 3 * in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w - 1) & ~7); i += 8) { #if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *)(in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *)(in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = + _mm_insert_epi16(nxt0, 3 * in_near[i + 8] + in_far[i + 8], 7); - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *)(out + i * 2), outv); #elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = + vsetq_lane_s16(3 * in_near[i + 8] + in_far[i + 8], nxt0, 7); - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i * 2, o); #endif - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } + // "previous" value for next iter + t1 = 3 * in_near[i + 7] + in_far[i + 7]; + } - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #endif -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, + stbi_uc *in_far, int w, int hs) { + // resample with nearest-neighbor + int i, j; + STBI_NOTUSED(in_far); + for (i = 0; i < w; ++i) + for (j = 0; j < hs; ++j) + out[i * hs + j] = in_near[i]; + return out; } // this is a reduced-precision calculation of YCbCr-to-RGB introduced // to make sure the code produces the same results in both SIMD and scalar -#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } +#define stbi__float2fixed(x) (((int)((x)*4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, + const stbi_uc *pcb, const stbi_uc *pcr, + int count, int step) { + int i; + for (i = 0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + (cr * -stbi__float2fixed(0.71414f)) + + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned)r > 255) { + if (r < 0) + r = 0; + else + r = 255; + } + if ((unsigned)g > 255) { + if (g < 0) + g = 0; + else + g = 255; + } + if ((unsigned)b > 255) { + if (b < 0) + b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, + stbi_uc const *pcb, stbi_uc const *pcr, + int count, int step) { + int i = 0; #ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16((short)(1.40200f * 4096.0f + 0.5f)); + __m128i cr_const1 = _mm_set1_epi16(-(short)(0.71414f * 4096.0f + 0.5f)); + __m128i cb_const0 = _mm_set1_epi16(-(short)(0.34414f * 4096.0f + 0.5f)); + __m128i cb_const1 = _mm_set1_epi16((short)(1.77200f * 4096.0f + 0.5f)); + __m128i y_bias = _mm_set1_epi8((char)(unsigned char)128); + __m128i xw = _mm_set1_epi16(255); // alpha channel - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + for (; i + 7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *)(y + i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *)(pcr + i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *)(pcb + i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } + // store + _mm_storeu_si128((__m128i *)(out + 0), o0); + _mm_storeu_si128((__m128i *)(out + 16), o1); + out += 32; + } + } #endif #ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16((short)(1.40200f * 4096.0f + 0.5f)); + int16x8_t cr_const1 = vdupq_n_s16(-(short)(0.71414f * 4096.0f + 0.5f)); + int16x8_t cb_const0 = vdupq_n_s16(-(short)(0.34414f * 4096.0f + 0.5f)); + int16x8_t cb_const1 = vdupq_n_s16((short)(1.77200f * 4096.0f + 0.5f)); - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + for (; i + 7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8 * 4; + } + } #endif - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + cr * -stbi__float2fixed(0.71414f) + + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned)r > 255) { + if (r < 0) + r = 0; + else + r = 255; + } + if ((unsigned)g > 255) { + if (g < 0) + g = 0; + else + g = 255; + } + if ((unsigned)b > 255) { + if (b < 0) + b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #endif // set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; +static void stbi__setup_jpeg(stbi__jpeg *j) { + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; #ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } #endif #ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; #endif } // clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - stbi__free_jpeg_components(j, j->s->img_n, 0); +static void stbi__cleanup_jpeg(stbi__jpeg *j) { + stbi__free_jpeg_components(j, j->s->img_n, 0); } -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on +typedef struct { + resample_row_func resample; + stbi_uc *line0, *line1; + int hs, vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on } stbi__resample; // fast 0..255 * 0..255 => 0..255 rounded multiplication -static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) -{ - unsigned int t = x*y + 128; - return (stbi_uc) ((t + (t >>8)) >> 8); +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) { + unsigned int t = x * y + 128; + return (stbi_uc)((t + (t >> 8)) >> 8); } -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n, is_rgb; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, + int *comp, int req_comp) { + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + // validate req_comp + if (req_comp < 0 || req_comp > 4) + return stbi__errpuc("bad req_comp", "Internal error"); - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { + stbi__cleanup_jpeg(z); + return NULL; + } - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + is_rgb = z->s->img_n == 3 && + (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); - if (z->s->img_n == 3 && n < 3 && !is_rgb) - decode_n = 1; - else - decode_n = z->s->img_n; + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; - // nothing to do if no components requested; check this now to avoid - // accessing uninitialized coutput[0] later - if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { + stbi__cleanup_jpeg(z); + return NULL; + } - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + // resample and color-convert + { + int k; + unsigned int i, j; + stbi_uc *output; + stbi_uc *coutput[4] = {NULL, NULL, NULL, NULL}; - stbi__resample res_comp[4]; + stbi__resample res_comp[4]; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; + for (k = 0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } - - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; - - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *)stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("outofmem", "Out of memory"); } - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs - 1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - if (is_rgb) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = y[i]; - out[1] = coutput[1][i]; - out[2] = coutput[2][i]; - out[3] = 255; - out += n; - } - } else { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else if (z->s->img_n == 4) { - if (z->app14_color_transform == 0) { // CMYK - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(coutput[0][i], m); - out[1] = stbi__blinn_8x8(coutput[1][i], m); - out[2] = stbi__blinn_8x8(coutput[2][i], m); - out[3] = 255; - out += n; - } - } else if (z->app14_color_transform == 2) { // YCCK - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(255 - out[0], m); - out[1] = stbi__blinn_8x8(255 - out[1], m); - out[2] = stbi__blinn_8x8(255 - out[2], m); - out += n; - } - } else { // YCbCr + alpha? Ignore the fourth channel for now - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - if (is_rgb) { - if (n == 1) - for (i=0; i < z->s->img_x; ++i) - *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - else { - for (i=0; i < z->s->img_x; ++i, out += 2) { - out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - out[1] = 255; - } - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); - stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); - stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); - out[0] = stbi__compute_y(r, g, b); - out[1] = 255; - out += n; - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); - out[1] = 255; - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } - } - } - } + if (r->hs == 1 && r->vs == 1) + r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) + r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) + r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) + r->resample = z->resample_row_hv_2_kernel; + else + r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *)stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output - return output; - } + return stbi__errpuc("outofmem", "Out of memory"); + } + + // now go ahead and resample + for (j = 0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k = 0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = + r->resample(z->img_comp[k].linebuf, y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i = 0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, + n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, + n); + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, + n); + } + } else + for (i = 0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i = 0; i < z->s->img_x; ++i) + *out++ = + stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i = 0; i < z->s->img_x; ++i, out += 2) { + out[0] = + stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i = 0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i = 0; i < z->s->img_x; ++i) + out[i] = y[i]; + else + for (i = 0; i < z->s->img_x; ++i) { + *out++ = y[i]; + *out++ = 255; + } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) + *comp = + z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } } -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - unsigned char* result; - stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__errpuc("outofmem", "Out of memory"); - STBI_NOTUSED(ri); - j->s = s; - stbi__setup_jpeg(j); - result = load_jpeg_image(j, x,y,comp,req_comp); - STBI_FREE(j); - return result; +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri) { + unsigned char *result; + stbi__jpeg *j = (stbi__jpeg *)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) + return stbi__errpuc("outofmem", "Out of memory"); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x, y, comp, req_comp); + STBI_FREE(j); + return result; } -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - if (!j) return stbi__err("outofmem", "Out of memory"); - j->s = s; - stbi__setup_jpeg(j); - r = stbi__decode_jpeg_header(j, STBI__SCAN_type); - stbi__rewind(s); - STBI_FREE(j); - return r; +static int stbi__jpeg_test(stbi__context *s) { + int r; + stbi__jpeg *j = (stbi__jpeg *)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) + return stbi__err("outofmem", "Out of memory"); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; } -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; - return 1; +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) { + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind(j->s); + return 0; + } + if (x) + *x = j->s->img_x; + if (y) + *y = j->s->img_y; + if (comp) + *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; } -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - int result; - stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - if (!j) return stbi__err("outofmem", "Out of memory"); - j->s = s; - result = stbi__jpeg_info_raw(j, x, y, comp); - STBI_FREE(j); - return result; +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { + int result; + stbi__jpeg *j = (stbi__jpeg *)(stbi__malloc(sizeof(stbi__jpeg))); + if (!j) + return stbi__err("outofmem", "Out of memory"); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; } #endif @@ -4031,84 +4452,82 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_ZLIB // fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) #define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[STBI__ZNSYMS]; - stbi__uint16 value[STBI__ZNSYMS]; +typedef struct { + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); +stbi_inline static int stbi__bitreverse16(int n) { + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); return n; } -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); +stbi_inline static int stbi__bit_reverse(int v, int bits) { + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16 - bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, + int num) { + int i, k = 0; + int code, next_code[16], sizes[17]; - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i = 0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i = 1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i = 1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16)code; + z->firstsymbol[i] = (stbi__uint16)k; + code = (code + sizes[i]); + if (sizes[i]) + if (code - 1 >= (1 << i)) + return stbi__err("bad codelengths", "Corrupt PNG"); + z->maxcode[i] = code << (16 - i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i = 0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16)((s << 9) | i); + z->size[c] = (stbi_uc)s; + z->value[c] = (stbi__uint16)i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s], s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } } - } - return 1; + ++next_code[s]; + } + } + return 1; } // zlib-from-memory implementation for PNG reading @@ -4117,277 +4536,313 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int // we require PNG read all the IDATs and combine them into a single // memory buffer -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; +typedef struct { + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; - stbi__zhuffman z_length, z_distance; + stbi__zhuffman z_length, z_distance; } stbi__zbuf; -stbi_inline static int stbi__zeof(stbi__zbuf *z) -{ - return (z->zbuffer >= z->zbuffer_end); +stbi_inline static int stbi__zeof(stbi__zbuf *z) { + return (z->zbuffer >= z->zbuffer_end); } -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - return stbi__zeof(z) ? 0 : *z->zbuffer++; +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { + return stbi__zeof(z) ? 0 : *z->zbuffer++; } -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - if (z->code_buffer >= (1U << z->num_bits)) { - z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ - return; - } - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); +static void stbi__fill_bits(stbi__zbuf *z) { + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int)stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); } -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) { + unsigned int k; + if (z->num_bits < n) + stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; } -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s >= 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! - if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) { + int b, s, k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s = STBI__ZFAST_BITS + 1;; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) + return -1; // invalid code! + // code size is s, so: + b = (k >> (16 - s)) - z->firstcode[s] + z->firstsymbol[s]; + if (b >= STBI__ZNSYMS) + return -1; // some data was corrupt somewhere! + if (z->size[b] != s) + return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; } -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) { - if (stbi__zeof(a)) { - return -1; /* report error for unexpected end of data. */ - } - stbi__fill_bits(a); - } - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { + int b, s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); } -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +static int stbi__zexpand(stbi__zbuf *z, char *zout, + int n) // need to make room for n bytes { - char *q; - unsigned int cur, limit, old_limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (unsigned int) (z->zout - z->zout_start); - limit = old_limit = (unsigned) (z->zout_end - z->zout_start); - if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); - while (cur + n > limit) { - if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); - limit *= 2; - } - q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); - STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) + return stbi__err("output buffer limit", "Corrupt PNG"); + cur = (unsigned int)(z->zout - z->zout_start); + limit = old_limit = (unsigned)(z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned)n) + return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if (limit > UINT_MAX / 2) + return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *)STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) + return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; } static const int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; -static const int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; +static const int stbi__zlength_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 0, 0, 0}; -static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; +static const int stbi__zdist_base[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; -static const int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; +static const int stbi__zdist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; +static int stbi__parse_huffman_block(stbi__zbuf *a) { + char *zout = a->zout; + for (;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) + return stbi__err("bad huffman code", + "Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) + return 0; + zout = a->zout; + } + *zout++ = (char)z; + } else { + stbi_uc *p; + int len, dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) + len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) + return stbi__err("bad huffman code", "Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) + dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) + return stbi__err("bad dist", "Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) + return 0; + zout = a->zout; + } + p = (stbi_uc *)(zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { + do + *zout++ = v; + while (--len); + } } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } + if (len) { + do + *zout++ = *p++; + while (--len); + } } - } + } + } } -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; +static int stbi__compute_huffman_codes(stbi__zbuf *a) { + static const stbi_uc length_dezigzag[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286 + 32 + 137]; // padding for maximum single op + stbi_uc codelength_sizes[19]; + int i, n; - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; + int hlit = stbi__zreceive(a, 5) + 257; + int hdist = stbi__zreceive(a, 5) + 1; + int hclen = stbi__zreceive(a, 4) + 4; + int ntot = hlit + hdist; - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i = 0; i < hclen; ++i) { + int s = stbi__zreceive(a, 3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc)s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) + return 0; - n = 0; - while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else { - stbi_uc fill = 0; - if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) { - c = stbi__zreceive(a,3)+3; - } else if (c == 18) { - c = stbi__zreceive(a,7)+11; - } else { - return stbi__err("bad codelengths", "Corrupt PNG"); - } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); - n += c; + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) + return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc)c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a, 2) + 3; + if (n == 0) + return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n - 1]; + } else if (c == 17) { + c = stbi__zreceive(a, 3) + 3; + } else if (c == 18) { + c = stbi__zreceive(a, 7) + 11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); } - } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; + if (ntot - n < c) + return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes + n, fill, c); + n += c; + } + } + if (n != ntot) + return stbi__err("bad codelengths", "Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) + return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes + hlit, hdist)) + return 0; + return 1; } -static int stbi__parse_uncompressed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; +static int stbi__parse_uncompressed_block(stbi__zbuf *a) { + stbi_uc header[4]; + int len, nlen, k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = + (stbi_uc)(a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) + return stbi__err("zlib corrupt", "Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) + return stbi__err("zlib corrupt", "Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) + return stbi__err("read past buffer", "Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) + return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; } -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; +static int stbi__parse_zlib_header(stbi__zbuf *a) { + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) + return stbi__err("bad zlib header", "Corrupt PNG"); // zlib spec + if ((cmf * 256 + flg) % 31 != 0) + return stbi__err("bad zlib header", "Corrupt PNG"); // zlib spec + if (flg & 32) + return stbi__err("no preset dict", + "Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) + return stbi__err("bad compression", + "Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; } -static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = -{ - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 -}; -static const stbi_uc stbi__zdefault_distance[32] = -{ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 -}; +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8}; +static const stbi_uc stbi__zdefault_distance[32] = { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; /* Init algorithm: { @@ -4401,117 +4856,132 @@ Init algorithm: } */ -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) { + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) + return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a, 1); + type = stbi__zreceive(a, 2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) + return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length, stbi__zdefault_length, + STBI__ZNSYMS)) + return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) + return 0; } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; + if (!stbi__compute_huffman_codes(a)) + return 0; } - } while (!final); - return 1; + if (!stbi__parse_huffman_block(a)) + return 0; + } + } while (!final); + return 1; } -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, + int parse_header) { + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; - return stbi__parse_zlib(a, parse_header); + return stbi__parse_zlib(a, parse_header); } -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, + int initial_size, int *outlen) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(initial_size); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, + int *outlen) { + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); } -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, + int len, + int initial_size, + int *outlen, + int parse_header) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(initial_size); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, + char const *ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc *)ibuffer; + a.zbuffer_end = (stbi_uc *)ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int)(a.zout - a.zout_start); + else + return -1; } -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, + int *outlen) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(16384); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, + const char *ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc *)ibuffer; + a.zbuffer_end = (stbi_uc *)ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int)(a.zout - a.zout_start); + else + return -1; } #endif @@ -4526,1131 +4996,1361 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char // - uses stb_zlib, a PD zlib implementation with fast huffman decoding #ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; +typedef struct { + stbi__uint32 length; + stbi__uint32 type; } stbi__pngchunk; -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) { + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; } -static int stbi__check_png_header(stbi__context *s) -{ - static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; +static int stbi__check_png_header(stbi__context *s) { + static const stbi_uc png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + int i; + for (i = 0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) + return stbi__err("bad png sig", "Not a PNG"); + return 1; } -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; - int depth; +typedef struct { + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; } stbi__png; - enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first + STBI__F_none = 0, + STBI__F_sub = 1, + STBI__F_up = 2, + STBI__F_avg = 3, + STBI__F_paeth = 4, + // synthetic filters used for first scanline to avoid needing a dummy row of + // 0s + STBI__F_avg_first, + STBI__F_paeth_first }; -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; +static stbi_uc first_row_filter[5] = {STBI__F_none, STBI__F_sub, STBI__F_none, + STBI__F_avg_first, STBI__F_paeth_first}; -static int stbi__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; - if (pb <= pc) return b; - return c; +static int stbi__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; + if (pb <= pc) + return b; + return c; } -static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static const stbi_uc stbi__depth_scale_table[9] = {0, 0xff, 0x55, 0, 0x11, + 0, 0, 0, 0x01}; // create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - int bytes = (depth == 16? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, + stbi__uint32 raw_len, int out_n, + stbi__uint32 x, stbi__uint32 y, int depth, + int color) { + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i, j, stride = x * out_n * bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; + int output_bytes = out_n * bytes; + int filter_bytes = img_n * bytes; + int width = x; - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n + 1); + a->out = (stbi_uc *)stbi__malloc_mad3( + x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) + return stbi__err("outofmem", "Out of memory"); - if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) + return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; - // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, - // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), - // so just check for raw_len < img_len always. - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + // we used to check for exact match between raw_len and img_len on + // non-interlaced PNGs, but issue #276 reported a PNG in the wild that had + // extra data at the end (all zeros), so just check for raw_len < img_len + // always. + if (raw_len < img_len) + return stbi__err("not enough pixels", "Corrupt PNG"); - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; - int filter = *raw++; + for (j = 0; j < y; ++j) { + stbi_uc *cur = a->out + stride * j; + stbi_uc *prior; + int filter = *raw++; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); + if (filter > 4) + return stbi__err("invalid filter", "Corrupt PNG"); - if (depth < 8) { - if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; + if (depth < 8) { + if (img_width_bytes > x) + return stbi__err("invalid width", "Corrupt PNG"); + cur += + x * out_n - img_width_bytes; // store output to the rightmost img_len + // bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = + cur - + stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) + filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k = 0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none: + cur[k] = raw[k]; + break; + case STBI__F_sub: + cur[k] = raw[k]; + break; + case STBI__F_up: + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + cur[k] = STBI__BYTECAST(raw[k] + (prior[k] >> 1)); + break; + case STBI__F_paeth: + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0, prior[k], 0)); + break; + case STBI__F_avg_first: + cur[k] = raw[k]; + break; + case STBI__F_paeth_first: + cur[k] = raw[k]; + break; } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + } - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; - - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes + 1] = 255; // first pixel bottom byte } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; + // this is a little gross, so that we don't switch per-pixel or + // per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1) * filter_bytes; +#define STBI__CASE(f) \ + case f: \ + for (k = 0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: + memcpy(cur, raw, nk); + break; + STBI__CASE(STBI__F_sub) { + cur[k] = STBI__BYTECAST(raw[k] + cur[k - filter_bytes]); + } + break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } + break; + STBI__CASE(STBI__F_avg) { + cur[k] = STBI__BYTECAST(raw[k] + + ((prior[k] + cur[k - filter_bytes]) >> 1)); + } + break; + STBI__CASE(STBI__F_paeth) { + cur[k] = STBI__BYTECAST(raw[k] + + stbi__paeth(cur[k - filter_bytes], prior[k], + prior[k - filter_bytes])); + } + break; + STBI__CASE(STBI__F_avg_first) { + cur[k] = STBI__BYTECAST(raw[k] + (cur[k - filter_bytes] >> 1)); + } + break; + STBI__CASE(STBI__F_paeth_first) { + cur[k] = + STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - filter_bytes], 0, 0)); + } + break; } - - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } +#undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n + 1 == out_n); +#define STBI__CASE(f) \ + case f: \ + for (i = x - 1; i >= 1; --i, cur[filter_bytes] = 255, raw += filter_bytes, \ + cur += output_bytes, prior += output_bytes) \ + for (k = 0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } + break; + STBI__CASE(STBI__F_sub) { + cur[k] = STBI__BYTECAST(raw[k] + cur[k - output_bytes]); + } + break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } + break; + STBI__CASE(STBI__F_avg) { + cur[k] = STBI__BYTECAST(raw[k] + + ((prior[k] + cur[k - output_bytes]) >> 1)); + } + break; + STBI__CASE(STBI__F_paeth) { + cur[k] = STBI__BYTECAST(raw[k] + + stbi__paeth(cur[k - output_bytes], prior[k], + prior[k - output_bytes])); + } + break; + STBI__CASE(STBI__F_avg_first) { + cur[k] = STBI__BYTECAST(raw[k] + (cur[k - output_bytes] >> 1)); + } + break; + STBI__CASE(STBI__F_paeth_first) { + cur[k] = + STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - output_bytes], 0, 0)); + } + break; } - } +#undef STBI__CASE - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; - if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; - } - } else { - STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; - } - } - } + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride * j; // start at the beginning of the row again + for (i = 0; i < x; ++i, cur += output_bytes) { + cur[filter_bytes + 1] = 255; + } } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; + } + } - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j = 0; j < y; ++j) { + stbi_uc *cur = a->out + stride * j; + stbi_uc *in = a->out + stride * j + x * out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common + // 8-bit path optimal at minimal cost for 1/2/4-bit png guarante byte + // alignment, if width is not multiple of 8/4/2 we'll decode dummy + // trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) + ? stbi__depth_scale_table[depth] + : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than + // desired. we can allocate enough data that this never writes out of + // memory, but it could also overwrite the next scanline. can it overwrite + // non-empty data on the next scanline? yes, consider 1-pixel-wide + // scanlines with 1-bit-per-pixel. so we need to explicitly clamp the + // final ones + + if (depth == 4) { + for (k = x * img_n; k >= 2; k -= 2, ++in) { + *cur++ = scale * ((*in >> 4)); + *cur++ = scale * ((*in) & 0x0f); + } + if (k > 0) + *cur++ = scale * ((*in >> 4)); + } else if (depth == 2) { + for (k = x * img_n; k >= 4; k -= 4, ++in) { + *cur++ = scale * ((*in >> 6)); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in) & 0x03); + } + if (k > 0) + *cur++ = scale * ((*in >> 6)); + if (k > 1) + *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) + *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k = x * img_n; k >= 8; k -= 8, ++in) { + *cur++ = scale * ((*in >> 7)); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in) & 0x01); + } + if (k > 0) + *cur++ = scale * ((*in >> 7)); + if (k > 1) + *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) + *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) + *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) + *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) + *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) + *cur++ = scale * ((*in >> 1) & 0x01); } - } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride * j; + if (img_n == 1) { + for (q = x - 1; q >= 0; --q) { + cur[q * 2 + 1] = 255; + cur[q * 2 + 0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q = x - 1; q >= 0; --q) { + cur[q * 4 + 3] = 255; + cur[q * 4 + 2] = cur[q * 3 + 2]; + cur[q * 4 + 1] = cur[q * 3 + 1]; + cur[q * 4 + 0] = cur[q * 3 + 0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16 *)cur; - return 1; + for (i = 0; i < x * y * out_n; ++i, cur16++, cur += 2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, + stbi__uint32 image_data_len, int out_n, + int depth, int color, int interlaced) { + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, + a->s->img_x, a->s->img_y, depth, color); - // de-interlacing - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - if (!final) return stbi__err("outofmem", "Out of memory"); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; + // de-interlacing + final = (stbi_uc *)stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) + return stbi__err("outofmem", "Out of memory"); + for (p = 0; p < 7; ++p) { + int xorig[] = {0, 4, 0, 2, 0, 1, 0}; + int yorig[] = {0, 0, 4, 0, 2, 0, 1}; + int xspc[] = {8, 8, 4, 4, 2, 2, 1}; + int yspc[] = {8, 8, 8, 4, 4, 2, 2}; + int i, j, x, y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p] - 1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p] - 1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, + y, depth, color)) { + STBI_FREE(final); + return 0; } - } - a->out = final; + for (j = 0; j < y; ++j) { + for (i = 0; i < x; ++i) { + int out_y = j * yspc[p] + yorig[p]; + int out_x = i * xspc[p] + xorig[p]; + memcpy(final + out_y * a->s->img_x * out_bytes + out_x * out_bytes, + a->out + (j * x + i) * out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; - return 1; + return 1; } -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; } -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], + int out_n) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16 *)z->out; - // compute color-based transparency, assuming we've - // already got 65535 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; } -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, + int pal_img_n) { + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (stbi_uc *)stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) + return stbi__err("outofmem", "Out of memory"); - // between here and free(out) below, exitting would leak - temp_out = p; + // between here and free(out) below, exitting would leak + temp_out = p; - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; + if (pal_img_n == 3) { + for (i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p += 3; + } + } else { + for (i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p[3] = palette[n + 3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; - STBI_NOTUSED(len); + STBI_NOTUSED(len); - return 1; + return 1; } static int stbi__unpremultiply_on_load_global = 0; static int stbi__de_iphone_flag_global = 0; -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; +STBIDEF void +stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag_global = flag_true_if_should_convert; +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { + stbi__de_iphone_flag_global = flag_true_if_should_convert; } #ifndef STBI_THREAD_LOCAL -#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global -#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global #else -static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; -static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, + stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, + stbi__de_iphone_flag_set; -STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; - stbi__unpremultiply_on_load_set = 1; +STBIDEF void +stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) { + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; } -STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag_local = flag_true_if_should_convert; - stbi__de_iphone_flag_set = 1; +STBIDEF void +stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) { + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; } -#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ - ? stbi__unpremultiply_on_load_local \ - : stbi__unpremultiply_on_load_global) -#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ - ? stbi__de_iphone_flag_local \ - : stbi__de_iphone_flag_global) +#define stbi__unpremultiply_on_load \ + (stbi__unpremultiply_on_load_set ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag \ + (stbi__de_iphone_flag_set ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) #endif // STBI_THREAD_LOCAL -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; +static void stbi__de_iphone(stbi__png *z) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; + if (s->img_out_n == 3) { // convert bgr to rgb + for (i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i = 0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = (t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - stbi_uc half = a / 2; - p[0] = (p[2] * 255 + half) / a; - p[1] = (p[1] * 255 + half) / a; - p[2] = ( t * 255 + half) / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } + } else { + // convert bgr to rgb + for (i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; } - } + } + } } -#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) +#define STBI__PNG_TYPE(a, b, c, d) \ + (((unsigned)(a) << 24) + ((unsigned)(b) << 16) + ((unsigned)(c) << 8) + \ + (unsigned)(d)) -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]={0}; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { + stbi_uc palette[1024], pal_img_n = 0; + stbi_uc has_trans = 0, tc[3] = {0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff = 0, idata_limit = 0, i, pal_len = 0; + int first = 1, k, interlace = 0, color = 0, is_iphone = 0; + stbi__context *s = z->s; - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; - if (!stbi__check_png_header(s)) return 0; + if (!stbi__check_png_header(s)) + return 0; - if (scan == STBI__SCAN_type) return 1; + if (scan == STBI__SCAN_type) + return 1; - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); - s->img_y = stbi__get32be(s); - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } - - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } - - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is - } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger - } - } - break; - } - - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } - - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } else if (has_trans) { - // non-paletted image with tRNS -> source image has (constant) alpha - ++s->img_n; - } - STBI_FREE(z->expanded); z->expanded = NULL; - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - return 1; - } - - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C', 'g', 'B', 'I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I', 'H', 'D', 'R'): { + int comp, filter; + if (!first) + return stbi__err("multiple IHDR", "Corrupt PNG"); + first = 0; + if (c.length != 13) + return stbi__err("bad IHDR len", "Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) + return stbi__err("too large", "Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) + return stbi__err("too large", "Very large image (corrupt?)"); + z->depth = stbi__get8(s); + if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && + z->depth != 16) + return stbi__err("1/2/4/8/16-bit only", + "PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); + if (color > 6) + return stbi__err("bad ctype", "Corrupt PNG"); + if (color == 3 && z->depth == 16) + return stbi__err("bad ctype", "Corrupt PNG"); + if (color == 3) + pal_img_n = 3; + else if (color & 1) + return stbi__err("bad ctype", "Corrupt PNG"); + comp = stbi__get8(s); + if (comp) + return stbi__err("bad comp method", "Corrupt PNG"); + filter = stbi__get8(s); + if (filter) + return stbi__err("bad filter method", "Corrupt PNG"); + interlace = stbi__get8(s); + if (interlace > 1) + return stbi__err("bad interlace method", "Corrupt PNG"); + if (!s->img_x || !s->img_y) + return stbi__err("0-pixel image", "Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) + return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) + return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) + return stbi__err("too large", "Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS } + break; + } + + case STBI__PNG_TYPE('P', 'L', 'T', 'E'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256 * 3) + return stbi__err("invalid PLTE", "Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) + return stbi__err("invalid PLTE", "Corrupt PNG"); + for (i = 0; i < pal_len; ++i) { + palette[i * 4 + 0] = stbi__get8(s); + palette[i * 4 + 1] = stbi__get8(s); + palette[i * 4 + 2] = stbi__get8(s); + palette[i * 4 + 3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t', 'R', 'N', 'S'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) + return stbi__err("tRNS after IDAT", "Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { + s->img_n = 4; + return 1; + } + if (pal_len == 0) + return stbi__err("tRNS before PLTE", "Corrupt PNG"); + if (c.length > pal_len) + return stbi__err("bad tRNS len", "Corrupt PNG"); + pal_img_n = 4; + for (i = 0; i < c.length; ++i) + palette[i * 4 + 3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) + return stbi__err("tRNS with alpha", "Corrupt PNG"); + if (c.length != (stbi__uint32)s->img_n * 2) + return stbi__err("bad tRNS len", "Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * + stbi__depth_scale_table[z->depth]; // non 8-bit images will + // be larger + } + } + break; + } + + case STBI__PNG_TYPE('I', 'D', 'A', 'T'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) + return stbi__err("no PLTE", "Corrupt PNG"); + if (scan == STBI__SCAN_header) { + s->img_n = pal_img_n; + return 1; + } + if ((int)(ioff + c.length) < (int)ioff) + return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) + idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *)STBI_REALLOC_SIZED(z->idata, idata_limit_old, + idata_limit); + if (p == NULL) + return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata + ioff, c.length)) + return stbi__err("outofdata", "Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I', 'E', 'N', 'D'): { + stbi__uint32 raw_len, bpl; + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) + return 1; + if (z->idata == NULL) + return stbi__err("no IDAT", "Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *)stbi_zlib_decode_malloc_guesssize_headerflag( + (char *)z->idata, ioff, raw_len, (int *)&raw_len, !is_iphone); + if (z->expanded == NULL) + return 0; // zlib should set error + STBI_FREE(z->idata); + z->idata = NULL; + if ((req_comp == s->img_n + 1 && req_comp != 3 && !pal_img_n) || + has_trans) + s->img_out_n = s->img_n + 1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, + z->depth, color, interlace)) + return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) + return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) + return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) + s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); + z->expanded = NULL; // end of PNG chunk, read and skip CRC stbi__get32be(s); - } -} + return 1; + } -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) -{ - void *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth <= 8) - ri->bits_per_channel = 8; - else if (p->depth == 16) - ri->bits_per_channel = 16; - else - return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; + default: + // if critical, fail + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { +#ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); +#endif + return stbi__err(invalid_chunk, + "PNG not supported: unknown PNG chunk type"); } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; - - return result; + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } } -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, + stbi__result_info *ri) { + void *result = NULL; + if (req_comp < 0 || req_comp > 4) + return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", + "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *)result, p->s->img_out_n, + req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *)result, p->s->img_out_n, + req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) + return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) + *n = p->s->img_n; + } + STBI_FREE(p->out); + p->out = NULL; + STBI_FREE(p->expanded); + p->expanded = NULL; + STBI_FREE(p->idata); + p->idata = NULL; + + return result; } -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri) { + stbi__png p; + p.s = s; + return stbi__do_png(&p, x, y, comp, req_comp, ri); } -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; +static int stbi__png_test(stbi__context *s) { + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; } -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) { + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind(p->s); + return 0; + } + if (x) + *x = p->s->img_x; + if (y) + *y = p->s->img_y; + if (comp) + *comp = p->s->img_n; + return 1; } -static int stbi__png_is16(stbi__context *s) -{ - stbi__png p; - p.s = s; - if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) - return 0; - if (p.depth != 16) { - stbi__rewind(p.s); - return 0; - } - return 1; +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) { + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) { + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; } #endif // Microsoft/Windows BMP image #ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; +static int stbi__bmp_test_raw(stbi__context *s) { + int r; + int sz; + if (stbi__get8(s) != 'B') + return 0; + if (stbi__get8(s) != 'M') + return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; } -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; +static int stbi__bmp_test(stbi__context *s) { + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; } - // returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) { n += 16; z >>= 16; } - if (z >= 0x00100) { n += 8; z >>= 8; } - if (z >= 0x00010) { n += 4; z >>= 4; } - if (z >= 0x00004) { n += 2; z >>= 2; } - if (z >= 0x00002) { n += 1;/* >>= 1;*/ } - return n; +static int stbi__high_bit(unsigned int z) { + int n = 0; + if (z == 0) + return -1; + if (z >= 0x10000) { + n += 16; + z >>= 16; + } + if (z >= 0x00100) { + n += 8; + z >>= 8; + } + if (z >= 0x00010) { + n += 4; + z >>= 4; + } + if (z >= 0x00004) { + n += 2; + z >>= 2; + } + if (z >= 0x00002) { + n += 1; /* >>= 1;*/ + } + return n; } -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; +static int stbi__bitcount(unsigned int a) { + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; } // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. -static int stbi__shiftsigned(unsigned int v, int shift, int bits) -{ - static unsigned int mul_table[9] = { +static int stbi__shiftsigned(unsigned int v, int shift, int bits) { + static unsigned int mul_table[9] = { 0, - 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, - 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, - }; - static unsigned int shift_table[9] = { - 0, 0,0,1,0,2,4,6,0, - }; - if (shift < 0) - v <<= -shift; - else - v >>= shift; - STBI_ASSERT(v < 256); - v >>= (8-bits); - STBI_ASSERT(bits >= 0 && bits <= 8); - return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; + 0xff /*0b11111111*/, + 0x55 /*0b01010101*/, + 0x49 /*0b01001001*/, + 0x11 /*0b00010001*/, + 0x21 /*0b00100001*/, + 0x41 /*0b01000001*/, + 0x81 /*0b10000001*/, + 0x01 /*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0, 0, 1, 0, 2, 4, 6, 0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8 - bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int)((unsigned)v * mul_table[bits]) >> shift_table[bits]; } -typedef struct -{ - int bpp, offset, hsz; - unsigned int mr,mg,mb,ma, all_a; - int extra_read; +typedef struct { + int bpp, offset, hsz; + unsigned int mr, mg, mb, ma, all_a; + int extra_read; } stbi__bmp_data; -static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) -{ - // BI_BITFIELDS specifies masks explicitly, don't override - if (compress == 3) - return 1; +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) { + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; - if (compress == 0) { - if (info->bpp == 16) { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } else if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - // otherwise, use defaults, which is all-0 - info->mr = info->mg = info->mb = info->ma = 0; - } - return 1; - } - return 0; // error + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but + // it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error } -static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - info->offset = stbi__get32le(s); - info->hsz = hsz = stbi__get32le(s); - info->mr = info->mg = info->mb = info->ma = 0; - info->extra_read = 14; +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') + return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; - if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + if (info->offset < 0) + return stbi__errpuc("bad BMP", "bad BMP"); - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - info->bpp = stbi__get16le(s); - if (hsz != 12) { - int compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes - if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (info->bpp == 16 || info->bpp == 32) { - if (compress == 0) { - stbi__bmp_set_mask_defaults(info, compress); - } else if (compress == 3) { - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->extra_read += 12; - // not documented, but generated by photoshop and handled by mspaint - if (info->mr == info->mg && info->mg == info->mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - // V4/V5 header - int i; - if (hsz != 108 && hsz != 124) + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) + return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) + return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) + return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) + return stbi__errpuc( + "BMP JPEG/PNG", + "BMP type not supported: unsupported compression"); // this includes + // PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) + return stbi__errpuc("bad BMP", + "bad BMP"); // bitfields requires 16 or 32 bits/pixel + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + stbi__bmp_set_mask_defaults(info, compress); + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? return stbi__errpuc("bad BMP", "bad BMP"); - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->ma = stbi__get32le(s); - if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs - stbi__bmp_set_mask_defaults(info, compress); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); } - } - return (void *) 1; + } else { + // V4/V5 header + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + if (compress != + 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); + stbi__get32le(s); // discard color space + for (i = 0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *)1; } +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri) { + stbi_uc *out; + unsigned int mr = 0, mg = 0, mb = 0, ma = 0, all_a; + stbi_uc pal[256][4]; + int psize = 0, i, j, width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a; - stbi_uc pal[256][4]; - int psize=0,i,j,width; - int flip_vertically, pad, target; - stbi__bmp_data info; - STBI_NOTUSED(ri); + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set - info.all_a = 255; - if (stbi__bmp_parse_header(s, &info) == NULL) - return NULL; // error code already set + flip_vertically = ((int)s->img_y) > 0; + s->img_y = abs((int)s->img_y); - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); + if (s->img_y > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; - mr = info.mr; - mg = info.mg; - mb = info.mb; - ma = info.ma; - all_a = info.all_a; + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + if (info.offset != + s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } + } - if (info.hsz == 12) { - if (info.bpp < 24) - psize = (info.offset - info.extra_read - 24) / 3; - } else { - if (info.bpp < 16) - psize = (info.offset - info.extra_read - info.hsz) >> 2; - } - if (psize == 0) { - if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { - return stbi__errpuc("bad offset", "Corrupt BMP"); + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *)stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z = 0; + if (psize == 0 || psize > 256) { + STBI_FREE(out); + return stbi__errpuc("invalid", "Corrupt BMP"); + } + for (i = 0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) + stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - + psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) + width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) + width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) + width = s->img_x; + else { + STBI_FREE(out); + return stbi__errpuc("bad bpp", "Corrupt BMP"); + } + pad = (-width) & 3; + if (info.bpp == 1) { + for (j = 0; j < (int)s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i = 0; i < (int)s->img_x; ++i) { + int color = (v >> bit_offset) & 0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) + out[z++] = 255; + if (i + 1 == (int)s->img_x) + break; + if ((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); } - } - - if (info.bpp == 24 && ma == 0xff000000) - s->img_n = 3; - else - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert - - // sanity-check size - if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "Corrupt BMP"); - - out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (info.bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (info.hsz != 12) stbi__get8(s); - pal[i][3] = 255; + } else { + for (j = 0; j < (int)s->img_y; ++j) { + for (i = 0; i < (int)s->img_x; i += 2) { + int v = stbi__get8(s), v2 = 0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) + out[z++] = 255; + if (i + 1 == (int)s->img_x) + break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) + out[z++] = 255; + } + stbi__skip(s, pad); } - stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 1) width = (s->img_x + 7) >> 3; - else if (info.bpp == 4) width = (s->img_x + 1) >> 1; - else if (info.bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - if (info.bpp == 1) { - for (j=0; j < (int) s->img_y; ++j) { - int bit_offset = 7, v = stbi__get8(s); - for (i=0; i < (int) s->img_x; ++i) { - int color = (v>>bit_offset)&0x1; - out[z++] = pal[color][0]; - out[z++] = pal[color][1]; - out[z++] = pal[color][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - if((--bit_offset) < 0) { - bit_offset = 7; - v = stbi__get8(s); - } - } - stbi__skip(s, pad); - } + } + } else { + int rshift = 0, gshift = 0, bshift = 0, ashift = 0, rcount = 0, gcount = 0, + bcount = 0, acount = 0; + int z = 0; + int easy = 0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) + width = 3 * s->img_x; + else if (info.bpp == 16) + width = 2 * s->img_x; + else /* bpp = 32 and pad = 0 */ + width = 0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { + STBI_FREE(out); + return stbi__errpuc("bad masks", "Corrupt BMP"); + } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr) - 7; + rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg) - 7; + gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb) - 7; + bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma) - 7; + acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { + STBI_FREE(out); + return stbi__errpuc("bad masks", "Corrupt BMP"); + } + } + for (j = 0; j < (int)s->img_y; ++j) { + if (easy) { + for (i = 0; i < (int)s->img_x; ++i) { + unsigned char a; + out[z + 2] = stbi__get8(s); + out[z + 1] = stbi__get8(s); + out[z + 0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) + out[z++] = a; + } } else { - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } + int bpp = info.bpp; + for (i = 0; i < (int)s->img_x; ++i) { + stbi__uint32 v = + (bpp == 16 ? (stbi__uint32)stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) + out[z++] = STBI__BYTECAST(a); + } } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, info.offset - info.extra_read - info.hsz); - if (info.bpp == 24) width = 3 * s->img_x; - else if (info.bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (info.bpp == 24) { - easy = 1; - } else if (info.bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - all_a |= a; - if (target == 4) out[z++] = a; - } - } else { - int bpp = info.bpp; - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - unsigned int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - all_a |= a; - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } + stbi__skip(s, pad); + } + } - // if alpha channel is all 0s, replace with all 255s - if (target == 4 && all_a == 0) - for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) - out[i] = 255; + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i = 4 * s->img_x * s->img_y - 1; i >= 0; i -= 4) + out[i] = 255; - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i]; p1[i] = p2[i]; p2[i] = t; - } + if (flip_vertically) { + stbi_uc t; + for (j = 0; j < (int)s->img_y >> 1; ++j) { + stbi_uc *p1 = out + j * s->img_x * target; + stbi_uc *p2 = out + (s->img_y - 1 - j) * s->img_x * target; + for (i = 0; i < (int)s->img_x * target; ++i) { + t = p1[i]; + p1[i] = p2[i]; + p2[i] = t; } - } + } + } - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; + *x = s->img_x; + *y = s->img_y; + if (comp) + *comp = s->img_n; + return out; } #endif @@ -5658,592 +6358,625 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req // by Jonathan Dummer #ifndef STBI_NO_TGA // returns STBI_rgb or whatever, 0 on error -static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) -{ - // only RGB or RGBA (incl. 16bit) or grey allowed - if (is_rgb16) *is_rgb16 = 0; - switch(bits_per_pixel) { - case 8: return STBI_grey; - case 16: if(is_grey) return STBI_grey_alpha; - // fallthrough - case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fallthrough - case 32: return bits_per_pixel/8; - default: return 0; - } +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int *is_rgb16) { + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) + *is_rgb16 = 0; + switch (bits_per_pixel) { + case 8: + return STBI_grey; + case 16: + if (is_grey) + return STBI_grey_alpha; + // fallthrough + case 15: + if (is_rgb16) + *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: + return bits_per_pixel / 8; + default: + return 0; + } } -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; - int sz, tga_colormap_type; - stbi__get8(s); // discard Offset - tga_colormap_type = stbi__get8(s); // colormap type - if( tga_colormap_type > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - tga_image_type = stbi__get8(s); // image type - if ( tga_colormap_type == 1 ) { // colormapped (paletted) image - if (tga_image_type != 1 && tga_image_type != 9) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip image x and y origin - tga_colormap_bpp = sz; - } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE - if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { - stbi__rewind(s); - return 0; // only RGB or grey allowed, +/- RLE - } - stbi__skip(s,9); // skip colormap specification and image x/y origin - tga_colormap_bpp = 0; - } - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - tga_bits_per_pixel = stbi__get8(s); // bits per pixel - stbi__get8(s); // ignore alpha bits - if (tga_colormap_bpp != 0) { - if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { - // when using a colormap, tga_bits_per_pixel is the size of the indexes - // I don't think anything but 8 or 16bit indexes makes sense - stbi__rewind(s); - return 0; - } - tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); - } else { - tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); - } - if(!tga_comp) { +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) { + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, + tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if (tga_colormap_type > 1) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if (tga_colormap_type == 1) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { stbi__rewind(s); return 0; } - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp; - return 1; // seems to have passed everything + stbi__skip(s, + 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ((tga_image_type != 2) && (tga_image_type != 3) && + (tga_image_type != 10) && (tga_image_type != 11)) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s, 9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if (tga_w < 1) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if (tga_h < 1) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp( + tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), + NULL); + } + if (!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) + *x = tga_w; + if (y) + *y = tga_h; + if (comp) + *comp = tga_comp; + return 1; // seems to have passed everything } -static int stbi__tga_test(stbi__context *s) -{ - int res = 0; - int sz, tga_color_type; - stbi__get8(s); // discard Offset - tga_color_type = stbi__get8(s); // color type - if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( tga_color_type == 1 ) { // colormapped (paletted) image - if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - stbi__skip(s,4); // skip image x and y origin - } else { // "normal" image w/o colormap - if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE - stbi__skip(s,9); // skip colormap specification and image x/y origin - } - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height - sz = stbi__get8(s); // bits per pixel - if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; +static int stbi__tga_test(stbi__context *s) { + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if (tga_color_type > 1) + goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if (tga_color_type == 1) { // colormapped (paletted) image + if (sz != 1 && sz != 9) + goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s, + 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) + goto errorEnd; + stbi__skip(s, 4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ((sz != 2) && (sz != 3) && (sz != 10) && (sz != 11)) + goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s, 9); // skip colormap specification and image x/y origin + } + if (stbi__get16le(s) < 1) + goto errorEnd; // test width + if (stbi__get16le(s) < 1) + goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ((tga_color_type == 1) && (sz != 8) && (sz != 16)) + goto errorEnd; // for colormapped images, bpp is size of an index + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) + goto errorEnd; - res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + res = 1; // if we got this far, everything's good and we can return 1 instead + // of 0 errorEnd: - stbi__rewind(s); - return res; + stbi__rewind(s); + return res; } // read 16bit value and convert to 24bit RGB -static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) -{ - stbi__uint16 px = (stbi__uint16)stbi__get16le(s); - stbi__uint16 fiveBitMask = 31; - // we have 3 channels with 5bits each - int r = (px >> 10) & fiveBitMask; - int g = (px >> 5) & fiveBitMask; - int b = px & fiveBitMask; - // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (stbi_uc)((r * 255)/31); - out[1] = (stbi_uc)((g * 255)/31); - out[2] = (stbi_uc)((b * 255)/31); +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc *out) { + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be + // swapped later + out[0] = (stbi_uc)((r * 255) / 31); + out[1] = (stbi_uc)((g * 255) / 31); + out[2] = (stbi_uc)((b * 255) / 31); - // some people claim that the most significant bit might be used for alpha - // (possibly if an alpha-bit is set in the "image descriptor byte") - // but that only made 16bit test images completely translucent.. - // so let's treat all 15 and 16bit TGAs as RGB with no alpha. + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp, tga_rgb16=0; - int tga_inverted = stbi__get8(s); - // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4] = {0}; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - STBI_NOTUSED(ri); - STBI_NOTUSED(tga_x_origin); // @TODO - STBI_NOTUSED(tga_y_origin); // @TODO +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri) { + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16 = 0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused + // (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO - if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_height > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - tga_inverted = 1 - ((tga_inverted >> 5) & 1); + // do a tiny bit of precessing + if (tga_image_type >= 8) { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); - else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + // If I'm paletted, then I'll use the number of bits from the palette + if (tga_indexed) + tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), + &tga_rgb16); - if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency - return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + if (!tga_comp) // shouldn't really happen, stbi__tga_test() should have + // ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; + // tga info + *x = tga_width; + *y = tga_height; + if (comp) + *comp = tga_comp; - if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) - return stbi__errpuc("too large", "Corrupt TGA"); + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); - tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + tga_data = + (unsigned char *)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) + return stbi__errpuc("outofmem", "Out of memory"); - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset); - if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { - for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); + if (!tga_indexed && !tga_is_RLE && !tga_rgb16) { + for (i = 0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height - i - 1 : i; + stbi_uc *tga_row = tga_data + row * tga_width * tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if (tga_indexed) { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - if (tga_palette_len == 0) { /* you have to have at least one entry! */ - STBI_FREE(tga_data); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (tga_rgb16) { - stbi_uc *pal_entry = tga_palette; - STBI_ASSERT(tga_comp == STBI_rgb); - for (i=0; i < tga_palette_len; ++i) { - stbi__tga_read_rgb16(s, pal_entry); - pal_entry += tga_comp; - } - } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start); + // load the palette + tga_palette = + (unsigned char *)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in index, then perform the lookup - int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); - if ( pal_idx >= tga_palette_len ) { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_comp; - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else if(tga_rgb16) { - STBI_ASSERT(tga_comp == STBI_rgb); - stbi__tga_read_rgb16(s, raw_data); - } else { - // read in the data raw - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel - - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; - - // in case we're in RLE mode, keep counting down - --RLE_count; + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i = 0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } + } + // load the data + for (i = 0; i < tga_width * tga_height; ++i) { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if (tga_is_RLE) { + if (RLE_count == 0) { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if (!RLE_repeating) { + read_next_pixel = 1; + } + } else { + read_next_pixel = 1; } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); + // OK, if I need to read a pixel, do it now + if (read_next_pixel) { + // load however much data we did have + if (tga_indexed) { + // read in index, then perform the lookup + int pal_idx = + (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if (pal_idx >= tga_palette_len) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx + j]; + } + } else if (tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i * tga_comp + j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if (tga_inverted) { + for (j = 0; j * 2 < tga_height; ++j) { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } } - } + } + // clear my palette, if I had one + if (tga_palette != NULL) { + STBI_FREE(tga_palette); + } + } - // swap RGB - if the source data was RGB16, it already is in the right order - if (tga_comp >= 3 && !tga_rgb16) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) { + unsigned char *tga_pixel = tga_data; + for (i = 0; i < tga_width * tga_height; ++i) { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, + tga_height); - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - STBI_NOTUSED(tga_palette_start); - // OK, done - return tga_data; + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = + tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; } #endif // ************************************************************************************************* -// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, +// tweaked by STB #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; +static int stbi__psd_test(stbi__context *s) { + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; } -static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) -{ - int count, nleft, len; +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) { + int count, nleft, len; - count = 0; - while ((nleft = pixelCount - count) > 0) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - if (len > nleft) return 0; // corrupt data - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len = 257 - len; - if (len > nleft) return 0; // corrupt data - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) + return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; } - } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) + return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } - return 1; + return 1; } -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - int pixelCount; - int channelCount, compression; - int channel, i; - int bitdepth; - int w,h; - stbi_uc *out; - STBI_NOTUSED(ri); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri, int bpc) { + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w, h; + stbi_uc *out; + STBI_NOTUSED(ri); - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); + // Skip 6 reserved bytes. + stbi__skip(s, 6); - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", + "Unsupported number of channels in PSD image"); - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); - if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (h > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); - // Make sure the depth is 8 bits. - bitdepth = stbi__get16be(s); - if (bitdepth != 8 && bitdepth != 16) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", + "PSD bit depth is not 8 or 16 bit"); - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); + // Skip the Mode Data. (It's the palette for indexed color; other info for + // other modes.) + stbi__skip(s, stbi__get32be(s)); - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s)); - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s)); - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", + "PSD has an unknown compression format"); - // Check size - if (!stbi__mad3sizes_valid(4, w, h, 0)) - return stbi__errpuc("too large", "Corrupt PSD"); + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); - // Create the destination image. + // Create the destination image. - if (!compression && bitdepth == 16 && bpc == 16) { - out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); - ri->bits_per_channel = 16; - } else - out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *)stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *)stbi__malloc(4 * w * h); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w * h; - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); + // Initialize the data to zero. + // memset( out, 0, pixelCount * 4 ); - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes + // literally. Else if n is between -127 and -1 inclusive, copy the next + // byte -n+1 times. Else if n is 128, noop. + // Endloop - // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); + // The RLE-compressed data is preceded by a 2-byte data count for each row + // in the data, which we're going to just skip. + stbi__skip(s, h * channelCount * 2); - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++, p += 4) - *p = (channel == 3 ? 255 : 0); - } else { - // Read the RLE data. - if (!stbi__psd_decode_rle(s, p, pixelCount)) { - STBI_FREE(out); - return stbi__errpuc("corrupt", "bad RLE data"); - } - } - } - - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. - - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - if (channel >= channelCount) { - // Fill this channel with default data. - if (bitdepth == 16 && bpc == 16) { - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - stbi__uint16 val = channel == 3 ? 65535 : 0; - for (i = 0; i < pixelCount; i++, q += 4) - *q = val; - } else { - stbi_uc *p = out+channel; - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } - } else { - if (ri->bits_per_channel == 16) { // output bpc - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - for (i = 0; i < pixelCount; i++, q += 4) - *q = (stbi__uint16) stbi__get16be(s); - } else { - stbi_uc *p = out+channel; - if (bitdepth == 16) { // input bpc - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - } - - // remove weird white matte from PSD - if (channelCount >= 4) { - if (ri->bits_per_channel == 16) { - for (i=0; i < w*h; ++i) { - stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; - if (pixel[3] != 0 && pixel[3] != 65535) { - float a = pixel[3] / 65535.0f; - float ra = 1.0f / a; - float inv_a = 65535.0f * (1 - ra); - pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); - pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); - pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); - } - } + p = out + channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); } else { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); - } - } + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } } - } + } - // convert to desired output format - if (req_comp && req_comp != 4) { - if (ri->bits_per_channel == 16) - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); - else - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } + } else { + // We're at the raw image data. It's each channel in order (Red, Green, + // Blue, Alpha, ...) where each channel consists of an 8-bit (or 16-bit) + // value for each pixel in the image. - if (comp) *comp = 4; - *y = h; - *x = w; + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *)out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out + channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *)out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16)stbi__get16be(s); + } else { + stbi_uc *p = out + channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc)(stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } - return out; + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i = 0; i < w * h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *)out + 4 * i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16)(pixel[0] * ra + inv_a); + pixel[1] = (stbi__uint16)(pixel[1] * ra + inv_a); + pixel[2] = (stbi__uint16)(pixel[2] * ra + inv_a); + } + } + } else { + for (i = 0; i < w * h; ++i) { + unsigned char *pixel = out + 4 * i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char)(pixel[0] * ra + inv_a); + pixel[1] = (unsigned char)(pixel[1] * ra + inv_a); + pixel[2] = (unsigned char)(pixel[2] * ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *)stbi__convert_format16((stbi__uint16 *)out, 4, req_comp, + w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } + + if (comp) + *comp = 4; + *y = h; + *x = w; + + return out; } #endif @@ -6255,216 +6988,224 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req // See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ #ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; - - return 1; -} - -static int stbi__pic_test_core(stbi__context *s) -{ - int i; - - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) +static int stbi__pic_is4(stbi__context *s, const char *str) { + int i; + for (i = 0; i < 4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) return 0; - for(i=0;i<84;++i) - stbi__get8(s); - - if (!stbi__pic_is4(s,"PICT")) - return 0; - - return 1; + return 1; } -typedef struct -{ - stbi_uc size,type,channel; +static int stbi__pic_test_core(stbi__context *s) { + int i; + + if (!stbi__pic_is4(s, "\x53\x80\xF6\x34")) + return 0; + + for (i = 0; i < 84; ++i) + stbi__get8(s); + + if (!stbi__pic_is4(s, "PICT")) + return 0; + + return 1; +} + +typedef struct { + stbi_uc size, type, channel; } stbi__pic_packet; -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) { + int mask = 0x80, i; - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); + for (i = 0; i < 4; ++i, mask >>= 1) { + if (channel & mask) { + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "PIC file too short"); + dest[i] = stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel, stbi_uc *dest, const stbi_uc *src) { + int mask = 0x80, i; + + for (i = 0; i < 4; ++i, mask >>= 1) + if (channel & mask) + dest[i] = src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s, int width, int height, + int *comp, stbi_uc *result) { + int act_comp = 0, num_packets = 0, y, chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets == sizeof(packets) / sizeof(packets[0])) + return stbi__errpuc("bad format", "too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (reading packets)"); + if (packet->size != 8) + return stbi__errpuc("bad format", "packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for (y = 0; y < height; ++y) { + int packet_idx; + + for (packet_idx = 0; packet_idx < num_packets; ++packet_idx) { + stbi__pic_packet *packet = &packets[packet_idx]; + stbi_uc *dest = result + y * width * 4; + + switch (packet->type) { + default: + return stbi__errpuc("bad format", "packet has bad compression type"); + + case 0: { // uncompressed + int x; + + for (x = 0; x < width; ++x, dest += 4) + if (!stbi__readval(s, packet->channel, dest)) + return 0; + break; } - } - return dest; -} + case 1: // Pure RLE + { + int left = width, i; -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; + while (left > 0) { + stbi_uc count, value[4]; - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; -} + count = stbi__get8(s); + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (pure read count)"); -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; + if (count > left) + count = (stbi_uc)left; - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; + if (!stbi__readval(s, packet->channel, value)) + return 0; - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); + for (i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + left -= count; + } + } break; - packet = &packets[num_packets++]; + case 2: { // Mixed RLE + int left = width; + while (left > 0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", + "file too short (mixed read count)"); - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); + if (count >= 128) { // Repeated + stbi_uc value[4]; - act_comp |= packet->channel; + if (count == 128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file", "scanline overrun"); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); + if (!stbi__readval(s, packet->channel, value)) + return 0; - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + for (i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + } else { // Raw + ++count; + if (count > left) + return stbi__errpuc("bad file", "scanline overrun"); - for(y=0; ytype) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); - - case 0: {//uncompressed - int x; - - for(x=0;xchannel,dest)) - return 0; - break; - } - - case 1://Pure RLE - { - int left=width, i; - - while (left>0) { - stbi_uc count,value[4]; - - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); - - if (count > left) - count = (stbi_uc) left; - - if (!stbi__readval(s,packet->channel,value)) return 0; - - for(i=0; ichannel,dest,value); - left -= count; - } - } - break; - - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); - - if (count >= 128) { // Repeated - stbi_uc value[4]; - - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); - - if (!stbi__readval(s,packet->channel,value)) - return 0; - - for(i=0;ichannel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); - - for(i=0;ichannel,dest)) - return 0; - } - left-=count; - } - break; - } - } + for (i = 0; i < count; ++i, dest += 4) + if (!stbi__readval(s, packet->channel, dest)) + return 0; + } + left -= count; + } + break; } - } + } + } + } - return result; + return result; } -static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) -{ - stbi_uc *result; - int i, x,y, internal_comp; - STBI_NOTUSED(ri); +static void *stbi__pic_load(stbi__context *s, int *px, int *py, int *comp, + int req_comp, stbi__result_info *ri) { + stbi_uc *result; + int i, x, y, internal_comp; + STBI_NOTUSED(ri); - if (!comp) comp = &internal_comp; + if (!comp) + comp = &internal_comp; - for (i=0; i<92; ++i) - stbi__get8(s); + for (i = 0; i < 92; ++i) + stbi__get8(s); - x = stbi__get16be(s); - y = stbi__get16be(s); + x = stbi__get16be(s); + y = stbi__get16be(s); - if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (y > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) + return stbi__errpuc("too large", "PIC image too large to decode"); - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' + stbi__get32be(s); // skip `ratio' + stbi__get16be(s); // skip `fields' + stbi__get16be(s); // skip `pad' - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); - if (!result) return stbi__errpuc("outofmem", "Out of memory"); - memset(result, 0xff, x*y*4); + // intermediate buffer is RGBA + result = (stbi_uc *)stbi__malloc_mad3(x, y, 4, 0); + if (!result) + return stbi__errpuc("outofmem", "Out of memory"); + memset(result, 0xff, x * y * 4); - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); + if (!stbi__pic_load_core(s, x, y, comp, result)) { + STBI_FREE(result); + result = 0; + } + *px = x; + *py = y; + if (req_comp == 0) + req_comp = *comp; + result = stbi__convert_format(result, 4, req_comp, x, y); - return result; + return result; } -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; +static int stbi__pic_test(stbi__context *s) { + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; } #endif @@ -6472,533 +7213,562 @@ static int stbi__pic_test(stbi__context *s) // GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb #ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; +typedef struct { + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; } stbi__gif_lzw; -typedef struct -{ - int w,h; - stbi_uc *out; // output buffer (always 4 components) - stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; - int flags, bgindex, ratio, transparent, eflags; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[8192]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; - int delay; +typedef struct { + int w, h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; } stbi__gif; -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; +static int stbi__gif_test_raw(stbi__context *s) { + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || + stbi__get8(s) != '8') + return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') + return 0; + if (stbi__get8(s) != 'a') + return 0; + return 1; } -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; +static int stbi__gif_test(stbi__context *s) { + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; } -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], + int num_entries, int transp) { + int i; + for (i = 0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } } -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, + int is_info) { + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || + stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + version = stbi__get8(s); + if (version != '7' && version != '9') + return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') + return stbi__err("not GIF", "Corrupt GIF"); - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; - if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); - if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->w > STBI_MAX_DIMENSIONS) + return stbi__err("too large", "Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) + return stbi__err("too large", "Very large image (corrupt?)"); - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + if (comp != 0) + *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the + // comments - if (is_info) return 1; + if (is_info) + return 1; - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + if (g->flags & 0x80) + stbi__gif_parse_colortable(s, g->pal, 2 << (g->flags & 7), -1); - return 1; + return 1; } -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!g) return stbi__err("outofmem", "Out of memory"); - if (!stbi__gif_header(s, g, comp, 1)) { - STBI_FREE(g); - stbi__rewind( s ); - return 0; - } - if (x) *x = g->w; - if (y) *y = g->h; - STBI_FREE(g); - return 1; +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { + stbi__gif *g = (stbi__gif *)stbi__malloc(sizeof(stbi__gif)); + if (!g) + return stbi__err("outofmem", "Out of memory"); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind(s); + return 0; + } + if (x) + *x = g->w; + if (y) + *y = g->h; + STBI_FREE(g); + return 1; } -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - int idx; +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { + stbi_uc *p, *c; + int idx; - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); - if (g->cur_y >= g->max_y) return; + if (g->cur_y >= g->max_y) + return; - idx = g->cur_x + g->cur_y; - p = &g->out[idx]; - g->history[idx / 4] = 1; + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; - c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; - if (g->cur_x >= g->max_x) { + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) { + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) + return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc)init_code; + g->codes[init_code].suffix = (stbi_uc)init_code; + } + + // support no starting clear code + avail = clear + 2; + oldcode = -1; + + len = 0; + for (;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32)stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s, len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16)oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16)code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image +// doesn't support it two back is the image from two frames ago, used for a very +// specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, + int req_comp, stbi_uc *two_back) { + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour + // (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp, 0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *)stbi__malloc(4 * pcount); + g->background = (stbi_uc *)stbi__malloc(4 * pcount); + g->history = (stbi_uc *)stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites + // the current background; background colour is only used for pixels that + // are not rendered first frame, after that "background" color refers to the + // color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, + 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, + pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the + // old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy(&g->out[pi * 4], &two_back[pi * 4], 4); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy(&g->out[pi * 4], &g->background[pi * 4], 4); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy(g->background, g->out, 4 * g->w * g->h); + } + + // clear my history; + memset(g->history, 0x00, + g->w * g->h); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; g->cur_x = g->start_x; - g->cur_y += g->step; + g->cur_y = g->start_y; - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } -} + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, init_code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; + g->lflags = stbi__get8(s); - lzw_cs = stbi__get8(s); - if (lzw_cs > 12) return NULL; - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (init_code = 0; init_code < clear; init_code++) { - g->codes[init_code].prefix = -1; - g->codes[init_code].first = (stbi_uc) init_code; - g->codes[init_code].suffix = (stbi_uc) init_code; - } - - // support no starting clear code - avail = clear+2; - oldcode = -1; - - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) { - return stbi__errpuc("no clear code", "Corrupt GIF"); - } - - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 8192) { - return stbi__errpuc("too many codes", "Corrupt GIF"); - } - - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - - stbi__out_gif_code(g, (stbi__uint16) code); - - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } - - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } + g->step = g->line_size; + g->parse = 0; } - } -} -// this function is designed to support animated gifs, although stb_image doesn't support it -// two back is the image from two frames ago, used for a very specific disposal format -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) -{ - int dispose; - int first_frame; - int pi; - int pcount; - STBI_NOTUSED(req_comp); + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s, g->lpal, 2 << (g->lflags & 7), + g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *)g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *)g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); - // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) - return stbi__errpuc("too large", "GIF image is too large"); + o = stbi__process_gif_raster(s, g); + if (!o) + return NULL; + + // if this was the first frame, pcount = g->w * g->h; - g->out = (stbi_uc *) stbi__malloc(4 * pcount); - g->background = (stbi_uc *) stbi__malloc(4 * pcount); - g->history = (stbi_uc *) stbi__malloc(pcount); - if (!g->out || !g->background || !g->history) - return stbi__errpuc("outofmem", "Out of memory"); - - // image is treated as "transparent" at the start - ie, nothing overwrites the current background; - // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to the color that was there the previous frame. - memset(g->out, 0x00, 4 * pcount); - memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) - memset(g->history, 0x00, pcount); // pixels that were affected previous frame - first_frame = 1; - } else { - // second frame - how do we dispose of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; - - if ((dispose == 3) && (two_back == 0)) { - dispose = 2; // if I don't have an image to revert back to, default to the old background + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = + 255; // just in case it was made transparent, undo that; It will + // be reset next frame if need be; + memcpy(&g->out[pi * 4], &g->pal[g->bgindex], 4); + } + } } - if (dispose == 3) { // use previous graphic - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = + 10 * stbi__get16le( + s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; } - } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); - } - } - } else { - // This is a non-disposal case eithe way, so just - // leave the pixels as is, and they will become the new background - // 1: do not dispose - // 0: not specified. + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } } - - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); - } - - // clear my history; - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - - for (;;) { - int tag = stbi__get8(s); - switch (tag) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi_uc *o; - - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; - - // if the width of the specified rectangle is 0, that means - // we may not see *any* pixels or the image is malformed; - // to make sure this is caught, move the current y down to - // max_y (which is what out_gif_code checks). - if (w == 0) - g->cur_y = g->max_y; - - g->lflags = stbi__get8(s); - - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } - - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (!o) return NULL; - - // if this was the first frame, - pcount = g->w * g->h; - if (first_frame && (g->bgindex > 0)) { - // if first frame, any pixel not drawn to gets the background color - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); - } - } - } - - return o; - } - - case 0x21: // Comment Extension. - { - int len; - int ext = stbi__get8(s); - if (ext == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. - - // unset old transparent - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } - if (g->eflags & 0x01) { - g->transparent = stbi__get8(s); - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; - } - } else { - // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; - } - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) { - stbi__skip(s, len); - } - break; - } - - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers - - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); } - } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *)s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } } -static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) -{ - STBI_FREE(g->out); - STBI_FREE(g->history); - STBI_FREE(g->background); +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, + int **delays) { + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); - if (out) STBI_FREE(out); - if (delays && *delays) STBI_FREE(*delays); - return stbi__errpuc("outofmem", "Out of memory"); + if (out) + STBI_FREE(out); + if (delays && *delays) + STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); } -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - if (stbi__gif_test(s)) { - int layers = 0; - stbi_uc *u = 0; - stbi_uc *out = 0; - stbi_uc *two_back = 0; - stbi__gif g; - int stride; - int out_size = 0; - int delays_size = 0; +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, + int *z, int *comp, int req_comp) { + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + int out_size = 0; + int delays_size = 0; - STBI_NOTUSED(out_size); - STBI_NOTUSED(delays_size); + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); - memset(&g, 0, sizeof(g)); - if (delays) { - *delays = 0; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *)s) + u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = + (stbi_uc *)STBI_REALLOC_SIZED(out, out_size, layers * stride); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc *)tmp; + out_size = layers * stride; + } + + if (delays) { + int *new_delays = (int *)STBI_REALLOC_SIZED(*delays, delays_size, + sizeof(int) * layers); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); + } + } else { + out = (stbi_uc *)stbi__malloc(layers * stride); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; + if (delays) { + *delays = (int *)stbi__malloc(layers * sizeof(int)); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); + } + } + memcpy(out + ((layers - 1) * stride), u, stride); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } } + } while (u != 0); - do { - u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - if (u) { - *x = g.w; - *y = g.h; - ++layers; - stride = g.w * g.h * 4; + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - if (out) { - void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); - if (!tmp) - return stbi__load_gif_main_outofmem(&g, out, delays); - else { - out = (stbi_uc*) tmp; - out_size = layers * stride; - } - - if (delays) { - int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); - if (!new_delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - *delays = new_delays; - delays_size = layers * sizeof(int); - } - } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); - if (!out) - return stbi__load_gif_main_outofmem(&g, out, delays); - out_size = layers * stride; - if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); - if (!*delays) - return stbi__load_gif_main_outofmem(&g, out, delays); - delays_size = layers * sizeof(int); - } - } - memcpy( out + ((layers - 1) * stride), u, stride ); - if (layers >= 2) { - two_back = out - 2 * stride; - } - - if (delays) { - (*delays)[layers - 1U] = g.delay; - } - } - } while (u != 0); - - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); - - // do the final conversion after loading everything; - if (req_comp && req_comp != 4) - out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - - *z = layers; - return out; - } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); - } + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } } -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); - STBI_NOTUSED(ri); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri) { + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); - u = stbi__gif_load_next(s, &g, comp, req_comp, 0); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *)s) + u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; - // moved conversion to after successful load so that the same - // can be done for multiple frames. - if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g.w, g.h); - } else if (g.out) { - // if there was an error and we allocated an image buffer, free it! - STBI_FREE(g.out); - } + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } - // free buffers needed for multiple frame loading; - STBI_FREE(g.history); - STBI_FREE(g.background); + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); - return u; + return u; } -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) { + return stbi__gif_info_raw(s, x, y, comp); } #endif @@ -7006,397 +7776,435 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s, const char *signature) -{ - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - stbi__rewind(s); - return 1; +static int stbi__hdr_test_core(stbi__context *s, const char *signature) { + int i; + for (i = 0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; } -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); - stbi__rewind(s); - if(!r) { - r = stbi__hdr_test_core(s, "#?RGBE\n"); - stbi__rewind(s); - } - return r; +static int stbi__hdr_test(stbi__context *s) { + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if (!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; } -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) { + int len = 0; + char c = '\0'; - c = (char) stbi__get8(z); + c = (char)stbi__get8(z); - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN - 1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char)stbi__get8(z); + } - buffer[len] = 0; - return buffer; + buffer[len] = 0; + return buffer; } -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) { + if (input[3] != 0) { + float f1; + // Exponent + f1 = (float)ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) + output[1] = 1; + if (req_comp == 4) + output[3] = 1; + } else { + switch (req_comp) { + case 4: + output[3] = 1; /* fallthrough */ + case 3: + output[0] = output[1] = output[2] = 0; + break; + case 2: + output[1] = 1; /* fallthrough */ + case 1: + output[0] = 0; + break; + } + } } -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - const char *headerToken; - STBI_NOTUSED(ri); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri) { + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1, c2, z; + const char *headerToken; + STBI_NOTUSED(ri); - // Check identifier - headerToken = stbi__hdr_gettoken(s,buffer); - if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); + // Check identifier + headerToken = stbi__hdr_gettoken(s, buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && + strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } + // Parse header + for (;;) { + token = stbi__hdr_gettoken(s, buffer); + if (token[0] == 0) + break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) + valid = 1; + } - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + if (!valid) + return stbi__errpf("unsupported format", "Unsupported HDR format"); - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s, buffer); + if (strncmp(token, "-Y ", 3)) + return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int)strtol(token, &token, 10); + while (*token == ' ') + ++token; + if (strncmp(token, "+X ", 3)) + return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int)strtol(token, NULL, 10); - if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); - if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (height > STBI_MAX_DIMENSIONS) + return stbi__errpf("too large", "Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) + return stbi__errpf("too large", "Very large image (corrupt?)"); - *x = width; - *y = height; + *x = width; + *y = height; - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; + if (comp) + *comp = 3; + if (req_comp == 0) + req_comp = 3; - if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) - return stbi__errpf("too large", "HDR image is too large"); + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); - // Read data - hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); - if (!hdr_data) - return stbi__errpf("outofmem", "Out of memory"); + // Read data + hdr_data = + (float *)stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } + // Load image data + // image data is stored as some number of sca + if (width < 8 || width >= 32768) { + // Read flat data + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, + req_comp); } - } else { - // Read RLE-encoded data - scanline = NULL; + } + } else { + // Read RLE-encoded data + scanline = NULL; - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) { - scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); - if (!scanline) { - STBI_FREE(hdr_data); - return stbi__errpf("outofmem", "Out of memory"); + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a + // decoded pixel (note this can't be a valid pixel--one of RGB must be + // >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc)c1; + rgbe[1] = (stbi_uc)c2; + rgbe[2] = (stbi_uc)len; + rgbe[3] = (stbi_uc)stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); + } + if (scanline == NULL) { + scanline = (stbi_uc *)stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); } - } - - for (k = 0; k < 4; ++k) { - int nleft; - i = 0; - while ((nleft = width - i) > 0) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } } - if (scanline) - STBI_FREE(scanline); - } + for (i = 0; i < width; ++i) + stbi__hdr_convert(hdr_data + (j * width + i) * req_comp, + scanline + i * 4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } - return hdr_data; + return hdr_data; } -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int dummy; +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) { + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; - if (stbi__hdr_test(s) == 0) { - stbi__rewind( s ); - return 0; - } + if (stbi__hdr_test(s) == 0) { + stbi__rewind(s); + return 0; + } - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } + for (;;) { + token = stbi__hdr_gettoken(s, buffer); + if (token[0] == 0) + break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) + valid = 1; + } - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; + if (!valid) { + stbi__rewind(s); + return 0; + } + token = stbi__hdr_gettoken(s, buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *y = (int)strtol(token, &token, 10); + while (*token == ' ') + ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *x = (int)strtol(token, NULL, 10); + *comp = 3; + return 1; } #endif // STBI_NO_HDR #ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - void *p; - stbi__bmp_data info; +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) { + void *p; + stbi__bmp_data info; - info.all_a = 255; - p = stbi__bmp_parse_header(s, &info); - if (p == NULL) { - stbi__rewind( s ); - return 0; - } - if (x) *x = s->img_x; - if (y) *y = s->img_y; - if (comp) { - if (info.bpp == 24 && info.ma == 0xff000000) - *comp = 3; - else - *comp = info.ma ? 4 : 3; - } - return 1; + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + if (p == NULL) { + stbi__rewind(s); + return 0; + } + if (x) + *x = s->img_x; + if (y) + *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; } #endif #ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount, dummy, depth; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 8 && depth != 16) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { + int channelCount, dummy, depth; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind(s); + return 0; + } + *comp = 4; + return 1; } -static int stbi__psd_is16(stbi__context *s) -{ - int channelCount, depth; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - STBI_NOTUSED(stbi__get32be(s)); - STBI_NOTUSED(stbi__get32be(s)); - depth = stbi__get16be(s); - if (depth != 16) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__psd_is16(stbi__context *s) { + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind(s); + return 0; + } + return 1; } #endif #ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained,dummy; - stbi__pic_packet packets[10]; +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) { + int act_comp = 0, num_packets = 0, chained, dummy; + stbi__pic_packet packets[10]; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + if (!stbi__pic_is4(s, "\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind(s); + return 0; + } + if ((*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets == sizeof(packets) / sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { stbi__rewind(s); return 0; - } - - stbi__skip(s, 88); - - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) { - stbi__rewind( s); + } + if (packet->size != 8) { + stbi__rewind(s); return 0; - } - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } + } + } while (chained); - stbi__skip(s, 8); + *comp = (act_comp & 0x10 ? 4 : 3); - do { - stbi__pic_packet *packet; - - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; - - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; - - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); - - *comp = (act_comp & 0x10 ? 4 : 3); - - return 1; + return 1; } #endif @@ -7413,269 +8221,281 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__pnm_test(stbi__context *s) { + char p, t; + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + return 1; } -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - STBI_NOTUSED(ri); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, + int req_comp, stbi__result_info *ri) { + stbi_uc *out; + STBI_NOTUSED(ri); - ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); - if (ri->bits_per_channel == 0) - return 0; + ri->bits_per_channel = + stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) + return 0; - if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); - if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_y > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) + return stbi__errpuc("too large", "Very large image (corrupt?)"); - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; + *x = s->img_x; + *y = s->img_y; + if (comp) + *comp = s->img_n; - if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) - return stbi__errpuc("too large", "PNM too large"); + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, + ri->bits_per_channel / 8, 0)) + return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + out = (stbi_uc *)stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, + ri->bits_per_channel / 8, 0); + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, + s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } + return out; } -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +static int stbi__pnm_isspace(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || + c == '\r'; } -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - for (;;) { - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) { + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char)stbi__get8(s); - if (stbi__at_eof(s) || *c != '#') - break; + if (stbi__at_eof(s) || *c != '#') + break; - while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) - *c = (char) stbi__get8(s); - } + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r') + *c = (char)stbi__get8(s); + } } -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; +static int stbi__pnm_isdigit(char c) { return c >= '0' && c <= '9'; } + +static int stbi__pnm_getinteger(stbi__context *s, char *c) { + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value * 10 + (*c - '0'); + *c = (char)stbi__get8(s); + } + + return value; } -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { + int maxv, dummy; + char c, p, t; - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; - return value; + stbi__rewind(s); + + // Get identifier + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = + (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char)stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + if (maxv > 65535) + return stbi__err("max value > 65535", + "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; + else + return 8; } -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv, dummy; - char c, p, t; - - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - - stbi__rewind(s); - - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind(s); - return 0; - } - - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); - - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); - - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); - - maxv = stbi__pnm_getinteger(s, &c); // read max value - if (maxv > 65535) - return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); - else if (maxv > 255) - return 16; - else - return 8; -} - -static int stbi__pnm_is16(stbi__context *s) -{ - if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) - return 1; - return 0; +static int stbi__pnm_is16(stbi__context *s) { + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) { +#ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) + return 1; +#endif - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +// test tga last because it's a crappy test! +#ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; +#endif + return stbi__err("unknown image type", + "Image not of any known type, or corrupt"); } -static int stbi__is_16_main(stbi__context *s) -{ - #ifndef STBI_NO_PNG - if (stbi__png_is16(s)) return 1; - #endif +static int stbi__is_16_main(stbi__context *s) { +#ifndef STBI_NO_PNG + if (stbi__png_is16(s)) + return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_is16(s)) return 1; - #endif +#ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) + return 1; +#endif - #ifndef STBI_NO_PNM - if (stbi__pnm_is16(s)) return 1; - #endif - return 0; +#ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) + return 1; +#endif + return 0; } #ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) { + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) + return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; } -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s, x, y, comp); + fseek(f, pos, SEEK_SET); + return r; } -STBIDEF int stbi_is_16_bit(char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_is_16_bit_from_file(f); - fclose(f); - return result; +STBIDEF int stbi_is_16_bit(char const *filename) { + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) + return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; } -STBIDEF int stbi_is_16_bit_from_file(FILE *f) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__is_16_main(&s); - fseek(f,pos,SEEK_SET); - return r; +STBIDEF int stbi_is_16_bit_from_file(FILE *f) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f, pos, SEEK_SET); + return r; } #endif // !STBI_NO_STDIO -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, + int *y, int *comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, + int *x, int *y, int *comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)c, user); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__is_16_main(&s); } -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, + void *user) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)c, user); + return stbi__is_16_main(&s); } #endif // STB_IMAGE_IMPLEMENTATION /* revision history: - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and + platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix + warnings 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug 1-bit BMP *_is_16_bit api avoid warnings @@ -7690,13 +8510,11 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user warning fixes; disable run-time SSE detection on gcc; uniform handling of optional "return" values; thread-safe initialization of zlib tables - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) allocate large structures on the stack - remove white matting for transparent PSD - fix reported channel count for PNG & BMP - re-enable SSE2 in non-gcc 64-bit + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet + JPGs 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now 2.12 + (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) + allocate large structures on the stack remove white matting for transparent + PSD fix reported channel count for PNG & BMP re-enable SSE2 in non-gcc 64-bit support RGB-formatted JPEG read 16-bit PNGs (only as 8-bit) 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED @@ -7704,11 +8522,9 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user 16-bit-per-pixel TGA (not bit-per-component) info() for TGA could break due to .hdr handling info() for BMP to shares code instead of sloppy parse - can use STBI_REALLOC_SIZED if allocator doesn't support realloc - code cleanup - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) fix compiler warnings - partial animated GIF support + can use STBI_REALLOC_SIZED if allocator doesn't support + realloc code cleanup 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD + as RGBA 2.07 (2015-09-13) fix compiler warnings partial animated GIF support limited 16-bpc PSD support #ifdef unused functions bug with < 92 byte PIC,PNM,HDR,TGA @@ -7719,23 +8535,18 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user stbi_set_flip_vertically_on_load (nguillemot) fix NEON support; fix mingw support 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit + without -msse2 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG 2.00 + (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) progressive + JPEG (stb) PGM/PPM support (Ken Miller) STBI_MALLOC,STBI_REALLOC,STBI_FREE GIF bugfix -- seemingly never worked STBI_NO_*, STBI_ONLY_* 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar + Cornut & stb) optimize PNG (ryg) fix bug in interlaced PNG with + user-specified channel count (stb) 1.46 (2014-08-26) fix broken tRNS chunk + (colorkey-style transparency) in non-paletted PNG 1.45 (2014-08-16) fix + MSVC-ARM internal compiler error by wrapping malloc 1.44 (2014-08-07) various warning fixes from Ronny Chevalier 1.43 (2014-07-15) fix MSVC-only compiler problem in code changed in 1.42 @@ -7744,73 +8555,48 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user fixes to stbi__cleanup_jpeg path added STBI_ASSERT to avoid requiring assert.h 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + fix search&replace from 1.36 that messed up comments/error + messages 1.40 (2014-06-22) fix gcc struct-initialization warning 1.39 + (2014-06-15) fix to TGA optimization when req_comp != number of components in + TGA; fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my + test suite) add support for BMP version 5 (more ignored fields) 1.38 + (2014-06-06) suppress MSVC warnings on integer casts truncating values fix + accidental rename of 'skip' field of I/O 1.37 (2014-06-04) remove duplicate + typedef 1.36 (2014-06-03) convert to header file single-file library if + de-iphone isn't set, load iphone images color-swapped instead of returning + NULL 1.35 (2014-05-27) various warnings fix broken STBI_SIMD path fix bug + where stbi_load_from_file no longer left file pointer in correct place fix + broken non-easy path for 32-bit BMP (possibly never used) TGA optimization by + Arseny Kapoulkine 1.34 (unknown) use STBI_NOTUSED in + stbi__resample_row_generic(), fix one more leak in tga failure case 1.33 + (2011-07-14) make stbi_is_hdr work in STBI_NO_HDR (as specified), minor + compiler-friendly improvements 1.32 (2011-07-13) support for "info" function + for all supported filetypes (SpartanJ) 1.31 (2011-06-20) a few more leak + fixes, bug in PNG handling (SpartanJ) 1.30 (2011-06-11) added ability to + load files via callbacks to accomidate custom input streams (Ben Wenger) removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher + removed support for installable file formats (stbi_loader) -- + would have been broken for IO callbacks anyway error cases in bmp and tga + give messages and don't leak (Raymond Barbiero, grisha) fix inefficiency in + decoding 32-bit BMP (David Woo) 1.29 (2010-08-16) various warning fixes from + Aurelien Pocheville 1.28 (2010-08-01) fix bug in GIF palette transparency + (SpartanJ) 1.27 (2010-08-01) cast-to-stbi_uc to fix warnings 1.26 + (2010-07-24) fix bug in file buffering for PNG reported by SpartanJ 1.25 + (2010-07-17) refix trans_data warning (Won Chun) 1.24 (2010-07-12) perf + improvements reading from files on platforms with lock-heavy fgetc() minor + perf improvements for jpeg deprecated type-specific functions so we'll get + feedback if they're needed attempt to fix trans_data warning (Won Chun) 1.23 + fixed bug in iPhone support 1.22 (2010-07-10) removed image *writing* + support stbi_info support from Jetro Lauha GIF support from Jean-Marc Lienher iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 (2008-08-02) - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. + Janez (U+017D)emva) 1.21 fix use of 'stbi_uc' in header (reported by jon + blow) 1.20 added support for Softimage PIC, by Tom Seddon 1.19 bug in + interlaced PNG corruption check (found by ryg) 1.18 (2008-08-02) fix a + threading bug (local mutable static) 1.17 support interlaced PNG 1.16 + major bugfix - stbi__convert_format converted one too many pixels 1.15 + initialize some fields for thread safety 1.14 fix threadsafe conversion + bug header-file-only version (#define STBI_HEADER_FILE_ONLY before including) 1.13 threadsafe 1.12 const qualifiers in the API 1.11 Support installable IDCT, colorspace conversion routines @@ -7820,15 +8606,14 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz 1.07 attempt to fix C++ warning/errors again 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 1.05 fix TGA loading to return correct *comp and use good luminance + calc 1.04 default float alpha is 1, not 255; use 'void *' for + stbi_image_free 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR 1.02 support + for (subset of) HDR files, float interface for preferred access to them 1.01 + fix bug: possible bug in handling right-side up bmps... not sure fix bug: the + stbi__bmp_load() and stbi__tga_load() functions didn't work at all 1.00 + interface to zlib that skips zlib header 0.99 correct handling of alpha in + palette 0.98 TGA loader by lonesock; dynamically add loaders (untested) 0.97 jpeg errors on too large a file; also catch another malloc failure 0.96 fix detection of invalid v value - particleman@mollyrocket forum 0.95 during header scan, seek to markers in case of padding @@ -7841,8 +8626,8 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user 0.60 fix compiling as c++ 0.59 fix warnings: merge Dave Moore's -Wall fixes 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but + less than 16 available 0.56 fix bug: zlib uncompressed mode len vs. nlen 0.55 fix bug: restart_interval not initialized to 0 0.54 allow NULL for 'int *comp' 0.53 fix bug in png 3->4; speedup png decoding @@ -7853,7 +8638,6 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user first released version */ - /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. diff --git a/include/renderd7/external/stb_image_write.h b/include/renderd7/external/stb_image_write.h index e4b32ed..1adf974 100644 --- a/include/renderd7/external/stb_image_write.h +++ b/include/renderd7/external/stb_image_write.h @@ -26,11 +26,12 @@ BUILDING: You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace malloc,realloc,free. You can #define STBIW_MEMMOVE() to replace memmove() - You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function - for PNG compression (instead of the builtin one), it must have the following signature: - unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); - The returned data will be freed with STBIW_FREE() (free() by default), - so it must be heap allocated with STBIW_MALLOC() (malloc() by default), + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress +function for PNG compression (instead of the builtin one), it must have the +following signature: unsigned char * my_compress(unsigned char *data, int +data_len, int *out_len, int quality); The returned data will be freed with +STBIW_FREE() (free() by default), so it must be heap allocated with +STBIW_MALLOC() (malloc() by default), UNICODE: @@ -44,30 +45,37 @@ USAGE: There are five functions, one for each image file format: - int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); - int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); - int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); - int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); - int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); + int stbi_write_png(char const *filename, int w, int h, int comp, const void +*data, int stride_in_bytes); int stbi_write_bmp(char const *filename, int w, int +h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, +int h, int comp, const void *data); int stbi_write_jpg(char const *filename, int +w, int h, int comp, const void *data, int quality); int stbi_write_hdr(char +const *filename, int w, int h, int comp, const float *data); - void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically + void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip +data vertically - There are also five equivalent functions that use an arbitrary write function. You are - expected to open/close your file-equivalent before and after calling these: + There are also five equivalent functions that use an arbitrary write +function. You are expected to open/close your file-equivalent before and after +calling these: - int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); - int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); - int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int +h, int comp, const void *data, int stride_in_bytes); int +stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int +comp, const void *data); int stbi_write_tga_to_func(stbi_write_func *func, void +*context, int w, int h, int comp, const void *data); int +stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int +comp, const float *data); int stbi_write_jpg_to_func(stbi_write_func *func, void +*context, int x, int y, int comp, const void *data, int quality); where the callback is: void stbi_write_func(void *context, void *data, int size); You can configure it with these global variables: - int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE - int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression - int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode + int stbi_write_tga_with_rle; // defaults to true; set to 0 to +disable RLE int stbi_write_png_compression_level; // defaults to 8; set to +higher for more compression int stbi_write_force_png_filter; // defaults +to -1; set to 0..5 to force a filter mode You can define STBI_WRITE_NO_STDIO to disable the file variant of these @@ -153,99 +161,114 @@ LICENSE #include -// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' +// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' +// or 'static inline' #ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC -#define STBIWDEF static +#define STBIWDEF static #else #ifdef __cplusplus -#define STBIWDEF extern "C" +#define STBIWDEF extern "C" #else -#define STBIWDEF extern +#define STBIWDEF extern #endif #endif #endif -#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations STBIWDEF int stbi_write_tga_with_rle; STBIWDEF int stbi_write_png_compression_level; STBIWDEF int stbi_write_force_png_filter; #endif #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); -STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, + const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, + const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, + const void *data); +STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, + const float *data); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, + const void *data, int quality); #ifdef STBIW_WINDOWS_UTF8 -STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, + const wchar_t *input); #endif #endif typedef void stbi_write_func(void *context, void *data, int size); -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); -STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, + int h, int comp, const void *data, + int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, + int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, + int h, int comp, const void *data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, + int h, int comp, const float *data); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, + int y, int comp, const void *data, + int quality); STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); -#endif//INCLUDE_STB_IMAGE_WRITE_H +#endif // INCLUDE_STB_IMAGE_WRITE_H #ifdef STB_IMAGE_WRITE_IMPLEMENTATION #ifdef _WIN32 - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - #ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE - #endif +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif #endif #ifndef STBI_WRITE_NO_STDIO #include #endif // STBI_WRITE_NO_STDIO +#include #include #include #include -#include -#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) +#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && \ + (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) // ok -#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) +#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && \ + !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) // ok #else -#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." +#error \ + "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." #endif #ifndef STBIW_MALLOC -#define STBIW_MALLOC(sz) malloc(sz) -#define STBIW_REALLOC(p,newsz) realloc(p,newsz) -#define STBIW_FREE(p) free(p) +#define STBIW_MALLOC(sz) malloc(sz) +#define STBIW_REALLOC(p, newsz) realloc(p, newsz) +#define STBIW_FREE(p) free(p) #endif #ifndef STBIW_REALLOC_SIZED -#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#define STBIW_REALLOC_SIZED(p, oldsz, newsz) STBIW_REALLOC(p, newsz) #endif - #ifndef STBIW_MEMMOVE -#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#define STBIW_MEMMOVE(a, b, sz) memmove(a, b, sz) #endif - #ifndef STBIW_ASSERT #include #define STBIW_ASSERT(x) assert(x) #endif -#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) +#define STBIW_UCHAR(x) (unsigned char)((x)&0xff) #ifdef STB_IMAGE_WRITE_STATIC static int stbi_write_png_compression_level = 8; @@ -259,31 +282,28 @@ int stbi_write_force_png_filter = -1; static int stbi__flip_vertically_on_write = 0; -STBIWDEF void stbi_flip_vertically_on_write(int flag) -{ - stbi__flip_vertically_on_write = flag; +STBIWDEF void stbi_flip_vertically_on_write(int flag) { + stbi__flip_vertically_on_write = flag; } -typedef struct -{ - stbi_write_func *func; - void *context; - unsigned char buffer[64]; - int buf_used; +typedef struct { + stbi_write_func *func; + void *context; + unsigned char buffer[64]; + int buf_used; } stbi__write_context; // initialize a callback-based context -static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) -{ - s->func = c; - s->context = context; +static void stbi__start_write_callbacks(stbi__write_context *s, + stbi_write_func *c, void *context) { + s->func = c; + s->context = context; } #ifndef STBI_WRITE_NO_STDIO -static void stbi__stdio_write(void *context, void *data, int size) -{ - fwrite(data,1,size,(FILE*) context); +static void stbi__stdio_write(void *context, void *data, int size) { + fwrite(data, 1, size, (FILE *)context); } #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) @@ -292,339 +312,364 @@ static void stbi__stdio_write(void *context, void *data, int size) #else #define STBIW_EXTERN extern #endif -STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar( + unsigned int cp, unsigned long flags, const char *str, int cbmb, + wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte( + unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, + char *str, int cbmb, const char *defchar, int *used_default); -STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) -{ - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, + const wchar_t *input) { + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, + (int)bufferlen, NULL, NULL); } #endif -static FILE *stbiw__fopen(char const *filename, char const *mode) -{ - FILE *f; +static FILE *stbiw__fopen(char const *filename, char const *mode) { + FILE *f; #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) - wchar_t wMode[64]; - wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) - return 0; + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, + sizeof(wFilename) / sizeof(*wFilename))) + return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) - return 0; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, + sizeof(wMode) / sizeof(*wMode))) + return 0; #if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else - f = _wfopen(wFilename, wMode); + f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; + if (0 != fopen_s(&f, filename, mode)) + f = 0; #else - f = fopen(filename, mode); + f = fopen(filename, mode); #endif - return f; + return f; } -static int stbi__start_write_file(stbi__write_context *s, const char *filename) -{ - FILE *f = stbiw__fopen(filename, "wb"); - stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); - return f != NULL; +static int stbi__start_write_file(stbi__write_context *s, + const char *filename) { + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *)f); + return f != NULL; } -static void stbi__end_write_file(stbi__write_context *s) -{ - fclose((FILE *)s->context); +static void stbi__end_write_file(stbi__write_context *s) { + fclose((FILE *)s->context); } #endif // !STBI_WRITE_NO_STDIO typedef unsigned int stbiw_uint32; -typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; +typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1]; -static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) -{ - while (*fmt) { - switch (*fmt++) { - case ' ': break; - case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); - s->func(s->context,&x,1); - break; } - case '2': { int x = va_arg(v,int); - unsigned char b[2]; - b[0] = STBIW_UCHAR(x); - b[1] = STBIW_UCHAR(x>>8); - s->func(s->context,b,2); - break; } - case '4': { stbiw_uint32 x = va_arg(v,int); - unsigned char b[4]; - b[0]=STBIW_UCHAR(x); - b[1]=STBIW_UCHAR(x>>8); - b[2]=STBIW_UCHAR(x>>16); - b[3]=STBIW_UCHAR(x>>24); - s->func(s->context,b,4); - break; } - default: - STBIW_ASSERT(0); - return; - } - } -} - -static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); -} - -static void stbiw__write_flush(stbi__write_context *s) -{ - if (s->buf_used) { - s->func(s->context, &s->buffer, s->buf_used); - s->buf_used = 0; - } -} - -static void stbiw__putc(stbi__write_context *s, unsigned char c) -{ - s->func(s->context, &c, 1); -} - -static void stbiw__write1(stbi__write_context *s, unsigned char a) -{ - if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) - stbiw__write_flush(s); - s->buffer[s->buf_used++] = a; -} - -static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) -{ - int n; - if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) - stbiw__write_flush(s); - n = s->buf_used; - s->buf_used = n+3; - s->buffer[n+0] = a; - s->buffer[n+1] = b; - s->buffer[n+2] = c; -} - -static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) -{ - unsigned char bg[3] = { 255, 0, 255}, px[3]; - int k; - - if (write_alpha < 0) - stbiw__write1(s, d[comp - 1]); - - switch (comp) { - case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case - case 1: - if (expand_mono) - stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp - else - stbiw__write1(s, d[0]); // monochrome TGA - break; - case 4: - if (!write_alpha) { - // composite against pink background - for (k = 0; k < 3; ++k) - px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; - stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); - break; - } - /* FALLTHROUGH */ - case 3: - stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); - break; - } - if (write_alpha > 0) - stbiw__write1(s, d[comp - 1]); -} - -static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) -{ - stbiw_uint32 zero = 0; - int i,j, j_end; - - if (y <= 0) +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) { + while (*fmt) { + switch (*fmt++) { + case ' ': + break; + case '1': { + unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context, &x, 1); + break; + } + case '2': { + int x = va_arg(v, int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x >> 8); + s->func(s->context, b, 2); + break; + } + case '4': { + stbiw_uint32 x = va_arg(v, int); + unsigned char b[4]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x >> 8); + b[2] = STBIW_UCHAR(x >> 16); + b[3] = STBIW_UCHAR(x >> 24); + s->func(s->context, b, 4); + break; + } + default: + STBIW_ASSERT(0); return; - - if (stbi__flip_vertically_on_write) - vdir *= -1; - - if (vdir < 0) { - j_end = -1; j = y-1; - } else { - j_end = y; j = 0; - } - - for (; j != j_end; j += vdir) { - for (i=0; i < x; ++i) { - unsigned char *d = (unsigned char *) data + (j*x+i)*comp; - stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); - } - stbiw__write_flush(s); - s->func(s->context, &zero, scanline_pad); - } + } + } } -static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) -{ - if (y < 0 || x < 0) { - return 0; - } else { - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); - stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); - return 1; - } +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); } -static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) -{ - if (comp != 4) { - // write RGB bitmap - int pad = (-x*3) & 3; - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, - "11 4 22 4" "4 44 22 444444", - 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header - 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header - } else { - // RGBA bitmaps need a v4 header - // use BI_BITFIELDS mode with 32bpp and alpha mask - // (straight BI_RGB with alpha mask doesn't work in most readers) - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, - "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", - 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header - 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header - } +static void stbiw__write_flush(stbi__write_context *s) { + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } } -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s = { 0 }; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_bmp_core(&s, x, y, comp, data); +static void stbiw__putc(stbi__write_context *s, unsigned char c) { + s->func(s->context, &c, 1); +} + +static void stbiw__write1(stbi__write_context *s, unsigned char a) { + if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + +static void stbiw__write3(stbi__write_context *s, unsigned char a, + unsigned char b, unsigned char c) { + int n; + if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n + 3; + s->buffer[n + 0] = a; + s->buffer[n + 1] = b; + s->buffer[n + 2] = c; +} + +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, + int write_alpha, int expand_mono, + unsigned char *d) { + unsigned char bg[3] = {255, 0, 255}, px[3]; + int k; + + if (write_alpha < 0) + stbiw__write1(s, d[comp - 1]); + + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as + // 1-channel case + case 1: + if (expand_mono) + stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp + else + stbiw__write1(s, d[0]); // monochrome TGA + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k = 0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + stbiw__write1(s, d[comp - 1]); +} + +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, + int x, int y, int comp, void *data, + int write_alpha, int scanline_pad, + int expand_mono) { + stbiw_uint32 zero = 0; + int i, j, j_end; + + if (y <= 0) + return; + + if (stbi__flip_vertically_on_write) + vdir *= -1; + + if (vdir < 0) { + j_end = -1; + j = y - 1; + } else { + j_end = y; + j = 0; + } + + for (; j != j_end; j += vdir) { + for (i = 0; i < x; ++i) { + unsigned char *d = (unsigned char *)data + (j * x + i) * comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + stbiw__write_flush(s); + s->func(s->context, &zero, scanline_pad); + } +} + +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, + int y, int comp, int expand_mono, void *data, + int alpha, int pad, const char *fmt, ...) { + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s, rgb_dir, vdir, x, y, comp, data, alpha, pad, + expand_mono); + return 1; + } +} + +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, + const void *data) { + if (comp != 4) { + // write RGB bitmap + int pad = (-x * 3) & 3; + return stbiw__outfile(s, -1, -1, x, y, comp, 1, (void *)data, 0, pad, + "11 4 22 4" + "4 44 22 444444", + 'B', 'M', 14 + 40 + (x * 3 + pad) * y, 0, 0, + 14 + 40, // file header + 40, x, y, 1, 24, 0, 0, 0, 0, 0, 0); // bitmap header + } else { + // RGBA bitmaps need a v4 header + // use BI_BITFIELDS mode with 32bpp and alpha mask + // (straight BI_RGB with alpha mask doesn't work in most readers) + return stbiw__outfile( + s, -1, -1, x, y, comp, 1, (void *)data, 1, 0, + "11 4 22 4" + "4 44 22 444444 4444 4 444 444 444 444", + 'B', 'M', 14 + 108 + x * y * 4, 0, 0, 14 + 108, // file header + 108, x, y, 1, 32, 3, 0, 0, 0, 0, 0, 0xff0000, 0xff00, 0xff, 0xff000000u, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // bitmap V4 header + } +} + +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, + int y, int comp, const void *data) { + stbi__write_context s = {0}; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s = { 0 }; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_bmp_core(&s, x, y, comp, data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, + const void *data) { + stbi__write_context s = {0}; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; } -#endif //!STBI_WRITE_NO_STDIO +#endif //! STBI_WRITE_NO_STDIO -static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) -{ - int has_alpha = (comp == 2 || comp == 4); - int colorbytes = has_alpha ? comp-1 : comp; - int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, + void *data) { + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp - 1 : comp; + int format = + colorbytes < 2 + ? 3 + : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 - if (y < 0 || x < 0) - return 0; + if (y < 0 || x < 0) + return 0; - if (!stbi_write_tga_with_rle) { - return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, - "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); - } else { - int i,j,k; - int jend, jdir; + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *)data, has_alpha, 0, + "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, + (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i, j, k; + int jend, jdir; - stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + stbiw__writef(s, "111 221 2222 11", 0, 0, format + 8, 0, 0, 0, 0, 0, x, y, + (colorbytes + has_alpha) * 8, has_alpha * 8); - if (stbi__flip_vertically_on_write) { - j = 0; - jend = y; - jdir = 1; - } else { - j = y-1; - jend = -1; - jdir = -1; - } - for (; j != jend; j += jdir) { - unsigned char *row = (unsigned char *) data + j * x * comp; - int len; + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y - 1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *)data + j * x * comp; + int len; - for (i = 0; i < x; i += len) { - unsigned char *begin = row + i * comp; - int diff = 1; - len = 1; + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; - if (i < x - 1) { - ++len; - diff = memcmp(begin, row + (i + 1) * comp, comp); - if (diff) { - const unsigned char *prev = begin; - for (k = i + 2; k < x && len < 128; ++k) { - if (memcmp(prev, row + k * comp, comp)) { - prev += comp; - ++len; - } else { - --len; - break; - } - } - } else { - for (k = i + 2; k < x && len < 128; ++k) { - if (!memcmp(begin, row + k * comp, comp)) { - ++len; - } else { - break; - } - } - } + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } } - - if (diff) { - unsigned char header = STBIW_UCHAR(len - 1); - stbiw__write1(s, header); - for (k = 0; k < len; ++k) { - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); - } - } else { - unsigned char header = STBIW_UCHAR(len - 129); - stbiw__write1(s, header); - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } } - } + } + } + + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + stbiw__write1(s, header); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + stbiw__write1(s, header); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } } - stbiw__write_flush(s); - } - return 1; + } + stbiw__write_flush(s); + } + return 1; } -STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s = { 0 }; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_tga_core(&s, x, y, comp, (void *) data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, + int y, int comp, const void *data) { + stbi__write_context s = {0}; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *)data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s = { 0 }; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, + const void *data) { + stbi__write_context s = {0}; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *)data); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif @@ -632,996 +677,1293 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const // Radiance RGBE HDR writer // by Baldur Karlsson -#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) #ifndef STBI_WRITE_NO_STDIO -static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) -{ - int exponent; - float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); - if (maxcomp < 1e-32f) { - rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; - } else { - float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float)frexp(maxcomp, &exponent) * 256.0f / maxcomp; - rgbe[0] = (unsigned char)(linear[0] * normalize); - rgbe[1] = (unsigned char)(linear[1] * normalize); - rgbe[2] = (unsigned char)(linear[2] * normalize); - rgbe[3] = (unsigned char)(exponent + 128); - } + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } } -static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) -{ - unsigned char lengthbyte = STBIW_UCHAR(length+128); - STBIW_ASSERT(length+128 <= 255); - s->func(s->context, &lengthbyte, 1); - s->func(s->context, &databyte, 1); +static void stbiw__write_run_data(stbi__write_context *s, int length, + unsigned char databyte) { + unsigned char lengthbyte = STBIW_UCHAR(length + 128); + STBIW_ASSERT(length + 128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); } -static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) -{ - unsigned char lengthbyte = STBIW_UCHAR(length); - STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code - s->func(s->context, &lengthbyte, 1); - s->func(s->context, data, length); +static void stbiw__write_dump_data(stbi__write_context *s, int length, + unsigned char *data) { + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= + 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); } -static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) -{ - unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; - unsigned char rgbe[4]; - float linear[3]; - int x; +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, + int ncomp, unsigned char *scratch, + float *scanline) { + unsigned char scanlineheader[4] = {2, 2, 0, 0}; + unsigned char rgbe[4]; + float linear[3]; + int x; - scanlineheader[2] = (width&0xff00)>>8; - scanlineheader[3] = (width&0x00ff); + scanlineheader[2] = (width & 0xff00) >> 8; + scanlineheader[3] = (width & 0x00ff); - /* skip RLE for images too small or large */ - if (width < 8 || width >= 32768) { - for (x=0; x < width; x++) { - switch (ncomp) { - case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; - default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - s->func(s->context, rgbe, 4); + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x = 0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: + linear[2] = scanline[x * ncomp + 2]; + linear[1] = scanline[x * ncomp + 1]; + linear[0] = scanline[x * ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0]; + break; } - } else { - int c,r; - /* encode into scratch buffer */ - for (x=0; x < width; x++) { - switch(ncomp) { - case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; - default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - scratch[x + width*0] = rgbe[0]; - scratch[x + width*1] = rgbe[1]; - scratch[x + width*2] = rgbe[2]; - scratch[x + width*3] = rgbe[3]; + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c, r; + /* encode into scratch buffer */ + for (x = 0; x < width; x++) { + switch (ncomp) { + case 4: /* fallthrough */ + case 3: + linear[2] = scanline[x * ncomp + 2]; + linear[1] = scanline[x * ncomp + 1]; + linear[0] = scanline[x * ncomp + 0]; + break; + default: + linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0]; + break; } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width * 0] = rgbe[0]; + scratch[x + width * 1] = rgbe[1]; + scratch[x + width * 2] = rgbe[2]; + scratch[x + width * 3] = rgbe[3]; + } - s->func(s->context, scanlineheader, 4); + s->func(s->context, scanlineheader, 4); - /* RLE each component separately */ - for (c=0; c < 4; c++) { - unsigned char *comp = &scratch[width*c]; + /* RLE each component separately */ + for (c = 0; c < 4; c++) { + unsigned char *comp = &scratch[width * c]; - x = 0; - while (x < width) { - // find first run - r = x; - while (r+2 < width) { - if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) - break; - ++r; - } - if (r+2 >= width) - r = width; - // dump up to first run - while (x < r) { - int len = r-x; - if (len > 128) len = 128; - stbiw__write_dump_data(s, len, &comp[x]); - x += len; - } - // if there's a run, output it - if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd - // find next byte after run - while (r < width && comp[r] == comp[x]) - ++r; - // output run up to r - while (x < r) { - int len = r-x; - if (len > 127) len = 127; - stbiw__write_run_data(s, len, comp[x]); - x += len; - } - } - } + x = 0; + while (x < width) { + // find first run + r = x; + while (r + 2 < width) { + if (comp[r] == comp[r + 1] && comp[r] == comp[r + 2]) + break; + ++r; + } + if (r + 2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r - x; + if (len > 128) + len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r + 2 < width) { // same test as what we break out of in search + // loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r - x; + if (len > 127) + len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } } - } + } + } } -static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) -{ - if (y <= 0 || x <= 0 || data == NULL) - return 0; - else { - // Each component is stored separately. Allocate scratch space for full output scanline. - unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); - int i, len; - char buffer[128]; - char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; - s->func(s->context, header, sizeof(header)-1); +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, + float *data) { + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full + // output scanline. + unsigned char *scratch = (unsigned char *)STBIW_MALLOC(x * 4); + int i, len; + char buffer[128]; + char header[] = + "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header) - 1); #ifdef __STDC_LIB_EXT1__ - len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = + sprintf_s(buffer, sizeof(buffer), + "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else - len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", + y, x); #endif - s->func(s->context, buffer, len); + s->func(s->context, buffer, len); - for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); - STBIW_FREE(scratch); - return 1; - } + for (i = 0; i < y; i++) + stbiw__write_hdr_scanline( + s, x, comp, scratch, + data + comp * x * (stbi__flip_vertically_on_write ? y - 1 - i : i)); + STBIW_FREE(scratch); + return 1; + } } -STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) -{ - stbi__write_context s = { 0 }; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, + int y, int comp, const float *data) { + stbi__write_context s = {0}; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *)data); } -STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) -{ - stbi__write_context s = { 0 }; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, + const float *data) { + stbi__write_context s = {0}; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *)data); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif // STBI_WRITE_NO_STDIO - ////////////////////////////////////////////////////////////////////////////// // // PNG writer // #ifndef STBIW_ZLIB_COMPRESS -// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() -#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) -#define stbiw__sbm(a) stbiw__sbraw(a)[0] -#define stbiw__sbn(a) stbiw__sbraw(a)[1] +// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() +// == vector<>::size() +#define stbiw__sbraw(a) ((int *)(void *)(a)-2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] -#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) -#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) -#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) +#define stbiw__sbneedgrow(a, n) ((a) == 0 || stbiw__sbn(a) + n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a, n) \ + (stbiw__sbneedgrow(a, (n)) ? stbiw__sbgrow(a, n) : 0) +#define stbiw__sbgrow(a, n) stbiw__sbgrowf((void **)&(a), (n), sizeof(*(a))) -#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) -#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) -#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) +#define stbiw__sbpush(a, v) \ + (stbiw__sbmaybegrow(a, 1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)), 0 : 0) -static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) -{ - int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; - void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); - STBIW_ASSERT(p); - if (p) { - if (!*arr) ((int *) p)[1] = 0; - *arr = (void *) ((int *) p + 2); - stbiw__sbm(*arr) = m; - } - return *arr; +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) { + int m = *arr ? 2 * stbiw__sbm(*arr) + increment : increment + 1; + void *p = STBIW_REALLOC_SIZED( + *arr ? stbiw__sbraw(*arr) : 0, + *arr ? (stbiw__sbm(*arr) * itemsize + sizeof(int) * 2) : 0, + itemsize * m + sizeof(int) * 2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) + ((int *)p)[1] = 0; + *arr = (void *)((int *)p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; } -static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) -{ - while (*bitcount >= 8) { - stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); - *bitbuffer >>= 8; - *bitcount -= 8; - } - return data; +static unsigned char *stbiw__zlib_flushf(unsigned char *data, + unsigned int *bitbuffer, + int *bitcount) { + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; } -static int stbiw__zlib_bitrev(int code, int codebits) -{ - int res=0; - while (codebits--) { - res = (res << 1) | (code & 1); - code >>= 1; - } - return res; +static int stbiw__zlib_bitrev(int code, int codebits) { + int res = 0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; } -static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) -{ - int i; - for (i=0; i < limit && i < 258; ++i) - if (a[i] != b[i]) break; - return i; +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, + int limit) { + int i; + for (i = 0; i < limit && i < 258; ++i) + if (a[i] != b[i]) + break; + return i; } -static unsigned int stbiw__zhash(unsigned char *data) -{ - stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - return hash; +static unsigned int stbiw__zhash(unsigned char *data) { + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; } #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) -#define stbiw__zlib_add(code,codebits) \ - (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) -#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +#define stbiw__zlib_add(code, codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b, c) stbiw__zlib_add(stbiw__zlib_bitrev(b, c), c) // default huffman tables -#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) -#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) -#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) -#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) -#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) -#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256, 7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280, 8) +#define stbiw__zlib_huff(n) \ + ((n) <= 143 ? stbiw__zlib_huff1(n) \ + : (n) <= 255 ? stbiw__zlib_huff2(n) \ + : (n) <= 279 ? stbiw__zlib_huff3(n) \ + : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huffb(n) \ + ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) -#define stbiw__ZHASH 16384 +#define stbiw__ZHASH 16384 #endif // STBIW_ZLIB_COMPRESS -STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) -{ +STBIWDEF unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, + int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS - // user provided a zlib compress implementation, use that - return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); -#else // use builtin - static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; - static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; - static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; - static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; - unsigned int bitbuf=0; - int i,j, bitcount=0; - unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); - if (hash_table == NULL) - return NULL; - if (quality < 5) quality = 5; + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, + 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 259}; + static unsigned char lengtheb[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static unsigned short distc[] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32768}; + static unsigned char disteb[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + unsigned int bitbuf = 0; + int i, j, bitcount = 0; + unsigned char *out = NULL; + unsigned char ***hash_table = + (unsigned char ***)STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char **)); + if (hash_table == NULL) + return NULL; + if (quality < 5) + quality = 5; - stbiw__sbpush(out, 0x78); // DEFLATE 32K window - stbiw__sbpush(out, 0x5e); // FLEVEL = 1 - stbiw__zlib_add(1,1); // BFINAL = 1 - stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1, 1); // BFINAL = 1 + stbiw__zlib_add(1, 2); // BTYPE = 1 -- fixed huffman - for (i=0; i < stbiw__ZHASH; ++i) - hash_table[i] = NULL; + for (i = 0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; - i=0; - while (i < data_len-3) { - // hash next 3 bytes of data to be compressed - int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; - unsigned char *bestloc = 0; - unsigned char **hlist = hash_table[h]; - int n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32768) { // if entry lies within window - int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) { best=d; bestloc=hlist[j]; } - } + i = 0; + while (i < data_len - 3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data + i) & (stbiw__ZHASH - 1), best = 3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j = 0; j < n; ++j) { + if (hlist[j] - data > i - 32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data + i, data_len - i); + if (d >= best) { + best = d; + bestloc = hlist[j]; + } } - // when hash table entry is too long, delete half the entries - if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { - STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); - stbiw__sbn(hash_table[h]) = quality; - } - stbiw__sbpush(hash_table[h],data+i); + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2 * quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h] + quality, + sizeof(hash_table[h][0]) * quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h], data + i); - if (bestloc) { - // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal - h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); - hlist = hash_table[h]; - n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32767) { - int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); - if (e > best) { // if next match is better, bail on current match - bestloc = NULL; - break; - } - } - } + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do + // cur byte as literal + h = stbiw__zhash(data + i + 1) & (stbiw__ZHASH - 1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j = 0; j < n; ++j) { + if (hlist[j] - data > i - 32767) { + int e = stbiw__zlib_countm(hlist[j], data + i + 1, data_len - i - 1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } } + } - if (bestloc) { - int d = (int) (data+i - bestloc); // distance back - STBIW_ASSERT(d <= 32767 && best <= 258); - for (j=0; best > lengthc[j+1]-1; ++j); - stbiw__zlib_huff(j+257); - if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); - for (j=0; d > distc[j+1]-1; ++j); - stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); - if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); - i += best; - } else { - stbiw__zlib_huffb(data[i]); - ++i; - } - } - // write out final bytes - for (;i < data_len; ++i) + if (bestloc) { + int d = (int)(data + i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j = 0; best > lengthc[j + 1] - 1; ++j) + ; + stbiw__zlib_huff(j + 257); + if (lengtheb[j]) + stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j = 0; d > distc[j + 1] - 1; ++j) + ; + stbiw__zlib_add(stbiw__zlib_bitrev(j, 5), 5); + if (disteb[j]) + stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { stbiw__zlib_huffb(data[i]); - stbiw__zlib_huff(256); // end of block - // pad with 0 bits to byte boundary - while (bitcount) - stbiw__zlib_add(0,1); + ++i; + } + } + // write out final bytes + for (; i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0, 1); - for (i=0; i < stbiw__ZHASH; ++i) - (void) stbiw__sbfree(hash_table[i]); - STBIW_FREE(hash_table); + for (i = 0; i < stbiw__ZHASH; ++i) + (void)stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); - // store uncompressed instead if compression was worse - if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { - stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 - for (j = 0; j < data_len;) { - int blocklen = data_len - j; - if (blocklen > 32767) blocklen = 32767; - stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression - stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN - stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN - stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); - memcpy(out+stbiw__sbn(out), data+j, blocklen); - stbiw__sbn(out) += blocklen; - j += blocklen; + // store uncompressed instead if compression was worse + if (stbiw__sbn(out) > data_len + 2 + ((data_len + 32766) / 32767) * 5) { + stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 + for (j = 0; j < data_len;) { + int blocklen = data_len - j; + if (blocklen > 32767) + blocklen = 32767; + stbiw__sbpush(out, + data_len - j == + blocklen); // BFINAL = ?, BTYPE = 0 -- no compression + stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN + stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN + stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); + memcpy(out + stbiw__sbn(out), data + j, blocklen); + stbiw__sbn(out) += blocklen; + j += blocklen; + } + } + + { + // compute adler32 on input + unsigned int s1 = 1, s2 = 0; + int blocklen = (int)(data_len % 5552); + j = 0; + while (j < data_len) { + for (i = 0; i < blocklen; ++i) { + s1 += data[j + i]; + s2 += s1; } - } - - { - // compute adler32 on input - unsigned int s1=1, s2=0; - int blocklen = (int) (data_len % 5552); - j=0; - while (j < data_len) { - for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } - s1 %= 65521; s2 %= 65521; - j += blocklen; - blocklen = 5552; - } - stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s2)); - stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s1)); - } - *out_len = stbiw__sbn(out); - // make returned pointer freeable - STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); - return (unsigned char *) stbiw__sbraw(out); + s1 %= 65521; + s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *)stbiw__sbraw(out); #endif // STBIW_ZLIB_COMPRESS } -static unsigned int stbiw__crc32(unsigned char *buffer, int len) -{ +static unsigned int stbiw__crc32(unsigned char *buffer, int len) { #ifdef STBIW_CRC32 - return STBIW_CRC32(buffer, len); + return STBIW_CRC32(buffer, len); #else - static unsigned int crc_table[256] = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; + static unsigned int crc_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D}; - unsigned int crc = ~0u; - int i; - for (i=0; i < len; ++i) - crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; - return ~crc; + unsigned int crc = ~0u; + int i; + for (i = 0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; #endif } -#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) -#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); -#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) +#define stbiw__wpng4(o, a, b, c, d) \ + ((o)[0] = STBIW_UCHAR(a), (o)[1] = STBIW_UCHAR(b), (o)[2] = STBIW_UCHAR(c), \ + (o)[3] = STBIW_UCHAR(d), (o) += 4) +#define stbiw__wp32(data, v) \ + stbiw__wpng4(data, (v) >> 24, (v) >> 16, (v) >> 8, (v)); +#define stbiw__wptag(data, s) stbiw__wpng4(data, s[0], s[1], s[2], s[3]) -static void stbiw__wpcrc(unsigned char **data, int len) -{ - unsigned int crc = stbiw__crc32(*data - len - 4, len+4); - stbiw__wp32(*data, crc); +static void stbiw__wpcrc(unsigned char **data, int len) { + unsigned int crc = stbiw__crc32(*data - len - 4, len + 4); + stbiw__wp32(*data, crc); } -static unsigned char stbiw__paeth(int a, int b, int c) -{ - int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); - if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); - if (pb <= pc) return STBIW_UCHAR(b); - return STBIW_UCHAR(c); +static unsigned char stbiw__paeth(int a, int b, int c) { + int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c); + if (pa <= pb && pa <= pc) + return STBIW_UCHAR(a); + if (pb <= pc) + return STBIW_UCHAR(b); + return STBIW_UCHAR(c); } // @OPTIMIZE: provide an option that always forces left-predict or paeth predict -static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) -{ - static int mapping[] = { 0,1,2,3,4 }; - static int firstmap[] = { 0,1,0,5,6 }; - int *mymap = (y != 0) ? mapping : firstmap; - int i; - int type = mymap[filter_type]; - unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); - int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, + int width, int height, int y, int n, + int filter_type, signed char *line_buffer) { + static int mapping[] = {0, 1, 2, 3, 4}; + static int firstmap[] = {0, 1, 0, 5, 6}; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = + pixels + + stride_bytes * (stbi__flip_vertically_on_write ? height - 1 - y : y); + int signed_stride = + stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; - if (type==0) { - memcpy(line_buffer, z, width*n); - return; - } + if (type == 0) { + memcpy(line_buffer, z, width * n); + return; + } - // first loop isn't optimized since it's just one pixel - for (i = 0; i < n; ++i) { - switch (type) { - case 1: line_buffer[i] = z[i]; break; - case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; - case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; - case 5: line_buffer[i] = z[i]; break; - case 6: line_buffer[i] = z[i]; break; - } - } - switch (type) { - case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; - case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; - case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; - case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: + line_buffer[i] = z[i]; + break; + case 2: + line_buffer[i] = z[i] - z[i - signed_stride]; + break; + case 3: + line_buffer[i] = z[i] - (z[i - signed_stride] >> 1); + break; + case 4: + line_buffer[i] = + (signed char)(z[i] - stbiw__paeth(0, z[i - signed_stride], 0)); + break; + case 5: + line_buffer[i] = z[i]; + break; + case 6: + line_buffer[i] = z[i]; + break; + } + } + switch (type) { + case 1: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - z[i - n]; + break; + case 2: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - z[i - signed_stride]; + break; + case 3: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - ((z[i - n] + z[i - signed_stride]) >> 1); + break; + case 4: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - stbiw__paeth(z[i - n], z[i - signed_stride], + z[i - signed_stride - n]); + break; + case 5: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - (z[i - n] >> 1); + break; + case 6: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - stbiw__paeth(z[i - n], 0, 0); + break; + } } -STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) -{ - int force_filter = stbi_write_force_png_filter; - int ctype[5] = { -1, 0, 4, 2, 6 }; - unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; - unsigned char *out,*o, *filt, *zlib; - signed char *line_buffer; - int j,zlen; +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, + int stride_bytes, int x, int y, + int n, int *out_len) { + int force_filter = stbi_write_force_png_filter; + int ctype[5] = {-1, 0, 4, 2, 6}; + unsigned char sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + unsigned char *out, *o, *filt, *zlib; + signed char *line_buffer; + int j, zlen; - if (stride_bytes == 0) - stride_bytes = x * n; + if (stride_bytes == 0) + stride_bytes = x * n; - if (force_filter >= 5) { - force_filter = -1; - } + if (force_filter >= 5) { + force_filter = -1; + } - filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; - line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } - for (j=0; j < y; ++j) { - int filter_type; - if (force_filter > -1) { - filter_type = force_filter; - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); - } else { // Estimate the best filter by running through all of them: - int best_filter = 0, best_filter_val = 0x7fffffff, est, i; - for (filter_type = 0; filter_type < 5; filter_type++) { - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + filt = (unsigned char *)STBIW_MALLOC((x * n + 1) * y); + if (!filt) + return 0; + line_buffer = (signed char *)STBIW_MALLOC(x * n); + if (!line_buffer) { + STBIW_FREE(filt); + return 0; + } + for (j = 0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, + n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, + n, filter_type, line_buffer); - // Estimate the entropy of the line using this filter; the less, the better. - est = 0; - for (i = 0; i < x*n; ++i) { - est += abs((signed char) line_buffer[i]); - } - if (est < best_filter_val) { - best_filter_val = est; - best_filter = filter_type; - } - } - if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); - filter_type = best_filter; - } + // Estimate the entropy of the line using this filter; the less, the + // better. + est = 0; + for (i = 0; i < x * n; ++i) { + est += abs((signed char)line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } } - // when we get here, filter_type contains the filter type, and line_buffer contains the data - filt[j*(x*n+1)] = (unsigned char) filter_type; - STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); - } - STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); - STBIW_FREE(filt); - if (!zlib) return 0; + if (filter_type != best_filter) { // If the last iteration already got us + // the best filter, don't redo it + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, + n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer + // contains the data + filt[j * (x * n + 1)] = (unsigned char)filter_type; + STBIW_MEMMOVE(filt + j * (x * n + 1) + 1, line_buffer, x * n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y * (x * n + 1), &zlen, + stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) + return 0; - // each tag requires 12 bytes of overhead - out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); - if (!out) return 0; - *out_len = 8 + 12+13 + 12+zlen + 12; + // each tag requires 12 bytes of overhead + out = (unsigned char *)STBIW_MALLOC(8 + 12 + 13 + 12 + zlen + 12); + if (!out) + return 0; + *out_len = 8 + 12 + 13 + 12 + zlen + 12; - o=out; - STBIW_MEMMOVE(o,sig,8); o+= 8; - stbiw__wp32(o, 13); // header length - stbiw__wptag(o, "IHDR"); - stbiw__wp32(o, x); - stbiw__wp32(o, y); - *o++ = 8; - *o++ = STBIW_UCHAR(ctype[n]); - *o++ = 0; - *o++ = 0; - *o++ = 0; - stbiw__wpcrc(&o,13); + o = out; + STBIW_MEMMOVE(o, sig, 8); + o += 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o, 13); - stbiw__wp32(o, zlen); - stbiw__wptag(o, "IDAT"); - STBIW_MEMMOVE(o, zlib, zlen); - o += zlen; - STBIW_FREE(zlib); - stbiw__wpcrc(&o, zlen); + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); - stbiw__wp32(o,0); - stbiw__wptag(o, "IEND"); - stbiw__wpcrc(&o,0); + stbiw__wp32(o, 0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o, 0); - STBIW_ASSERT(o == out + *out_len); + STBIW_ASSERT(o == out + *out_len); - return out; + return out; } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) -{ - FILE *f; - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, + const void *data, int stride_bytes) { + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *)data, + stride_bytes, x, y, comp, &len); + if (png == NULL) + return 0; - f = stbiw__fopen(filename, "wb"); - if (!f) { STBIW_FREE(png); return 0; } - fwrite(png, 1, len, f); - fclose(f); - STBIW_FREE(png); - return 1; + f = stbiw__fopen(filename, "wb"); + if (!f) { + STBIW_FREE(png); + return 0; + } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; } #endif -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) -{ - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - func(context, png, len); - STBIW_FREE(png); - return 1; +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, + int y, int comp, const void *data, + int stride_bytes) { + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *)data, + stride_bytes, x, y, comp, &len); + if (png == NULL) + return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; } - /* *************************************************************************** * * JPEG writer * * This is based on Jon Olick's jo_jpeg.cpp: - * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + * public domain Simple, Minimalistic JPEG writer - + * http://www.jonolick.com/code.html */ -static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, - 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; +static const unsigned char stbiw__jpg_ZigZag[] = { + 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63}; -static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { - int bitBuf = *bitBufP, bitCnt = *bitCntP; - bitCnt += bs[1]; - bitBuf |= bs[0] << (24 - bitCnt); - while(bitCnt >= 8) { - unsigned char c = (bitBuf >> 16) & 255; - stbiw__putc(s, c); - if(c == 255) { - stbiw__putc(s, 0); - } - bitBuf <<= 8; - bitCnt -= 8; - } - *bitBufP = bitBuf; - *bitCntP = bitCnt; +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, + int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while (bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if (c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; } -static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { - float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; - float z1, z2, z3, z4, z5, z11, z13; +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, + float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, + d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; - float tmp0 = d0 + d7; - float tmp7 = d0 - d7; - float tmp1 = d1 + d6; - float tmp6 = d1 - d6; - float tmp2 = d2 + d5; - float tmp5 = d2 - d5; - float tmp3 = d3 + d4; - float tmp4 = d3 - d4; + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; - // Even part - float tmp10 = tmp0 + tmp3; // phase 2 - float tmp13 = tmp0 - tmp3; - float tmp11 = tmp1 + tmp2; - float tmp12 = tmp1 - tmp2; + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; - d0 = tmp10 + tmp11; // phase 3 - d4 = tmp10 - tmp11; + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; - z1 = (tmp12 + tmp13) * 0.707106781f; // c4 - d2 = tmp13 + z1; // phase 5 - d6 = tmp13 - z1; + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; - // Odd part - tmp10 = tmp4 + tmp5; // phase 2 - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; - // The rotator is modified from fig 4-8 to avoid extra negations. - z5 = (tmp10 - tmp12) * 0.382683433f; // c6 - z2 = tmp10 * 0.541196100f + z5; // c2-c6 - z4 = tmp12 * 1.306562965f + z5; // c2+c6 - z3 = tmp11 * 0.707106781f; // c4 + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 - z11 = tmp7 + z3; // phase 5 - z13 = tmp7 - z3; + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; - *d5p = z13 + z2; // phase 6 - *d3p = z13 - z2; - *d1p = z11 + z4; - *d7p = z11 - z4; + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; - *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; + *d0p = d0; + *d2p = d2; + *d4p = d4; + *d6p = d6; } static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { - int tmp1 = val < 0 ? -val : val; - val = val < 0 ? val-1 : val; - bits[1] = 1; - while(tmp1 >>= 1) { - ++bits[1]; - } - bits[0] = val & ((1<>= 1) { + ++bits[1]; + } + bits[0] = val & ((1 << bits[1]) - 1); } -static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) { - const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] }; - const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] }; - int dataOff, i, j, n, diff, end0pos, x, y; - int DU[64]; +static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, + int *bitCnt, float *CDU, int du_stride, + float *fdtbl, int DC, + const unsigned short HTDC[256][2], + const unsigned short HTAC[256][2]) { + const unsigned short EOB[2] = {HTAC[0x00][0], HTAC[0x00][1]}; + const unsigned short M16zeroes[2] = {HTAC[0xF0][0], HTAC[0xF0][1]}; + int dataOff, i, j, n, diff, end0pos, x, y; + int DU[64]; - // DCT rows - for(dataOff=0, n=du_stride*8; dataOff0)&&(DU[end0pos]==0); --end0pos) { - } - // end0pos = first element in reverse order !=0 - if(end0pos == 0) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - return DU[0]; - } - for(i = 1; i <= end0pos; ++i) { - int startpos = i; - int nrzeroes; - unsigned short bits[2]; - for (; DU[i]==0 && i<=end0pos; ++i) { - } - nrzeroes = i-startpos; - if ( nrzeroes >= 16 ) { - int lng = nrzeroes>>4; - int nrmarker; - for (nrmarker=1; nrmarker <= lng; ++nrmarker) - stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); - nrzeroes &= 15; - } - stbiw__jpg_calcBits(DU[i], bits); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); - } - if(end0pos != 63) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - } - return DU[0]; + // Encode DC + diff = DU[0] - DC; + if (diff == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]); + } else { + unsigned short bits[2]; + stbiw__jpg_calcBits(diff, bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + // Encode ACs + end0pos = 63; + for (; (end0pos > 0) && (DU[end0pos] == 0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if (end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for (i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i] == 0 && i <= end0pos; ++i) { + } + nrzeroes = i - startpos; + if (nrzeroes >= 16) { + int lng = nrzeroes >> 4; + int nrmarker; + for (nrmarker = 1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes << 4) + bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if (end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; } -static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { - // Constants that don't pollute global namespace - static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; - static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; - static const unsigned char std_ac_luminance_values[] = { - 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, - 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, - 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, - 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, - 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, - 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, - 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; - static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; - static const unsigned char std_ac_chrominance_values[] = { - 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, - 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, - 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, - 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, - 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, - 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, - 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - // Huffman tables - static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; - static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; - static const unsigned short YAC_HT[256][2] = { - {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const unsigned short UVAC_HT[256][2] = { - {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, - 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; - static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, - 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; - static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, - 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, + int comp, const void *data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = { + 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}; + static const unsigned char std_dc_luminance_values[] = {0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11}; + static const unsigned char std_ac_luminance_nrcodes[] = { + 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, + 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, + 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, + 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, + 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; + static const unsigned char std_dc_chrominance_nrcodes[] = { + 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; + static const unsigned char std_dc_chrominance_values[] = {0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11}; + static const unsigned char std_ac_chrominance_nrcodes[] = { + 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, + 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, + 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, + 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { + {0, 2}, {2, 3}, {3, 3}, {4, 3}, {5, 3}, {6, 3}, + {14, 4}, {30, 5}, {62, 6}, {126, 7}, {254, 8}, {510, 9}}; + static const unsigned short UVDC_HT[256][2] = { + {0, 2}, {1, 2}, {2, 2}, {6, 3}, {14, 4}, {30, 5}, + {62, 6}, {126, 7}, {254, 8}, {510, 9}, {1022, 10}, {2046, 11}}; + static const unsigned short YAC_HT[256][2] = { + {10, 4}, {0, 2}, {1, 2}, {4, 3}, {11, 4}, + {26, 5}, {120, 7}, {248, 8}, {1014, 10}, {65410, 16}, + {65411, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {12, 4}, {27, 5}, {121, 7}, + {502, 9}, {2038, 11}, {65412, 16}, {65413, 16}, {65414, 16}, + {65415, 16}, {65416, 16}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {28, 5}, {249, 8}, + {1015, 10}, {4084, 12}, {65417, 16}, {65418, 16}, {65419, 16}, + {65420, 16}, {65421, 16}, {65422, 16}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {58, 6}, + {503, 9}, {4085, 12}, {65423, 16}, {65424, 16}, {65425, 16}, + {65426, 16}, {65427, 16}, {65428, 16}, {65429, 16}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {59, 6}, {1016, 10}, {65430, 16}, {65431, 16}, {65432, 16}, + {65433, 16}, {65434, 16}, {65435, 16}, {65436, 16}, {65437, 16}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {122, 7}, {2039, 11}, {65438, 16}, {65439, 16}, + {65440, 16}, {65441, 16}, {65442, 16}, {65443, 16}, {65444, 16}, + {65445, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {123, 7}, {4086, 12}, {65446, 16}, + {65447, 16}, {65448, 16}, {65449, 16}, {65450, 16}, {65451, 16}, + {65452, 16}, {65453, 16}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {250, 8}, {4087, 12}, + {65454, 16}, {65455, 16}, {65456, 16}, {65457, 16}, {65458, 16}, + {65459, 16}, {65460, 16}, {65461, 16}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {504, 9}, + {32704, 15}, {65462, 16}, {65463, 16}, {65464, 16}, {65465, 16}, + {65466, 16}, {65467, 16}, {65468, 16}, {65469, 16}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {505, 9}, {65470, 16}, {65471, 16}, {65472, 16}, {65473, 16}, + {65474, 16}, {65475, 16}, {65476, 16}, {65477, 16}, {65478, 16}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {506, 9}, {65479, 16}, {65480, 16}, {65481, 16}, + {65482, 16}, {65483, 16}, {65484, 16}, {65485, 16}, {65486, 16}, + {65487, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {1017, 10}, {65488, 16}, {65489, 16}, + {65490, 16}, {65491, 16}, {65492, 16}, {65493, 16}, {65494, 16}, + {65495, 16}, {65496, 16}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {1018, 10}, {65497, 16}, + {65498, 16}, {65499, 16}, {65500, 16}, {65501, 16}, {65502, 16}, + {65503, 16}, {65504, 16}, {65505, 16}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2040, 11}, + {65506, 16}, {65507, 16}, {65508, 16}, {65509, 16}, {65510, 16}, + {65511, 16}, {65512, 16}, {65513, 16}, {65514, 16}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {65515, 16}, {65516, 16}, {65517, 16}, {65518, 16}, {65519, 16}, + {65520, 16}, {65521, 16}, {65522, 16}, {65523, 16}, {65524, 16}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {2041, 11}, {65525, 16}, {65526, 16}, {65527, 16}, {65528, 16}, + {65529, 16}, {65530, 16}, {65531, 16}, {65532, 16}, {65533, 16}, + {65534, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}}; + static const unsigned short UVAC_HT[256][2] = { + {0, 2}, {1, 2}, {4, 3}, {10, 4}, {24, 5}, + {25, 5}, {56, 6}, {120, 7}, {500, 9}, {1014, 10}, + {4084, 12}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {11, 4}, {57, 6}, {246, 8}, + {501, 9}, {2038, 11}, {4085, 12}, {65416, 16}, {65417, 16}, + {65418, 16}, {65419, 16}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {26, 5}, {247, 8}, + {1015, 10}, {4086, 12}, {32706, 15}, {65420, 16}, {65421, 16}, + {65422, 16}, {65423, 16}, {65424, 16}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {27, 5}, + {248, 8}, {1016, 10}, {4087, 12}, {65425, 16}, {65426, 16}, + {65427, 16}, {65428, 16}, {65429, 16}, {65430, 16}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {58, 6}, {502, 9}, {65431, 16}, {65432, 16}, {65433, 16}, + {65434, 16}, {65435, 16}, {65436, 16}, {65437, 16}, {65438, 16}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {59, 6}, {1017, 10}, {65439, 16}, {65440, 16}, + {65441, 16}, {65442, 16}, {65443, 16}, {65444, 16}, {65445, 16}, + {65446, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {121, 7}, {2039, 11}, {65447, 16}, + {65448, 16}, {65449, 16}, {65450, 16}, {65451, 16}, {65452, 16}, + {65453, 16}, {65454, 16}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {122, 7}, {2040, 11}, + {65455, 16}, {65456, 16}, {65457, 16}, {65458, 16}, {65459, 16}, + {65460, 16}, {65461, 16}, {65462, 16}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {249, 8}, + {65463, 16}, {65464, 16}, {65465, 16}, {65466, 16}, {65467, 16}, + {65468, 16}, {65469, 16}, {65470, 16}, {65471, 16}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {503, 9}, {65472, 16}, {65473, 16}, {65474, 16}, {65475, 16}, + {65476, 16}, {65477, 16}, {65478, 16}, {65479, 16}, {65480, 16}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {504, 9}, {65481, 16}, {65482, 16}, {65483, 16}, + {65484, 16}, {65485, 16}, {65486, 16}, {65487, 16}, {65488, 16}, + {65489, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {505, 9}, {65490, 16}, {65491, 16}, + {65492, 16}, {65493, 16}, {65494, 16}, {65495, 16}, {65496, 16}, + {65497, 16}, {65498, 16}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {506, 9}, {65499, 16}, + {65500, 16}, {65501, 16}, {65502, 16}, {65503, 16}, {65504, 16}, + {65505, 16}, {65506, 16}, {65507, 16}, {0, 0}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {2041, 11}, + {65508, 16}, {65509, 16}, {65510, 16}, {65511, 16}, {65512, 16}, + {65513, 16}, {65514, 16}, {65515, 16}, {65516, 16}, {0, 0}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {16352, 14}, {65517, 16}, {65518, 16}, {65519, 16}, {65520, 16}, + {65521, 16}, {65522, 16}, {65523, 16}, {65524, 16}, {65525, 16}, + {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {1018, 10}, {32707, 15}, {65526, 16}, {65527, 16}, {65528, 16}, + {65529, 16}, {65530, 16}, {65531, 16}, {65532, 16}, {65533, 16}, + {65534, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}}; + static const int YQT[] = { + 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99}; + static const int UVQT[] = {17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, + 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}; + static const float aasf[] = { + 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, + 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, + 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f}; - int row, col, i, k, subsample; - float fdtbl_Y[64], fdtbl_UV[64]; - unsigned char YTable[64], UVTable[64]; + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; - if(!data || !width || !height || comp > 4 || comp < 1) { - return 0; - } + if (!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } - quality = quality ? quality : 90; - subsample = quality <= 90 ? 1 : 0; - quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; - quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; - for(i = 0; i < 64; ++i) { - int uvti, yti = (YQT[i]*quality+50)/100; - YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); - uvti = (UVQT[i]*quality+50)/100; - UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); - } + for (i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i] * quality + 50) / 100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(yti < 1 ? 1 + : yti > 255 ? 255 + : yti); + uvti = (UVQT[i] * quality + 50) / 100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(uvti < 1 ? 1 + : uvti > 255 ? 255 + : uvti); + } - for(row = 0, k = 0; row < 8; ++row) { - for(col = 0; col < 8; ++col, ++k) { - fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - } - } + for (row = 0, k = 0; row < 8; ++row) { + for (col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } - // Write Headers - { - static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; - static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; - const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), - 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; - s->func(s->context, (void*)head0, sizeof(head0)); - s->func(s->context, (void*)YTable, sizeof(YTable)); - stbiw__putc(s, 1); - s->func(s->context, UVTable, sizeof(UVTable)); - s->func(s->context, (void*)head1, sizeof(head1)); - s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); - s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); - stbiw__putc(s, 0x10); // HTYACinfo - s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); - s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); - stbiw__putc(s, 1); // HTUDCinfo - s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); - stbiw__putc(s, 0x11); // HTUACinfo - s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); - s->func(s->context, (void*)head2, sizeof(head2)); - } + // Write Headers + { + static const unsigned char head0[] = { + 0xFF, 0xD8, 0xFF, 0xE0, 0, 0x10, 'J', 'F', 'I', 'F', 0, 1, 1, + 0, 0, 1, 0, 1, 0, 0, 0xFF, 0xDB, 0, 0x84, 0}; + static const unsigned char head2[] = {0xFF, 0xDA, 0, 0xC, 3, 1, 0, + 2, 0x11, 3, 0x11, 0, 0x3F, 0}; + const unsigned char head1[] = {0xFF, + 0xC0, + 0, + 0x11, + 8, + (unsigned char)(height >> 8), + STBIW_UCHAR(height), + (unsigned char)(width >> 8), + STBIW_UCHAR(width), + 3, + 1, + (unsigned char)(subsample ? 0x22 : 0x11), + 0, + 2, + 0x11, + 1, + 3, + 0x11, + 1, + 0xFF, + 0xC4, + 0x01, + 0xA2, + 0}; + s->func(s->context, (void *)head0, sizeof(head0)); + s->func(s->context, (void *)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void *)head1, sizeof(head1)); + s->func(s->context, (void *)(std_dc_luminance_nrcodes + 1), + sizeof(std_dc_luminance_nrcodes) - 1); + s->func(s->context, (void *)std_dc_luminance_values, + sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void *)(std_ac_luminance_nrcodes + 1), + sizeof(std_ac_luminance_nrcodes) - 1); + s->func(s->context, (void *)std_ac_luminance_values, + sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void *)(std_dc_chrominance_nrcodes + 1), + sizeof(std_dc_chrominance_nrcodes) - 1); + s->func(s->context, (void *)std_dc_chrominance_values, + sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void *)(std_ac_chrominance_nrcodes + 1), + sizeof(std_ac_chrominance_nrcodes) - 1); + s->func(s->context, (void *)std_ac_chrominance_values, + sizeof(std_ac_chrominance_values)); + s->func(s->context, (void *)head2, sizeof(head2)); + } - // Encode 8x8 macroblocks - { - static const unsigned short fillBits[] = {0x7F, 7}; - int DCY=0, DCU=0, DCV=0; - int bitBuf=0, bitCnt=0; - // comp == 2 is grey+alpha (alpha is ignored) - int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; - const unsigned char *dataR = (const unsigned char *)data; - const unsigned char *dataG = dataR + ofsG; - const unsigned char *dataB = dataR + ofsB; - int x, y, pos; - if(subsample) { - for(y = 0; y < height; y += 16) { - for(x = 0; x < width; x += 16) { - float Y[256], U[256], V[256]; - for(row = y, pos = 0; row < y+16; ++row) { - // row >= height => use last input row - int clamped_row = (row < height) ? row : height - 1; - int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; - for(col = x; col < x+16; ++col, ++pos) { - // if col >= width => use pixel from last input column - int p = base_p + ((col < width) ? col : (width-1))*comp; - float r = dataR[p], g = dataG[p], b = dataB[p]; - Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; - U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; - V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; - } - } - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - - // subsample U,V - { - float subU[64], subV[64]; - int yy, xx; - for(yy = 0, pos = 0; yy < 8; ++yy) { - for(xx = 0; xx < 8; ++xx, ++pos) { - int j = yy*32+xx*2; - subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; - subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; - } - } - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); - } + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY = 0, DCU = 0, DCV = 0; + int bitBuf = 0, bitCnt = 0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if (subsample) { + for (y = 0; y < height; y += 16) { + for (x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for (row = y, pos = 0; row < y + 16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = + (stbi__flip_vertically_on_write ? (height - 1 - clamped_row) + : clamped_row) * + width * comp; + for (col = x; col < x + 16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width - 1)) * comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128; + U[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b; + V[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b; } - } - } else { - for(y = 0; y < height; y += 8) { - for(x = 0; x < width; x += 8) { - float Y[64], U[64], V[64]; - for(row = y, pos = 0; row < y+8; ++row) { - // row >= height => use last input row - int clamped_row = (row < height) ? row : height - 1; - int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; - for(col = x; col < x+8; ++col, ++pos) { - // if col >= width => use pixel from last input column - int p = base_p + ((col < width) ? col : (width-1))*comp; - float r = dataR[p], g = dataG[p], b = dataB[p]; - Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; - U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; - V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; - } - } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 0, 16, fdtbl_Y, + DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 8, 16, fdtbl_Y, + DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 128, 16, fdtbl_Y, + DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 136, 16, fdtbl_Y, + DCY, YDC_HT, YAC_HT); - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for (yy = 0, pos = 0; yy < 8; ++yy) { + for (xx = 0; xx < 8; ++xx, ++pos) { + int j = yy * 32 + xx * 2; + subU[pos] = + (U[j + 0] + U[j + 1] + U[j + 16] + U[j + 17]) * 0.25f; + subV[pos] = + (V[j + 0] + V[j + 1] + V[j + 16] + V[j + 17]) * 0.25f; + } } - } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, + DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, + DCV, UVDC_HT, UVAC_HT); + } + } } + } else { + for (y = 0; y < height; y += 8) { + for (x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for (row = y, pos = 0; row < y + 8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = + (stbi__flip_vertically_on_write ? (height - 1 - clamped_row) + : clamped_row) * + width * comp; + for (col = x; col < x + 8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width - 1)) * comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128; + U[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b; + V[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b; + } + } - // Do the bit alignment of the EOI marker - stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); - } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, + YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, + UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, + UVDC_HT, UVAC_HT); + } + } + } - // EOI - stbiw__putc(s, 0xFF); - stbiw__putc(s, 0xD9); + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } - return 1; + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; } -STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s = { 0 }; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, + int y, int comp, const void *data, + int quality) { + stbi__write_context s = {0}; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *)data, quality); } - #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s = { 0 }; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, + const void *data, int quality) { + stbi__write_context s = {0}; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif @@ -1629,9 +1971,8 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const /* Revision history 1.16 (2021-07-11) - make Deflate code emit uncompressed blocks when it would otherwise expand - support writing BMPs with alpha channel - 1.15 (2020-07-13) unknown + make Deflate code emit uncompressed blocks when it would otherwise + expand support writing BMPs with alpha channel 1.15 (2020-07-13) unknown 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1.13 1.12 @@ -1642,24 +1983,13 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const 1.09 (2018-02-11) fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) - add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter - 1.07 (2017-07-24) - doc fix - 1.06 (2017-07-23) - writing JPEG (using Jon Olick's code) - 1.05 ??? - 1.04 (2017-03-03) - monochrome BMP expansion - 1.03 ??? - 1.02 (2016-04-02) - avoid allocating large structures on the stack - 1.01 (2016-01-16) - STBIW_REALLOC_SIZED: support allocators with no realloc support - avoid race-condition in crc initialization - minor compile issues - 1.00 (2015-09-14) - installable file IO function - 0.99 (2015-09-13) + add stbi__flip_vertically_on_write, external zlib, zlib quality, + choose PNG filter 1.07 (2017-07-24) doc fix 1.06 (2017-07-23) writing JPEG + (using Jon Olick's code) 1.05 ??? 1.04 (2017-03-03) monochrome BMP + expansion 1.03 ??? 1.02 (2016-04-02) avoid allocating large structures on + the stack 1.01 (2016-01-16) STBIW_REALLOC_SIZED: support allocators with no + realloc support avoid race-condition in crc initialization minor compile + issues 1.00 (2015-09-14) installable file IO function 0.99 (2015-09-13) warning fixes; TGA rle support 0.98 (2015-04-08) added STBIW_MALLOC, STBIW_ASSERT etc diff --git a/include/renderd7/external/stb_truetype.h b/include/renderd7/external/stb_truetype.h index bbf2284..ac29351 100644 --- a/include/renderd7/external/stb_truetype.h +++ b/include/renderd7/external/stb_truetype.h @@ -15,7 +15,8 @@ // extract glyph metrics // extract glyph shapes // render glyphs to one-channel bitmaps with antialiasing (box filter) -// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// render glyphs to one-channel SDF bitmaps (signed-distance +// field/function) // // Todo: // non-MS cmaps @@ -61,27 +62,27 @@ // 1.26 (2021-08-28) fix broken rasterizer // 1.25 (2021-07-11) many fixes // 1.24 (2020-02-05) fix warning -// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) -// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined -// 1.21 (2019-02-25) fix warning -// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() -// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod -// 1.18 (2018-01-29) add missing function -// 1.17 (2017-07-23) make more arguments const; doc fix -// 1.16 (2017-07-12) SDF support -// 1.15 (2017-03-03) make more arguments const -// 1.14 (2017-01-16) num-fonts-in-TTC function -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual -// 1.11 (2016-04-02) fix unused-variable warning -// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; -// variant PackFontRanges to pack and render in separate phases; -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); -// fixed an assert() bug in the new rasterizer -// replace assert() with STBTT_assert() in new rasterizer +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but +// only kern not GPOS) 1.22 (2019-08-11) minimize missing-glyph duplication; +// fix kerning if both 'GPOS' and 'kern' are defined 1.21 (2019-02-25) fix +// warning 1.20 (2019-02-07) PackFontRange skips missing codepoints; +// GetScaleFontVMetrics() 1.19 (2018-02-11) GPOS kerning, STBTT_fmod 1.18 +// (2018-01-29) add missing function 1.17 (2017-07-23) make more arguments +// const; doc fix 1.16 (2017-07-12) SDF support 1.15 (2017-03-03) make more +// arguments const 1.14 (2017-01-16) num-fonts-in-TTC function 1.13 +// (2017-01-02) support OpenType fonts, certain Apple fonts 1.12 (2016-10-25) +// suppress warnings about casting away const with -Wcast-qual 1.11 +// (2016-04-02) fix unused-variable warning 1.10 (2016-04-02) user-defined +// fabs(); rare memory leak; remove duplicate typedef 1.09 (2016-01-16) +// warning fix; avoid crash on outofmem; use allocation userdata properly 1.08 +// (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal +// edges 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse +// codepoints; +// variant PackFontRanges to pack and render in separate +// phases; fix stbtt_GetFontOFfsetForIndex (never worked for +// non-0 input?); fixed an assert() bug in the new +// rasterizer replace assert() with STBTT_assert() in new +// rasterizer // // Full history can be found at the end of this file. // @@ -97,30 +98,33 @@ // before the #include of this file. This expands out the actual // implementation into that C/C++ file. // -// To make the implementation private to the file that generates the implementation, +// To make the implementation private to the file that generates the +// implementation, // #define STBTT_STATIC // // Simple 3D API (don't ship this, but it's fine for tools and quick start) -// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture -// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for +// use as texture stbtt_GetBakedQuad() -- compute quad +// to draw for a given char // // Improved 3D API (more shippable): -// #include "stb_rect_pack.h" -- optional, but you really want it -// stbtt_PackBegin() -// stbtt_PackSetOversampling() -- for improved quality on small fonts -// stbtt_PackFontRanges() -- pack and renders -// stbtt_PackEnd() -// stbtt_GetPackedQuad() +// #include "stb_rect_pack.h" -- optional, but you really +// want it stbtt_PackBegin() stbtt_PackSetOversampling() -- +// for improved quality on small fonts stbtt_PackFontRanges() -- pack +// and renders stbtt_PackEnd() stbtt_GetPackedQuad() // -// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// "Load" a font file from a memory buffer (you have to keep the buffer +// loaded) // stbtt_InitFont() -// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections -// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font +// collections stbtt_GetNumberOfFonts() -- number of fonts +// for TTC font collections // // Render a unicode codepoint to a bitmap -// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap -// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide -// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// stbtt_GetCodepointBitmap() -- allocates and returns a +// bitmap stbtt_MakeCodepointBitmap() -- renders into bitmap +// you provide stbtt_GetCodepointBitmapBox() -- how big the +// bitmap must be // // Character advance/positioning // stbtt_GetCodepointHMetrics() @@ -174,8 +178,8 @@ // // Font Size in Pixels or Points // The preferred interface for specifying font sizes in stb_truetype -// is to specify how tall the font's vertical extent should be in pixels. -// If that sounds good enough, skip the next paragraph. +// is to specify how tall the font's vertical extent should be in +// pixels. If that sounds good enough, skip the next paragraph. // // Most font APIs instead use "points", which are a common typographic // measurement for describing font size, defined as 72 points per inch. @@ -200,11 +204,11 @@ // // Baseline: // You need to select a y-coordinate that is the baseline of where -// your text will appear. Call GetFontBoundingBox to get the baseline-relative -// bounding box for all characters. SF*-y0 will be the distance in pixels -// that the worst-case character could extend above the baseline, so if -// you want the top edge of characters to appear at the top of the -// screen where y=0, then you would set the baseline to SF*-y0. +// your text will appear. Call GetFontBoundingBox to get the +// baseline-relative bounding box for all characters. SF*-y0 will be the +// distance in pixels that the worst-case character could extend above the +// baseline, so if you want the top edge of characters to appear at the top +// of the screen where y=0, then you would set the baseline to SF*-y0. // // Current point: // Set the current point where the first character will appear. The @@ -218,7 +222,8 @@ // Compute the bounding box of the character. It will contain signed values // relative to . I.e. if it returns x0,y0,x1,y1, // then the character should be displayed in the rectangle from -// to to +// -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate + // implementation #include "stb_truetype.h" char ttf_buffer[1<<25]; @@ -412,7 +419,6 @@ int main(int arg, char **argv) } #endif - ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //// @@ -423,70 +429,70 @@ int main(int arg, char **argv) //// link with the C runtime library. #ifdef STB_TRUETYPE_IMPLEMENTATION - // #define your own (u)stbtt_int8/16/32 before including to override this - #ifndef stbtt_uint8 - typedef unsigned char stbtt_uint8; - typedef signed char stbtt_int8; - typedef unsigned short stbtt_uint16; - typedef signed short stbtt_int16; - typedef unsigned int stbtt_uint32; - typedef signed int stbtt_int32; - #endif +// #define your own (u)stbtt_int8/16/32 before including to override this +#ifndef stbtt_uint8 +typedef unsigned char stbtt_uint8; +typedef signed char stbtt_int8; +typedef unsigned short stbtt_uint16; +typedef signed short stbtt_int16; +typedef unsigned int stbtt_uint32; +typedef signed int stbtt_int32; +#endif - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; +typedef char stbtt__check_size32[sizeof(stbtt_int32) == 4 ? 1 : -1]; +typedef char stbtt__check_size16[sizeof(stbtt_int16) == 2 ? 1 : -1]; - // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h - #ifndef STBTT_ifloor - #include - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif +// e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h +#ifndef STBTT_ifloor +#include +#define STBTT_ifloor(x) ((int)floor(x)) +#define STBTT_iceil(x) ((int)ceil(x)) +#endif - #ifndef STBTT_sqrt - #include - #define STBTT_sqrt(x) sqrt(x) - #define STBTT_pow(x,y) pow(x,y) - #endif +#ifndef STBTT_sqrt +#include +#define STBTT_sqrt(x) sqrt(x) +#define STBTT_pow(x, y) pow(x, y) +#endif - #ifndef STBTT_fmod - #include - #define STBTT_fmod(x,y) fmod(x,y) - #endif +#ifndef STBTT_fmod +#include +#define STBTT_fmod(x, y) fmod(x, y) +#endif - #ifndef STBTT_cos - #include - #define STBTT_cos(x) cos(x) - #define STBTT_acos(x) acos(x) - #endif +#ifndef STBTT_cos +#include +#define STBTT_cos(x) cos(x) +#define STBTT_acos(x) acos(x) +#endif - #ifndef STBTT_fabs - #include - #define STBTT_fabs(x) fabs(x) - #endif +#ifndef STBTT_fabs +#include +#define STBTT_fabs(x) fabs(x) +#endif - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h - #ifndef STBTT_malloc - #include - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) - #define STBTT_free(x,u) ((void)(u),free(x)) - #endif +// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h +#ifndef STBTT_malloc +#include +#define STBTT_malloc(x, u) ((void)(u), malloc(x)) +#define STBTT_free(x, u) ((void)(u), free(x)) +#endif - #ifndef STBTT_assert - #include - #define STBTT_assert(x) assert(x) - #endif +#ifndef STBTT_assert +#include +#define STBTT_assert(x) assert(x) +#endif - #ifndef STBTT_strlen - #include - #define STBTT_strlen(x) strlen(x) - #endif +#ifndef STBTT_strlen +#include +#define STBTT_strlen(x) strlen(x) +#endif - #ifndef STBTT_memcpy - #include - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif +#ifndef STBTT_memcpy +#include +#define STBTT_memcpy memcpy +#define STBTT_memset memset +#endif #endif /////////////////////////////////////////////////////////////////////////////// @@ -510,11 +516,10 @@ extern "C" { #endif // private structure -typedef struct -{ - unsigned char *data; - int cursor; - int size; +typedef struct { + unsigned char *data; + int cursor; + int size; } stbtt__buf; ////////////////////////////////////////////////////////////////////////////// @@ -524,33 +529,35 @@ typedef struct // If you use this API, you only have to call two functions ever. // -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; +typedef struct { + unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap + float xoff, yoff, xadvance; } stbtt_bakedchar; -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +STBTT_DEF int stbtt_BakeFontBitmap( + const unsigned char *data, + int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long // if return is positive, the first unused row of the bitmap -// if return is negative, returns the negative of the number of characters that fit -// if return is 0, no characters fit and no rows were used -// This uses a very crappy packing. +// if return is negative, returns the negative of the number of characters that +// fit if return is 0, no characters fit and no rows were used This uses a very +// crappy packing. -typedef struct -{ - float x0,y0,s0,t0; // top-left - float x1,y1,s1,t1; // bottom-right +typedef struct { + float x0, y0, s0, t0; // top-left + float x1, y1, s1, t1; // bottom-right } stbtt_aligned_quad; -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +STBTT_DEF void stbtt_GetBakedQuad( + const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, + float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier // Call GetBakedQuad with char_index = 'character - first_char', and it // creates the quad you need to draw and advances the current position. // @@ -561,10 +568,11 @@ STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int p // // It's inefficient; you might want to c&p it and optimize it. -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, + int index, float size, float *ascent, + float *descent, float *lineGap); // Query the font vertical metrics without having to create a font first. - ////////////////////////////////////////////////////////////////////////////// // // NEW TEXTURE BAKING API @@ -572,11 +580,10 @@ STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int in // This provides options for packing multiple fonts into one atlas, not // perfectly but better than nothing. -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; - float xoff2,yoff2; +typedef struct { + unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap + float xoff, yoff, xadvance; + float xoff2, yoff2; } stbtt_packedchar; typedef struct stbtt_pack_context stbtt_pack_context; @@ -585,7 +592,9 @@ typedef struct stbtt_fontinfo stbtt_fontinfo; typedef struct stbrp_rect stbrp_rect; #endif -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, + int width, int height, int stride_in_bytes, + int padding, void *alloc_context); // Initializes a packing context stored in the passed-in stbtt_pack_context. // Future calls using this context will pack characters into the bitmap passed // in here: a 1-channel bitmap that is width * height. stride_in_bytes is @@ -596,43 +605,57 @@ STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, i // // Returns 0 on failure, 1 on success. -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc); // Cleans up the packing context and frees all memory. -#define STBTT_POINT_SIZE(x) (-(x)) +#define STBTT_POINT_SIZE(x) (-(x)) -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, + const unsigned char *fontdata, int font_index, + float font_size, + int first_unicode_char_in_range, + int num_chars_in_range, + stbtt_packedchar *chardata_for_range); // Creates character bitmaps from the font_index'th font found in fontdata (use // font_index=0 if you don't know what that is). It creates num_chars_in_range -// bitmaps for characters with unicode values starting at first_unicode_char_in_range -// and increasing. Data for how to render them is stored in chardata_for_range; -// pass these to stbtt_GetPackedQuad to get back renderable quads. +// bitmaps for characters with unicode values starting at +// first_unicode_char_in_range and increasing. Data for how to render them is +// stored in chardata_for_range; pass these to stbtt_GetPackedQuad to get back +// renderable quads. // // font_size is the full height of the character from ascender to descender, // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() // and pass that result as 'font_size': -// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., 20 , ... // font max minus min y is 20 pixels +// tall // ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall -typedef struct -{ - float font_size; - int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint - int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints - int num_chars; - stbtt_packedchar *chardata_for_range; // output - unsigned char h_oversample, v_oversample; // don't set these, they're used internally +typedef struct { + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are + // continuous, and this is the first + // codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of + // unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, + v_oversample; // don't set these, they're used internally } stbtt_pack_range; -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, + const unsigned char *fontdata, + int font_index, stbtt_pack_range *ranges, + int num_ranges); // Creates character bitmaps from multiple ranges of characters stored in // ranges. This will usually create a better-packed bitmap than multiple // calls to stbtt_PackFontRange. Note that you can call this multiple // times within a single PackBegin/PackEnd. -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, + unsigned int h_oversample, + unsigned int v_oversample); // Oversampling a font increases the quality by allowing higher-quality subpixel // positioning, and is especially valuable at smaller text sizes. // @@ -648,21 +671,33 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h // To use with PackFontRangesGather etc., you must set it before calls // call to PackFontRangesGatherRects. -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, + int skip); // If skip != 0, this tells stb_truetype to skip any codepoints for which // there is no corresponding glyph. If skip=0, which is the default, then // codepoints without a glyph recived the font's "missing character" glyph, // typically an empty box by convention. -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int align_to_integer); +STBTT_DEF void stbtt_GetPackedQuad( + const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, + float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, + const stbtt_fontinfo *info, + stbtt_pack_range *ranges, + int num_ranges, + stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, + stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, + const stbtt_fontinfo *info, + stbtt_pack_range *ranges, + int num_ranges, + stbrp_rect *rects); // Calling these functions in sequence is roughly equivalent to calling // stbtt_PackFontRanges(). If you more control over the packing of multiple // fonts, or if you want to pack custom data into a font texture, take a look @@ -676,16 +711,16 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, cons // this is an opaque structure that you shouldn't mess with which holds // all the context needed from PackBegin to PackEnd. struct stbtt_pack_context { - void *user_allocator_context; - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - int skip_missing; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; }; ////////////////////////////////////////////////////////////////////////////// @@ -710,109 +745,129 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); // The following structure is defined publicly so you can declare one on // the stack or as a global or etc, but you should treat it as opaque. -struct stbtt_fontinfo -{ - void * userdata; - unsigned char * data; // pointer to .ttf file - int fontstart; // offset of start of font +struct stbtt_fontinfo { + void *userdata; + unsigned char *data; // pointer to .ttf file + int fontstart; // offset of start of font - int numGlyphs; // number of glyphs, needed for range checking + int numGlyphs; // number of glyphs, needed for range checking - int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf - int index_map; // a cmap mapping for our chosen character encoding - int indexToLocFormat; // format needed to map from glyph index to glyph + int loca, head, glyf, hhea, hmtx, kern, gpos, + svg; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph - stbtt__buf cff; // cff font data - stbtt__buf charstrings; // the charstring index - stbtt__buf gsubrs; // global charstring subroutines index - stbtt__buf subrs; // private charstring subroutines index - stbtt__buf fontdicts; // array of font dicts - stbtt__buf fdselect; // map from glyph to fontdict + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict }; -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, + int offset); // Given an offset into the file that defines a font, this function builds // the necessary cached info for the rest of the system. You must allocate // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't // need to do anything special to free it, because the contents are pure // value data with no additional data structures. Returns 0 on failure. - ////////////////////////////////////////////////////////////////////////////// // // CHARACTER TO GLYPH-INDEX CONVERSIOn -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, + int unicode_codepoint); // If you're going to perform multiple operations on the same character // and you want a speed-up, call this function with the character you're // going to process, then use glyph-based functions instead of the // codepoint-based functions. // Returns 0 if the character codepoint is not defined in the font. - ////////////////////////////////////////////////////////////////////////////// // // CHARACTER PROPERTIES // -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, + float pixels); // computes a scale factor to produce a font whose "height" is 'pixels' tall. // Height is measured as the distance from the highest ascender to the lowest // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics // and computing: // scale = pixels / (ascent - descent) -// so if you prefer to measure height by the ascent only, use a similar calculation. +// so if you prefer to measure height by the ascent only, use a similar +// calculation. -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, + float pixels); // computes a scale factor to produce a font whose EM size is mapped to // 'pixels' tall. This is probably what traditional APIs compute, but // I'm not positive. -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, + int *descent, int *lineGap); // ascent is the coordinate above the baseline the font extends; descent -// is the coordinate below the baseline the font extends (i.e. it is typically negative) -// lineGap is the spacing between one row's descent and the next row's ascent... -// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// is the coordinate below the baseline the font extends (i.e. it is typically +// negative) lineGap is the spacing between one row's descent and the next row's +// ascent... so you should advance the vertical position by "*ascent - *descent +// + *lineGap" // these are expressed in unscaled coordinates, so you must multiply by // the scale factor for a given size -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); -// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 -// table (specific to MS/Windows TTF files). +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, + int *typoAscent, int *typoDescent, + int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the +// OS/2 table (specific to MS/Windows TTF files). // // Returns 1 on success (table present), 0 on failure. -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, + int *y0, int *x1, int *y1); // the bounding box around all possible characters -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); -// leftSideBearing is the offset from the current horizontal position to the left edge of the character -// advanceWidth is the offset from the current horizontal position to the next horizontal position +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, + int codepoint, int *advanceWidth, + int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the +// left edge of the character advanceWidth is the offset from the current +// horizontal position to the next horizontal position // these are expressed in unscaled coordinates -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, + int ch2); // an additional amount to add to the 'advance' value between ch1 and ch2 -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); -// Gets the bounding box of the visible part of the glyph, in unscaled coordinates +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, + int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled +// coordinates -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, + int glyph_index, int *advanceWidth, + int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, + int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, + int *x0, int *y0, int *x1, int *y1); // as above, but takes one or more glyph indices for greater efficiency -typedef struct stbtt_kerningentry -{ - int glyph1; // use stbtt_FindGlyphIndex - int glyph2; - int advance; +typedef struct stbtt_kerningentry { + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; } stbtt_kerningentry; -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, + stbtt_kerningentry *table, + int table_length); // Retrieves a complete list of all of the kerning pairs provided by the font -// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. -// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) +// stbtt_GetKerningTable never writes more than table_length entries and returns +// how many entries it did write. The table will be sorted by (a.glyph1 == +// b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) ////////////////////////////////////////////////////////////////////////////// // @@ -820,30 +875,29 @@ STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningen // the bitmaps for C declaration-order reasons) // -#ifndef STBTT_vmove // you can predefine these to use different values (but why?) - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve, - STBTT_vcubic - }; +#ifndef STBTT_vmove // you can predefine these to use different values (but + // why?) +enum { STBTT_vmove = 1, STBTT_vline, STBTT_vcurve, STBTT_vcubic }; #endif #ifndef stbtt_vertex // you can predefine this to use different values - // (we share this with other code at RAD) - #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file - typedef struct - { - stbtt_vertex_type x,y,cx,cy,cx1,cy1; - unsigned char type,padding; - } stbtt_vertex; + // (we share this with other code at RAD) +#define stbtt_vertex_type \ + short // can't use stbtt_int16 because that's not visible in the header file +typedef struct { + stbtt_vertex_type x, y, cx, cy, cx1, cy1; + unsigned char type, padding; +} stbtt_vertex; #endif STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); // returns non-zero if nothing is drawn for this glyph -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, + int unicode_codepoint, + stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, + stbtt_vertex **vertices); // returns # of vertices and fills *vertices with the pointer to them // these are expressed in "unscaled" coordinates // @@ -854,12 +908,15 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s // draws a quadratic bezier from previous endpoint to // its x,y, using cx,cy as the bezier control point. -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, + stbtt_vertex *vertices); // frees the data allocated above STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, + int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, + const char **svg); // fills svg with the character's SVG data. // returns data size or 0 if SVG not found. @@ -871,72 +928,120 @@ STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char * STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); // frees the bitmap allocated below -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, + float scale_x, float scale_y, + int codepoint, int *width, + int *height, int *xoff, + int *yoff); // allocates a large-enough single-channel 8bpp bitmap and renders the // specified character/glyph at the specified scale into it, with // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). // *width & *height are filled out with the width & height of the bitmap, // which is stored left-to-right, top-to-bottom. // -// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left +// of the bitmap -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * +stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, + float scale_y, float shift_x, float shift_y, + int codepoint, int *width, int *height, + int *xoff, int *yoff); // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel // shift for the character -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, + unsigned char *output, int out_w, + int out_h, int out_stride, + float scale_x, float scale_y, + int codepoint); // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the // width and height and positioning info for it first. -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, + unsigned char *output, + int out_w, int out_h, + int out_stride, float scale_x, + float scale_y, float shift_x, + float shift_y, int codepoint); // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel // shift for the character -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter( + const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, + int oversample_x, int oversample_y, float *sub_x, float *sub_y, + int codepoint); // same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering // is performed (see stbtt_PackSetOversampling) -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, + int codepoint, float scale_x, + float scale_y, int *ix0, int *iy0, + int *ix1, int *iy1); // get the bbox of the bitmap centered around the glyph origin; so the // bitmap width is ix1-ix0, height is iy1-iy0, and location to place // the bitmap top left is (leftSideBearing*scale,iy0). // (Note that the bitmap uses y-increases-down, but the shape uses // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel( + const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, + float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel // shift for the character // the following functions are equivalent to the above functions, but operate // on glyph indices instead of Unicode codepoints (for efficiency) -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); - +STBTT_DEF unsigned char * +stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, + int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel( + const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, + float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, + unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, + float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, + unsigned char *output, int out_w, + int out_h, int out_stride, + float scale_x, float scale_y, + float shift_x, float shift_y, + int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter( + const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, + int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, + float scale_x, float scale_y, int *ix0, + int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, + int glyph, float scale_x, + float scale_y, float shift_x, + float shift_y, int *ix0, + int *iy0, int *ix1, int *iy1); // @TODO: don't expose this structure -typedef struct -{ - int w,h,stride; - unsigned char *pixels; +typedef struct { + int w, h, stride; + unsigned char *pixels; } stbtt__bitmap; // rasterize a shape with quadratic beziers into a bitmap -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into - float flatness_in_pixels, // allowable error of curve in pixels - stbtt_vertex *vertices, // array of vertices defining shape - int num_verts, // number of vertices in above array - float scale_x, float scale_y, // scale applied to input vertices - float shift_x, float shift_y, // translation applied to input vertices - int x_off, int y_off, // another translation applied to input - int invert, // if non-zero, vertically flip shape - void *userdata); // context for to STBTT_MALLOC +STBTT_DEF void +stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, + float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC ////////////////////////////////////////////////////////////////////////////// // @@ -945,26 +1050,42 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); // frees the SDF bitmap allocated below -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -// These functions compute a discretized SDF field for a single character, suitable for storing -// in a single-channel texture, sampling with bilinear filtering, and testing against -// larger than some threshold to produce scalable fonts. +STBTT_DEF unsigned char *stbtt_GetGlyphSDF(const stbtt_fontinfo *info, + float scale, int glyph, int padding, + unsigned char onedge_value, + float pixel_dist_scale, int *width, + int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * +stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, + int padding, unsigned char onedge_value, + float pixel_dist_scale, int *width, int *height, + int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, +// suitable for storing in a single-channel texture, sampling with bilinear +// filtering, and testing against larger than some threshold to produce scalable +// fonts. // info -- the font -// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap -// glyph/codepoint -- the character to generate the SDF for -// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// scale -- controls the size of the resulting SDF bitmap, +// same as it would be creating a regular bitmap glyph/codepoint -- the +// character to generate the SDF for padding -- extra "pixels" +// around the character which are filled with the distance to the +// character (not 0), // which allows effects like bit outlines -// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) -// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) -// if positive, > onedge_value is inside; if negative, < onedge_value is inside -// width,height -- output height & width of the SDF bitmap (including padding) -// xoff,yoff -- output origin of the character -// return value -- a 2D array of bytes 0..255, width*height in size +// onedge_value -- value 0-255 to test the SDF against to +// reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when +// moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if +// negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap +// (including padding) xoff,yoff -- output origin of the +// character return value -- a 2D array of bytes 0..255, +// width*height in size // // pixel_dist_scale & onedge_value are a scale & bias that allows you to make // optimal use of the limited 0..255 for your application, trading off precision -// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// and special effects. SDF values outside the range 0..255 are clamped to +// 0..255. // // Example: // scale = stbtt_ScaleForPixelHeight(22) @@ -973,17 +1094,17 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // pixel_dist_scale = 180/5.0 = 36.0 // // This will create an SDF bitmap in which the character is about 22 pixels -// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled -// shape, sample the SDF at each pixel and fill the pixel if the SDF value -// is greater than or equal to 180/255. (You'll actually want to antialias, -// which is beyond the scope of this example.) Additionally, you can compute -// offset outlines (e.g. to stroke the character border inside & outside, -// or only outside). For example, to fill outside the character up to 3 SDF -// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above -// choice of variables maps a range from 5 pixels outside the shape to -// 2 pixels inside the shape to 0..255; this is intended primarily for apply -// outside effects only (the interior range is needed to allow proper -// antialiasing of the font at *smaller* sizes) +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a +// filled shape, sample the SDF at each pixel and fill the pixel if the SDF +// value is greater than or equal to 180/255. (You'll actually want to +// antialias, which is beyond the scope of this example.) Additionally, you +// can compute offset outlines (e.g. to stroke the character border inside +// & outside, or only outside). For example, to fill outside the character +// up to 3 SDF pixels, you would compare against (180-36.0*3)/255 = 72/255. +// The above choice of variables maps a range from 5 pixels outside the +// shape to 2 pixels inside the shape to 0..255; this is intended primarily +// for apply outside effects only (the interior range is needed to allow +// proper antialiasing of the font at *smaller* sizes) // // The function computes the SDF analytically at each SDF pixel, not by e.g. // building a higher-res bitmap and approximating it. In theory the quality @@ -994,8 +1115,6 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // The algorithm has not been optimized at all, so expect it to be slow // if computing lots of characters or very large sizes. - - ////////////////////////////////////////////////////////////////////////////// // // Finding the right font... @@ -1017,23 +1136,29 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // from the file yourself and do your own comparisons on them. // You have to have called stbtt_InitFont() first. - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, + const char *name, int flags); // returns the offset (not index) of the font that matches, or -1 if none // if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". // if you use any other flag, use a font name like "Arial"; this checks // the 'macStyle' header field; i don't know if fonts set this consistently -#define STBTT_MACSTYLE_DONTCARE 0 -#define STBTT_MACSTYLE_BOLD 1 -#define STBTT_MACSTYLE_ITALIC 2 -#define STBTT_MACSTYLE_UNDERSCORE 4 -#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE \ + 8 // <= not same as 0, this makes us check the bitfield is 0 -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, + const char *s2, int len2); // returns 1/0 whether the first string interpreted as utf8 is identical to -// the second string interpreted as big-endian utf16... useful for strings from next func +// the second string interpreted as big-endian utf16... useful for strings from +// next func -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, + int *length, int platformID, + int encodingID, int languageID, + int nameID); // returns the string (which may be big-endian double byte, e.g. for unicode) // and puts the length in bytes in *length. // @@ -1042,52 +1167,70 @@ STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *l // http://www.microsoft.com/typography/otspec/name.htm enum { // platformID - STBTT_PLATFORM_ID_UNICODE =0, - STBTT_PLATFORM_ID_MAC =1, - STBTT_PLATFORM_ID_ISO =2, - STBTT_PLATFORM_ID_MICROSOFT =3 + STBTT_PLATFORM_ID_UNICODE = 0, + STBTT_PLATFORM_ID_MAC = 1, + STBTT_PLATFORM_ID_ISO = 2, + STBTT_PLATFORM_ID_MICROSOFT = 3 }; enum { // encodingID for STBTT_PLATFORM_ID_UNICODE - STBTT_UNICODE_EID_UNICODE_1_0 =0, - STBTT_UNICODE_EID_UNICODE_1_1 =1, - STBTT_UNICODE_EID_ISO_10646 =2, - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 + STBTT_UNICODE_EID_UNICODE_1_0 = 0, + STBTT_UNICODE_EID_UNICODE_1_1 = 1, + STBTT_UNICODE_EID_ISO_10646 = 2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP = 3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL = 4 }; enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT - STBTT_MS_EID_SYMBOL =0, - STBTT_MS_EID_UNICODE_BMP =1, - STBTT_MS_EID_SHIFTJIS =2, - STBTT_MS_EID_UNICODE_FULL =10 + STBTT_MS_EID_SYMBOL = 0, + STBTT_MS_EID_UNICODE_BMP = 1, + STBTT_MS_EID_SHIFTJIS = 2, + STBTT_MS_EID_UNICODE_FULL = 10 }; enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 + STBTT_MAC_EID_ROMAN = 0, + STBTT_MAC_EID_ARABIC = 4, + STBTT_MAC_EID_JAPANESE = 1, + STBTT_MAC_EID_HEBREW = 5, + STBTT_MAC_EID_CHINESE_TRAD = 2, + STBTT_MAC_EID_GREEK = 6, + STBTT_MAC_EID_KOREAN = 3, + STBTT_MAC_EID_RUSSIAN = 7 }; enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... - // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D + // problematic because there are e.g. 16 english LCIDs and 16 arabic + // LCIDs + STBTT_MS_LANG_ENGLISH = 0x0409, + STBTT_MS_LANG_ITALIAN = 0x0410, + STBTT_MS_LANG_CHINESE = 0x0804, + STBTT_MS_LANG_JAPANESE = 0x0411, + STBTT_MS_LANG_DUTCH = 0x0413, + STBTT_MS_LANG_KOREAN = 0x0412, + STBTT_MS_LANG_FRENCH = 0x040c, + STBTT_MS_LANG_RUSSIAN = 0x0419, + STBTT_MS_LANG_GERMAN = 0x0407, + STBTT_MS_LANG_SPANISH = 0x0409, + STBTT_MS_LANG_HEBREW = 0x040d, + STBTT_MS_LANG_SWEDISH = 0x041D }; enum { // languageID for STBTT_PLATFORM_ID_MAC - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 + STBTT_MAC_LANG_ENGLISH = 0, + STBTT_MAC_LANG_JAPANESE = 11, + STBTT_MAC_LANG_ARABIC = 12, + STBTT_MAC_LANG_KOREAN = 23, + STBTT_MAC_LANG_DUTCH = 4, + STBTT_MAC_LANG_RUSSIAN = 32, + STBTT_MAC_LANG_FRENCH = 1, + STBTT_MAC_LANG_SPANISH = 6, + STBTT_MAC_LANG_GERMAN = 2, + STBTT_MAC_LANG_SWEDISH = 5, + STBTT_MAC_LANG_HEBREW = 10, + STBTT_MAC_LANG_CHINESE_SIMPLIFIED = 33, + STBTT_MAC_LANG_ITALIAN = 3, + STBTT_MAC_LANG_CHINESE_TRAD = 19 }; #ifdef __cplusplus @@ -1106,23 +1249,24 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC #ifdef STB_TRUETYPE_IMPLEMENTATION #ifndef STBTT_MAX_OVERSAMPLE -#define STBTT_MAX_OVERSAMPLE 8 +#define STBTT_MAX_OVERSAMPLE 8 #endif #if STBTT_MAX_OVERSAMPLE > 255 #error "STBTT_MAX_OVERSAMPLE cannot be > 255" #endif -typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; +typedef int stbtt__test_oversample_pow2 + [(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE - 1)) == 0 ? 1 : -1]; #ifndef STBTT_RASTERIZER_VERSION #define STBTT_RASTERIZER_VERSION 2 #endif #ifdef _MSC_VER -#define STBTT__NOTUSED(v) (void)(v) +#define STBTT__NOTUSED(v) (void)(v) #else -#define STBTT__NOTUSED(v) (void)sizeof(v) +#define STBTT__NOTUSED(v) (void)sizeof(v) #endif ////////////////////////////////////////////////////////////////////////// @@ -1130,145 +1274,141 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS // stbtt__buf helpers to parse data from file // -static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor++]; +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) { + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; } -static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor]; +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) { + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; } -static void stbtt__buf_seek(stbtt__buf *b, int o) -{ - STBTT_assert(!(o > b->size || o < 0)); - b->cursor = (o > b->size || o < 0) ? b->size : o; +static void stbtt__buf_seek(stbtt__buf *b, int o) { + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; } -static void stbtt__buf_skip(stbtt__buf *b, int o) -{ - stbtt__buf_seek(b, b->cursor + o); +static void stbtt__buf_skip(stbtt__buf *b, int o) { + stbtt__buf_seek(b, b->cursor + o); } -static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) -{ - stbtt_uint32 v = 0; - int i; - STBTT_assert(n >= 1 && n <= 4); - for (i = 0; i < n; i++) - v = (v << 8) | stbtt__buf_get8(b); - return v; +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) { + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; } -static stbtt__buf stbtt__new_buf(const void *p, size_t size) -{ - stbtt__buf r; - STBTT_assert(size < 0x40000000); - r.data = (stbtt_uint8*) p; - r.size = (int) size; - r.cursor = 0; - return r; +static stbtt__buf stbtt__new_buf(const void *p, size_t size) { + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8 *)p; + r.size = (int)size; + r.cursor = 0; + return r; } -#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) -#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) -static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) -{ - stbtt__buf r = stbtt__new_buf(NULL, 0); - if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; - r.data = b->data + o; - r.size = s; - return r; +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) { + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) + return r; + r.data = b->data + o; + r.size = s; + return r; } -static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) -{ - int count, start, offsize; - start = b->cursor; - count = stbtt__buf_get16(b); - if (count) { - offsize = stbtt__buf_get8(b); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(b, offsize * count); - stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); - } - return stbtt__buf_range(b, start, b->cursor - start); +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) { + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); } -static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) -{ - int b0 = stbtt__buf_get8(b); - if (b0 >= 32 && b0 <= 246) return b0 - 139; - else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; - else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; - else if (b0 == 28) return stbtt__buf_get16(b); - else if (b0 == 29) return stbtt__buf_get32(b); - STBTT_assert(0); - return 0; +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) { + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) + return b0 - 139; + else if (b0 >= 247 && b0 <= 250) + return (b0 - 247) * 256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) + return -(b0 - 251) * 256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) + return stbtt__buf_get16(b); + else if (b0 == 29) + return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; } static void stbtt__cff_skip_operand(stbtt__buf *b) { - int v, b0 = stbtt__buf_peek8(b); - STBTT_assert(b0 >= 28); - if (b0 == 30) { - stbtt__buf_skip(b, 1); - while (b->cursor < b->size) { - v = stbtt__buf_get8(b); - if ((v & 0xF) == 0xF || (v >> 4) == 0xF) - break; - } - } else { - stbtt__cff_int(b); - } + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } } -static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) -{ - stbtt__buf_seek(b, 0); - while (b->cursor < b->size) { - int start = b->cursor, end, op; - while (stbtt__buf_peek8(b) >= 28) - stbtt__cff_skip_operand(b); - end = b->cursor; - op = stbtt__buf_get8(b); - if (op == 12) op = stbtt__buf_get8(b) | 0x100; - if (op == key) return stbtt__buf_range(b, start, end-start); - } - return stbtt__buf_range(b, 0, 0); +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) { + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) + op = stbtt__buf_get8(b) | 0x100; + if (op == key) + return stbtt__buf_range(b, start, end - start); + } + return stbtt__buf_range(b, 0, 0); } -static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) -{ - int i; - stbtt__buf operands = stbtt__dict_get(b, key); - for (i = 0; i < outcount && operands.cursor < operands.size; i++) - out[i] = stbtt__cff_int(&operands); +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, + stbtt_uint32 *out) { + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); } -static int stbtt__cff_index_count(stbtt__buf *b) -{ - stbtt__buf_seek(b, 0); - return stbtt__buf_get16(b); +static int stbtt__cff_index_count(stbtt__buf *b) { + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); } -static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) -{ - int count, offsize, start, end; - stbtt__buf_seek(&b, 0); - count = stbtt__buf_get16(&b); - offsize = stbtt__buf_get8(&b); - STBTT_assert(i >= 0 && i < count); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(&b, i*offsize); - start = stbtt__buf_get(&b, offsize); - end = stbtt__buf_get(&b, offsize); - return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) { + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i * offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2 + (count + 1) * offsize + start, end - start); } ////////////////////////////////////////////////////////////////////////// @@ -1277,1440 +1417,1589 @@ static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) // // on platforms that don't allow misaligned reads, if we want to allow -// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE +// truetype fonts that aren't padded to alignment, define +// ALLOW_UNALIGNED_TRUETYPE -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) -#define ttCHAR(p) (* (stbtt_int8 *) (p)) -#define ttFixed(p) ttLONG(p) +#define ttBYTE(p) (*(stbtt_uint8 *)(p)) +#define ttCHAR(p) (*(stbtt_int8 *)(p)) +#define ttFixed(p) ttLONG(p) -static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } -static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0] * 256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0] * 256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { + return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; +} +static stbtt_int32 ttLONG(stbtt_uint8 *p) { + return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; +} -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) +#define stbtt_tag4(p, c0, c1, c2, c3) \ + ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p, str) stbtt_tag4(p, str[0], str[1], str[2], str[3]) -static int stbtt__isfont(stbtt_uint8 *font) -{ - // check the version number - if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 - if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! - if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF - if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 - if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts - return 0; +static int stbtt__isfont(stbtt_uint8 *font) { + // check the version number + if (stbtt_tag4(font, '1', 0, 0, 0)) + return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) + return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) + return 1; // OpenType with CFF + if (stbtt_tag4(font, 0, 1, 0, 0)) + return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) + return 1; // Apple specification for TrueType fonts + return 0; } // @OPTIMIZE: binary search -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) -{ - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); - stbtt_uint32 tabledir = fontstart + 12; - stbtt_int32 i; - for (i=0; i < num_tables; ++i) { - stbtt_uint32 loc = tabledir + 16*i; - if (stbtt_tag(data+loc+0, tag)) - return ttULONG(data+loc+8); - } - return 0; +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, + const char *tag) { + stbtt_int32 num_tables = ttUSHORT(data + fontstart + 4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i = 0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16 * i; + if (stbtt_tag(data + loc + 0, tag)) + return ttULONG(data + loc + 8); + } + return 0; } -static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) -{ - // if it's just a font, there's only one valid index - if (stbtt__isfont(font_collection)) - return index == 0 ? 0 : -1; +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, + int index) { + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - stbtt_int32 n = ttLONG(font_collection+8); - if (index >= n) - return -1; - return ttULONG(font_collection+12+index*4); - } - } - return -1; + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection + 4) == 0x00010000 || + ttULONG(font_collection + 4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection + 8); + if (index >= n) + return -1; + return ttULONG(font_collection + 12 + index * 4); + } + } + return -1; } -static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) -{ - // if it's just a font, there's only one valid font - if (stbtt__isfont(font_collection)) - return 1; +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) { + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - return ttLONG(font_collection+8); - } - } - return 0; + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection + 4) == 0x00010000 || + ttULONG(font_collection + 4) == 0x00020000) { + return ttLONG(font_collection + 8); + } + } + return 0; } -static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) -{ - stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; - stbtt__buf pdict; - stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); - if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); - pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); - stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); - if (!subrsoff) return stbtt__new_buf(NULL, 0); - stbtt__buf_seek(&cff, private_loc[1]+subrsoff); - return stbtt__cff_get_index(&cff); +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) { + stbtt_uint32 subrsoff = 0, private_loc[2] = {0, 0}; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) + return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) + return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1] + subrsoff); + return stbtt__cff_get_index(&cff); } // since most people won't use this, find this table the first time it's needed -static int stbtt__get_svg(stbtt_fontinfo *info) -{ - stbtt_uint32 t; - if (info->svg < 0) { - t = stbtt__find_table(info->data, info->fontstart, "SVG "); - if (t) { - stbtt_uint32 offset = ttULONG(info->data + t + 2); - info->svg = t + offset; +static int stbtt__get_svg(stbtt_fontinfo *info) { + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, + int fontstart) { + stbtt_uint32 cmap, t; + stbtt_int32 i, numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) + return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) + return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data + cff, 512 * 1024 * 1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) + return 0; + if (charstrings == 0) + return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) + return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size - fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data + t + 4); + else + info->numGlyphs = 0xffff; + + info->svg = -1; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i = 0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch (ttUSHORT(data + encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data + encoding_record + 2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data + encoding_record + 4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data + encoding_record + 4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data + info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, + int unicode_codepoint) { + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes - 6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32)unicode_codepoint >= first && + (stbtt_uint32)unicode_codepoint < first + count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first) * 2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search + // collection of ranges + stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data + index_map + 8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data + index_map + 10); + stbtt_uint16 rangeShift = ttUSHORT(data + index_map + 12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift * 2)) + search += rangeShift * 2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange * 2); + if (unicode_codepoint > end) + search += searchRange * 2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start, last; + stbtt_uint16 item = (stbtt_uint16)((search - endCount) >> 1); + + start = ttUSHORT(data + index_map + 14 + segcount * 2 + 2 + 2 * item); + last = ttUSHORT(data + endCount + 2 * item); + if (unicode_codepoint < start || unicode_codepoint > last) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount * 6 + 2 + 2 * item); + if (offset == 0) + return (stbtt_uint16)(unicode_codepoint + + ttSHORT(data + index_map + 14 + segcount * 4 + 2 + + 2 * item)); + + return ttUSHORT(data + offset + (unicode_codepoint - start) * 2 + + index_map + 14 + segcount * 6 + 2 + 2 * item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data + index_map + 12); + stbtt_int32 low, high; + low = 0; + high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = + low + ((high - low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data + index_map + 16 + mid * 12); + stbtt_uint32 end_char = ttULONG(data + index_map + 16 + mid * 12 + 4); + if ((stbtt_uint32)unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32)unicode_codepoint > end_char) + low = mid + 1; + else { + stbtt_uint32 start_glyph = + ttULONG(data + index_map + 16 + mid * 12 + 8); + if (format == 12) + return start_glyph + unicode_codepoint - start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, + int unicode_codepoint, + stbtt_vertex **vertices) { + return stbtt_GetGlyphShape( + info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, + stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) { + v->type = type; + v->x = (stbtt_int16)x; + v->y = (stbtt_int16)y; + v->cx = (stbtt_int16)cx; + v->cy = (stbtt_int16)cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) { + int g1, g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) + return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) + return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4 + 4); + } + + return g1 == g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, + int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, + int *x0, int *y0, int *x1, int *y1) { + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) + return 0; + + if (x0) + *x0 = ttSHORT(info->data + g + 2); + if (y0) + *y0 = ttSHORT(info->data + g + 4); + if (x1) + *x1 = ttSHORT(info->data + g + 6); + if (y1) + *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, + int *x0, int *y0, int *x1, int *y1) { + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info, codepoint), x0, y0, + x1, y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) { + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == + 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) + return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, + int was_off, int start_off, stbtt_int32 sx, + stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, + stbtt_int32 cx, stbtt_int32 cy) { + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + scx) >> 1, + (cy + scy) >> 1, cx, cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, scx, scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, sx, sy, 0, 0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, + stbtt_vertex **pvertices) { + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices = 0; + int num_vertices = 0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) + return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags = 0, flagcount; + stbtt_int32 ins, i, j = 0, m, n, next_move, was_off = 0, off, start_off = 0; + stbtt_int32 x, y, cx, cy, sx, sy, scx, scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1 + ttUSHORT(endPtsOfContours + numberOfContours * 2 - 2); + + m = n + 2 * numberOfContours; // a loose bound on how many vertices we might + // need + vertices = + (stbtt_vertex *)STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount = 0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m + // ends up being calculated + + // first load flags + + for (i = 0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off + i].type = flags; + } + + // now load x coordinates + x = 0; + for (i = 0; i < n; ++i) { + flags = vertices[off + i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? } else { - info->svg = 0; + if (!(flags & 16)) { + x = x + (stbtt_int16)(points[0] * 256 + points[1]); + points += 2; + } } - } - return info->svg; -} + vertices[off + i].x = (stbtt_int16)x; + } -static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) -{ - stbtt_uint32 cmap, t; - stbtt_int32 i,numTables; + // now load y coordinates + y = 0; + for (i = 0; i < n; ++i) { + flags = vertices[off + i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16)(points[0] * 256 + points[1]); + points += 2; + } + } + vertices[off + i].y = (stbtt_int16)y; + } - info->data = data; - info->fontstart = fontstart; - info->cff = stbtt__new_buf(NULL, 0); + // now convert them to our format + num_vertices = 0; + sx = sy = cx = cy = scx = scy = 0; + for (i = 0; i < n; ++i) { + flags = vertices[off + i].type; + x = (stbtt_int16)vertices[off + i].x; + y = (stbtt_int16)vertices[off + i].y; - cmap = stbtt__find_table(data, fontstart, "cmap"); // required - info->loca = stbtt__find_table(data, fontstart, "loca"); // required - info->head = stbtt__find_table(data, fontstart, "head"); // required - info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required - info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required - info->kern = stbtt__find_table(data, fontstart, "kern"); // not required - info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + if (next_move == i) { + if (i != 0) + num_vertices = + stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, + sy, scx, scy, cx, cy); - if (!cmap || !info->head || !info->hhea || !info->hmtx) - return 0; - if (info->glyf) { - // required for truetype - if (!info->loca) return 0; - } else { - // initialization for CFF / Type2 fonts (OTF) - stbtt__buf b, topdict, topdictidx; - stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; - stbtt_uint32 cff; + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find + // a point on the curve where we can start, and we need to save some + // state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off + i + 1].type & 1)) { + // next point is also a curve point, so interpolate an on-point + // curve + sx = (x + (stbtt_int32)vertices[off + i + 1].x) >> 1; + sy = (y + (stbtt_int32)vertices[off + i + 1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32)vertices[off + i + 1].x; + sy = (stbtt_int32)vertices[off + i + 1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove, sx, sy, 0, 0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours + j * 2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means + // interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, + (cx + x) >> 1, (cy + y) >> 1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x, y, cx, + cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x, y, 0, 0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, + start_off, sx, sy, scx, scy, cx, cy); + } else if (numberOfContours < 0) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1, 0, 0, 1, 0, 0}, m, n; - cff = stbtt__find_table(data, fontstart, "CFF "); - if (!cff) return 0; + flags = ttSHORT(comp); + comp += 2; + gidx = ttSHORT(comp); + comp += 2; - info->fontdicts = stbtt__new_buf(NULL, 0); - info->fdselect = stbtt__new_buf(NULL, 0); - - // @TODO this should use size from table (not 512MB) - info->cff = stbtt__new_buf(data+cff, 512*1024*1024); - b = info->cff; - - // read the header - stbtt__buf_skip(&b, 2); - stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize - - // @TODO the name INDEX could list multiple fonts, - // but we just use the first one. - stbtt__cff_get_index(&b); // name INDEX - topdictidx = stbtt__cff_get_index(&b); - topdict = stbtt__cff_index_get(topdictidx, 0); - stbtt__cff_get_index(&b); // string INDEX - info->gsubrs = stbtt__cff_get_index(&b); - - stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); - stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); - stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); - stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); - info->subrs = stbtt__get_subrs(b, topdict); - - // we only support Type 2 charstrings - if (cstype != 2) return 0; - if (charstrings == 0) return 0; - - if (fdarrayoff) { - // looks like a CID font - if (!fdselectoff) return 0; - stbtt__buf_seek(&b, fdarrayoff); - info->fontdicts = stbtt__cff_get_index(&b); - info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); + comp += 2; + mtx[5] = ttSHORT(comp); + comp += 2; + } else { + mtx[4] = ttCHAR(comp); + comp += 1; + mtx[5] = ttCHAR(comp); + comp += 1; + } + } else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1 << 3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1 << 6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp) / 16384.0f; + comp += 2; + } else if (flags & (1 << 7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[1] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[2] = ttSHORT(comp) / 16384.0f; + comp += 2; + mtx[3] = ttSHORT(comp) / 16384.0f; + comp += 2; } - stbtt__buf_seek(&b, charstrings); - info->charstrings = stbtt__cff_get_index(&b); - } + // Find transformation scales. + m = (float)STBTT_sqrt(mtx[0] * mtx[0] + mtx[1] * mtx[1]); + n = (float)STBTT_sqrt(mtx[2] * mtx[2] + mtx[3] * mtx[3]); - t = stbtt__find_table(data, fontstart, "maxp"); - if (t) - info->numGlyphs = ttUSHORT(data+t+4); - else - info->numGlyphs = 0xffff; - - info->svg = -1; - - // find a cmap encoding table we understand *now* to avoid searching - // later. (todo: could make this installable) - // the same regardless of glyph. - numTables = ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) { - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; - // find an encoding we understand: - switch(ttUSHORT(data+encoding_record)) { - case STBTT_PLATFORM_ID_MICROSOFT: - switch (ttUSHORT(data+encoding_record+2)) { - case STBTT_MS_EID_UNICODE_BMP: - case STBTT_MS_EID_UNICODE_FULL: - // MS/Unicode - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - break; - case STBTT_PLATFORM_ID_UNICODE: - // Mac/iOS has these - // all the encodingIDs are unicode, so we don't bother to check it - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - } - if (info->index_map == 0) - return 0; - - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; -} - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) -{ - stbtt_uint8 *data = info->data; - stbtt_uint32 index_map = info->index_map; - - stbtt_uint16 format = ttUSHORT(data + index_map + 0); - if (format == 0) { // apple byte encoding - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - stbtt_uint32 first = ttUSHORT(data + index_map + 6); - stbtt_uint32 count = ttUSHORT(data + index_map + 8); - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean - return 0; - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - - // do a binary search of the segments - stbtt_uint32 endCount = index_map + 14; - stbtt_uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - // they lie from endCount .. endCount + segCount - // but searchRange is the nearest power of two, so... - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) - search += rangeShift*2; - - // now decrement to bias correctly to find smallest - search -= 2; - while (entrySelector) { - stbtt_uint16 end; - searchRange >>= 1; - end = ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; - - { - stbtt_uint16 offset, start, last; - stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - last = ttUSHORT(data + endCount + 2*item); - if (unicode_codepoint < start || unicode_codepoint > last) - return 0; - - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - stbtt_uint32 ngroups = ttULONG(data+index_map+12); - stbtt_int32 low,high; - low = 0; high = (stbtt_int32)ngroups; - // Binary search the right group. - while (low < high) { - stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); - if ((stbtt_uint32) unicode_codepoint < start_char) - high = mid; - else if ((stbtt_uint32) unicode_codepoint > end_char) - low = mid+1; - else { - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return start_glyph + unicode_codepoint-start_char; - else // format == 13 - return start_glyph; - } - } - return 0; // not found - } - // @TODO - STBTT_assert(0); - return 0; -} - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) -{ - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); -} - -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) -{ - v->type = type; - v->x = (stbtt_int16) x; - v->y = (stbtt_int16) y; - v->cx = (stbtt_int16) cx; - v->cy = (stbtt_int16) cy; -} - -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) -{ - int g1,g2; - - STBTT_assert(!info->cff.size); - - if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range - if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - - return g1==g2 ? -1 : g1; // if length is 0, return -1 -} - -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); - -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - if (info->cff.size) { - stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); - } else { - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); - } - return 1; -} - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) -{ - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); -} - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt_int16 numberOfContours; - int g; - if (info->cff.size) - return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; - g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 1; - numberOfContours = ttSHORT(info->data + g); - return numberOfContours == 0; -} - -static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, - stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) -{ - if (start_off) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - return num_vertices; -} - -static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - stbtt_int16 numberOfContours; - stbtt_uint8 *endPtsOfContours; - stbtt_uint8 *data = info->data; - stbtt_vertex *vertices=0; - int num_vertices=0; - int g = stbtt__GetGlyfOffset(info, glyph_index); - - *pvertices = NULL; - - if (g < 0) return 0; - - numberOfContours = ttSHORT(data + g); - - if (numberOfContours > 0) { - stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; - stbtt_uint8 *points; - endPtsOfContours = (data + g + 10); - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); - - m = n + 2*numberOfContours; // a loose bound on how many vertices we might need - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - // in first pass, we load uninterpreted data into the allocated array - // above, shifted to the end of the array so we won't overwrite it when - // we create our final data starting from the front - - off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated - - // first load flags - - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else - --flagcount; - vertices[off+i].type = flags; - } - - // now load x coordinates - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - stbtt_int16 dx = *points++; - x += (flags & 16) ? dx : -dx; // ??? - } else { - if (!(flags & 16)) { - x = x + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (stbtt_int16) x; - } - - // now load y coordinates - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - stbtt_int16 dy = *points++; - y += (flags & 32) ? dy : -dy; // ??? - } else { - if (!(flags & 32)) { - y = y + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (stbtt_int16) y; - } - - // now convert them to our format - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - x = (stbtt_int16) vertices[off+i].x; - y = (stbtt_int16) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - // now start the new one - start_off = !(flags & 1); - if (start_off) { - // if we start off with an off-curve point, then when we need to find a point on the curve - // where we can start, and we need to save some state for when we wraparound. - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - // next point is also a curve point, so interpolate an on-point curve - sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; - sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; - } else { - // otherwise just use the next point as our start point - sx = (stbtt_int32) vertices[off+i+1].x; - sy = (stbtt_int32) vertices[off+i+1].y; - ++i; // we're using point i+1 as the starting point, so skip it - } - } else { - sx = x; - sy = y; - } - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) { // if it's a curve - if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); - was_off = 0; - } - } - } - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours < 0) { - // Compound shapes. - int more = 1; - stbtt_uint8 *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - while (more) { - stbtt_uint16 flags, gidx; - int comp_num_verts = 0, i; - stbtt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = ttSHORT(comp); comp+=2; - gidx = ttSHORT(comp); comp+=2; - - if (flags & 2) { // XY values - if (flags & 1) { // shorts - mtx[4] = ttSHORT(comp); comp+=2; - mtx[5] = ttSHORT(comp); comp+=2; - } else { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; - } - } - else { - // @TODO handle matching point - STBTT_assert(0); - } - if (flags & (1<<3)) { // WE_HAVE_A_SCALE - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } - - // Find transformation scales. - m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - // Get indexed glyph. - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); - if (comp_num_verts > 0) { - // Transform vertices. - for (i = 0; i < comp_num_verts; ++i) { - stbtt_vertex* v = &comp_verts[i]; - stbtt_vertex_type x,y; - x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - // Append vertices. - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); - if (!tmp) { - if (vertices) STBTT_free(vertices, info->userdata); - if (comp_verts) STBTT_free(comp_verts, info->userdata); - return 0; - } - if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); - STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); - if (vertices) STBTT_free(vertices, info->userdata); - vertices = tmp; + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex *v = &comp_verts[i]; + stbtt_vertex_type x, y; + x = v->x; + y = v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5])); + x = v->cx; + y = v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex *)STBTT_malloc((num_vertices + comp_num_verts) * + sizeof(stbtt_vertex), + info->userdata); + if (!tmp) { + if (vertices) + STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); - num_vertices += comp_num_verts; - } - // More components ? - more = flags & (1<<5); + return 0; + } + if (num_vertices > 0 && vertices) + STBTT_memcpy(tmp, vertices, num_vertices * sizeof(stbtt_vertex)); + STBTT_memcpy(tmp + num_vertices, comp_verts, + comp_num_verts * sizeof(stbtt_vertex)); + if (vertices) + STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; } - } else { - // numberOfCounters == 0, do nothing - } + // More components ? + more = flags & (1 << 5); + } + } else { + // numberOfCounters == 0, do nothing + } - *pvertices = vertices; - return num_vertices; + *pvertices = vertices; + return num_vertices; } -typedef struct -{ - int bounds; - int started; - float first_x, first_y; - float x, y; - stbtt_int32 min_x, max_x, min_y, max_y; +typedef struct { + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; - stbtt_vertex *pvertices; - int num_vertices; + stbtt_vertex *pvertices; + int num_vertices; } stbtt__csctx; -#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} +#define STBTT__CSCTX_INIT(bounds) \ + { bounds, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0 } -static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) -{ - if (x > c->max_x || !c->started) c->max_x = x; - if (y > c->max_y || !c->started) c->max_y = y; - if (x < c->min_x || !c->started) c->min_x = x; - if (y < c->min_y || !c->started) c->min_y = y; - c->started = 1; +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) { + if (x > c->max_x || !c->started) + c->max_x = x; + if (y > c->max_y || !c->started) + c->max_y = y; + if (x < c->min_x || !c->started) + c->min_x = x; + if (y < c->min_y || !c->started) + c->min_y = y; + c->started = 1; } -static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) -{ - if (c->bounds) { - stbtt__track_vertex(c, x, y); - if (type == STBTT_vcubic) { - stbtt__track_vertex(c, cx, cy); - stbtt__track_vertex(c, cx1, cy1); +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, + stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, + stbtt_int32 cx1, stbtt_int32 cy1) { + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16)cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16)cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) { + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, + 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) { + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) { + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, + float dx2, float dy2, float dx3, + float dy3) { + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, + (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) { + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, + int glyph_index) { + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; } - } else { - stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); - c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; - c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; - } - c->num_vertices++; + start = end; + } + } + if (fdselector == -1) + stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, + stbtt__cff_index_get(info->fontdicts, fdselector)); } -static void stbtt__csctx_close_shape(stbtt__csctx *ctx) -{ - if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) -{ - stbtt__csctx_close_shape(ctx); - ctx->first_x = ctx->x = ctx->x + dx; - ctx->first_y = ctx->y = ctx->y + dy; - stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) -{ - ctx->x += dx; - ctx->y += dy; - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) -{ - float cx1 = ctx->x + dx1; - float cy1 = ctx->y + dy1; - float cx2 = cx1 + dx2; - float cy2 = cy1 + dy2; - ctx->x = cx2 + dx3; - ctx->y = cy2 + dy3; - stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); -} - -static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) -{ - int count = stbtt__cff_index_count(&idx); - int bias = 107; - if (count >= 33900) - bias = 32768; - else if (count >= 1240) - bias = 1131; - n += bias; - if (n < 0 || n >= count) - return stbtt__new_buf(NULL, 0); - return stbtt__cff_index_get(idx, n); -} - -static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt__buf fdselect = info->fdselect; - int nranges, start, end, v, fmt, fdselector = -1, i; - - stbtt__buf_seek(&fdselect, 0); - fmt = stbtt__buf_get8(&fdselect); - if (fmt == 0) { - // untested - stbtt__buf_skip(&fdselect, glyph_index); - fdselector = stbtt__buf_get8(&fdselect); - } else if (fmt == 3) { - nranges = stbtt__buf_get16(&fdselect); - start = stbtt__buf_get16(&fdselect); - for (i = 0; i < nranges; i++) { - v = stbtt__buf_get8(&fdselect); - end = stbtt__buf_get16(&fdselect); - if (glyph_index >= start && glyph_index < end) { - fdselector = v; - break; - } - start = end; - } - } - if (fdselector == -1) stbtt__new_buf(NULL, 0); - return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); -} - -static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) -{ - int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; - int has_subrs = 0, clear_stack; - float s[48]; - stbtt__buf subr_stack[10], subrs = info->subrs, b; - float f; +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, + stbtt__csctx *c) { + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; #define STBTT__CSERR(s) (0) - // this currently ignores the initial width value, which isn't needed if we have hmtx - b = stbtt__cff_index_get(info->charstrings, glyph_index); - while (b.cursor < b.size) { - i = 0; - clear_stack = 1; - b0 = stbtt__buf_get8(&b); - switch (b0) { - // @TODO implement hinting - case 0x13: // hintmask - case 0x14: // cntrmask - if (in_header) - maskbits += (sp / 2); // implicit "vstem" - in_header = 0; - stbtt__buf_skip(&b, (maskbits + 7) / 8); - break; + // this currently ignores the initial width value, which isn't needed if we + // have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; - case 0x01: // hstem - case 0x03: // vstem - case 0x12: // hstemhm - case 0x17: // vstemhm - maskbits += (sp / 2); - break; + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; - case 0x15: // rmoveto - in_header = 0; - if (sp < 2) return STBTT__CSERR("rmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); - break; - case 0x04: // vmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("vmoveto stack"); - stbtt__csctx_rmove_to(c, 0, s[sp-1]); - break; - case 0x16: // hmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("hmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-1], 0); - break; + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) + return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp - 2], s[sp - 1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) + return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp - 1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) + return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp - 1], 0); + break; - case 0x05: // rlineto - if (sp < 2) return STBTT__CSERR("rlineto stack"); - for (; i + 1 < sp; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; + case 0x05: // rlineto + if (sp < 2) + return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i + 1]); + break; - // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical - // starting from a different place. + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and + // vertical starting from a different place. - case 0x07: // vlineto - if (sp < 1) return STBTT__CSERR("vlineto stack"); - goto vlineto; - case 0x06: // hlineto - if (sp < 1) return STBTT__CSERR("hlineto stack"); - for (;;) { - if (i >= sp) break; - stbtt__csctx_rline_to(c, s[i], 0); - i++; + case 0x07: // vlineto + if (sp < 1) + return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) + return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) + break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; vlineto: - if (i >= sp) break; - stbtt__csctx_rline_to(c, 0, s[i]); - i++; - } - break; + if (i >= sp) + break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; - case 0x1F: // hvcurveto - if (sp < 4) return STBTT__CSERR("hvcurveto stack"); - goto hvcurveto; - case 0x1E: // vhcurveto - if (sp < 4) return STBTT__CSERR("vhcurveto stack"); - for (;;) { - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); - i += 4; + case 0x1F: // hvcurveto + if (sp < 4) + return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) + return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) + break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i + 1], s[i + 2], s[i + 3], + (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; hvcurveto: - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); - i += 4; - } - break; + if (i + 3 >= sp) + break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i + 1], s[i + 2], + (sp - i == 5) ? s[i + 4] : 0.0f, s[i + 3]); + i += 4; + } + break; - case 0x08: // rrcurveto - if (sp < 6) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; + case 0x08: // rrcurveto + if (sp < 6) + return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], + s[i + 5]); + break; - case 0x18: // rcurveline - if (sp < 8) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp - 2; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; + case 0x18: // rcurveline + if (sp < 8) + return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], + s[i + 5]); + if (i + 1 >= sp) + return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i + 1]); + break; - case 0x19: // rlinecurve - if (sp < 8) return STBTT__CSERR("rlinecurve stack"); - for (; i + 1 < sp - 6; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; + case 0x19: // rlinecurve + if (sp < 8) + return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i + 1]); + if (i + 5 >= sp) + return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], + s[i + 5]); + break; - case 0x1A: // vvcurveto - case 0x1B: // hhcurveto - if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); - f = 0.0; - if (sp & 1) { f = s[i]; i++; } - for (; i + 3 < sp; i += 4) { - if (b0 == 0x1B) - stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); - else - stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); - f = 0.0; - } - break; + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) + return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { + f = s[i]; + i++; + } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i + 1], s[i + 2], s[i + 3], + 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i + 1], s[i + 2], 0.0, + s[i + 3]); + f = 0.0; + } + break; - case 0x0A: // callsubr - if (!has_subrs) { - if (info->fdselect.size) - subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); - has_subrs = 1; - } - // FALLTHROUGH - case 0x1D: // callgsubr - if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); - v = (int) s[--sp]; - if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); - subr_stack[subr_stack_height++] = b; - b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); - if (b.size == 0) return STBTT__CSERR("subr not found"); - b.cursor = 0; - clear_stack = 0; - break; + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // FALLTHROUGH + case 0x1D: // callgsubr + if (sp < 1) + return STBTT__CSERR("call(g|)subr stack"); + v = (int)s[--sp]; + if (subr_stack_height >= 10) + return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) + return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; - case 0x0B: // return - if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); - b = subr_stack[--subr_stack_height]; - clear_stack = 0; - break; + case 0x0B: // return + if (subr_stack_height <= 0) + return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; - case 0x0E: // endchar - stbtt__csctx_close_shape(c); - return 1; + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; - case 0x0C: { // two-byte escape - float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; - float dx, dy; - int b1 = stbtt__buf_get8(&b); - switch (b1) { - // @TODO These "flex" implementations ignore the flex-depth and resolution, - // and always draw beziers. - case 0x22: // hflex - if (sp < 7) return STBTT__CSERR("hflex stack"); - dx1 = s[0]; - dx2 = s[1]; - dy2 = s[2]; - dx3 = s[3]; - dx4 = s[4]; - dx5 = s[5]; - dx6 = s[6]; - stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); - break; + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and + // resolution, and always draw beziers. + case 0x22: // hflex + if (sp < 7) + return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; - case 0x23: // flex - if (sp < 13) return STBTT__CSERR("flex stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = s[10]; - dy6 = s[11]; - //fd is s[12] - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; + case 0x23: // flex + if (sp < 13) + return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + // fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; - case 0x24: // hflex1 - if (sp < 9) return STBTT__CSERR("hflex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dx4 = s[5]; - dx5 = s[6]; - dy5 = s[7]; - dx6 = s[8]; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); - break; + case 0x24: // hflex1 + if (sp < 9) + return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1 + dy2 + dy5)); + break; - case 0x25: // flex1 - if (sp < 11) return STBTT__CSERR("flex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = dy6 = s[10]; - dx = dx1+dx2+dx3+dx4+dx5; - dy = dy1+dy2+dy3+dy4+dy5; - if (STBTT_fabs(dx) > STBTT_fabs(dy)) - dy6 = -dy; - else - dx6 = -dx; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; - - default: - return STBTT__CSERR("unimplemented"); - } - } break; + case 0x25: // flex1 + if (sp < 11) + return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1 + dx2 + dx3 + dx4 + dx5; + dy = dy1 + dy2 + dy3 + dy4 + dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; default: - if (b0 != 255 && b0 != 28 && b0 < 32) - return STBTT__CSERR("reserved operator"); - - // push immediate - if (b0 == 255) { - f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; - } else { - stbtt__buf_skip(&b, -1); - f = (float)(stbtt_int16)stbtt__cff_int(&b); - } - if (sp >= 48) return STBTT__CSERR("push stack overflow"); - s[sp++] = f; - clear_stack = 0; - break; + return STBTT__CSERR("unimplemented"); } - if (clear_stack) sp = 0; - } - return STBTT__CSERR("no endchar"); + } break; + + default: + if (b0 != 255 && b0 != 28 && b0 < 32) + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) + return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) + sp = 0; + } + return STBTT__CSERR("no endchar"); #undef STBTT__CSERR } -static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - // runs the charstring twice, once to count and once to output (to avoid realloc) - stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); - stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); - if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { - *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); - output_ctx.pvertices = *pvertices; - if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { - STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); - return output_ctx.num_vertices; - } - } - *pvertices = NULL; - return 0; +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, + stbtt_vertex **pvertices) { + // runs the charstring twice, once to count and once to output (to avoid + // realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex *)STBTT_malloc( + count_ctx.num_vertices * sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; } -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - stbtt__csctx c = STBTT__CSCTX_INIT(1); - int r = stbtt__run_charstring(info, glyph_index, &c); - if (x0) *x0 = r ? c.min_x : 0; - if (y0) *y0 = r ? c.min_y : 0; - if (x1) *x1 = r ? c.max_x : 0; - if (y1) *y1 = r ? c.max_y : 0; - return r ? c.num_vertices : 0; +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, + int *x0, int *y0, int *x1, int *y1) { + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) + *x0 = r ? c.min_x : 0; + if (y0) + *y0 = r ? c.min_y : 0; + if (x1) + *x1 = r ? c.max_x : 0; + if (y1) + *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; } -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - if (!info->cff.size) - return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); - else - return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, + stbtt_vertex **pvertices) { + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); } -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) -{ - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, + int glyph_index, int *advanceWidth, + int *leftSideBearing) { + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data + info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) + *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * glyph_index); + if (leftSideBearing) + *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * glyph_index + 2); + } else { + if (advanceWidth) + *advanceWidth = + ttSHORT(info->data + info->hmtx + 4 * (numOfLongHorMetrics - 1)); + if (leftSideBearing) + *leftSideBearing = + ttSHORT(info->data + info->hmtx + 4 * numOfLongHorMetrics + + 2 * (glyph_index - numOfLongHorMetrics)); + } } -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) -{ - stbtt_uint8 *data = info->data + info->kern; +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) { + stbtt_uint8 *data = info->data + info->kern; - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format + return 0; - return ttUSHORT(data+10); + return ttUSHORT(data + 10); } -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) -{ - stbtt_uint8 *data = info->data + info->kern; - int k, length; +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, + stbtt_kerningentry *table, + int table_length) { + stbtt_uint8 *data = info->data + info->kern; + int k, length; - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format + return 0; - length = ttUSHORT(data+10); - if (table_length < length) - length = table_length; + length = ttUSHORT(data + 10); + if (table_length < length) + length = table_length; - for (k = 0; k < length; k++) - { - table[k].glyph1 = ttUSHORT(data+18+(k*6)); - table[k].glyph2 = ttUSHORT(data+20+(k*6)); - table[k].advance = ttSHORT(data+22+(k*6)); - } + for (k = 0; k < length; k++) { + table[k].glyph1 = ttUSHORT(data + 18 + (k * 6)); + table[k].glyph2 = ttUSHORT(data + 20 + (k * 6)); + table[k].advance = ttSHORT(data + 22 + (k * 6)); + } - return length; + return length; } -static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint8 *data = info->data + info->kern; - stbtt_uint32 needle, straw; - int l, r, m; +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, + int glyph1, int glyph2) { + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format + return 0; - l = 0; - r = ttUSHORT(data+10) - 1; - needle = glyph1 << 16 | glyph2; - while (l <= r) { + l = 0; + r = ttUSHORT(data + 10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data + 18 + (m * 6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data + 22 + (m * 6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, + int glyph) { + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch (coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l = 0, r = glyphCount - 1, m; + int straw, needle = glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; m = (l + r) >> 1; - straw = ttULONG(data+18+(m*6)); // note: unaligned read + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; if (needle < straw) - r = m - 1; + r = m - 1; else if (needle > straw) - l = m + 1; + l = m + 1; + else { + return m; + } + } + break; + } + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l = 0, r = rangeCount - 1, m; + int strawStart, strawEnd, needle = glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + break; + } + + default: + return -1; // unsupported + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) { + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch (classDefFormat) { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + + 2 * (glyph - startGlyphID)); + break; + } + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l = 0, r = classRangeCount - 1, m; + int strawStart, strawEnd, needle = glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; else - return ttSHORT(data+22+(m*6)); - } - return 0; -} + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } -static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) -{ - stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); - switch (coverageFormat) { - case 1: { - stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + default: + return -1; // Unsupported definition type, return an error. + } - // Binary search. - stbtt_int32 l=0, r=glyphCount-1, m; - int straw, needle=glyph; - while (l <= r) { - stbtt_uint8 *glyphArray = coverageTable + 4; - stbtt_uint16 glyphID; - m = (l + r) >> 1; - glyphID = ttUSHORT(glyphArray + 2 * m); - straw = glyphID; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - return m; - } - } - break; - } - - case 2: { - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); - stbtt_uint8 *rangeArray = coverageTable + 4; - - // Binary search. - stbtt_int32 l=0, r=rangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *rangeRecord; - m = (l + r) >> 1; - rangeRecord = rangeArray + 6 * m; - strawStart = ttUSHORT(rangeRecord); - strawEnd = ttUSHORT(rangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else { - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); - return startCoverageIndex + glyph - strawStart; - } - } - break; - } - - default: return -1; // unsupported - } - - return -1; -} - -static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) -{ - stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); - switch (classDefFormat) - { - case 1: { - stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); - stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); - stbtt_uint8 *classDef1ValueArray = classDefTable + 6; - - if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) - return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - break; - } - - case 2: { - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); - stbtt_uint8 *classRangeRecords = classDefTable + 4; - - // Binary search. - stbtt_int32 l=0, r=classRangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *classRangeRecord; - m = (l + r) >> 1; - classRangeRecord = classRangeRecords + 6 * m; - strawStart = ttUSHORT(classRangeRecord); - strawEnd = ttUSHORT(classRangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); - } - break; - } - - default: - return -1; // Unsupported definition type, return an error. - } - - // "All glyphs not assigned to a class fall into class 0". (OpenType spec) - return 0; + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; } // Define to STBTT_assert(x) if you want to break on unimplemented formats. #define STBTT_GPOS_TODO_assert(x) -static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint16 lookupListOffset; - stbtt_uint8 *lookupList; - stbtt_uint16 lookupCount; - stbtt_uint8 *data; - stbtt_int32 i, sti; +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, + int glyph1, int glyph2) { + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i, sti; - if (!info->gpos) return 0; + if (!info->gpos) + return 0; - data = info->data + info->gpos; + data = info->data + info->gpos; - if (ttUSHORT(data+0) != 1) return 0; // Major version 1 - if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + if (ttUSHORT(data + 0) != 1) + return 0; // Major version 1 + if (ttUSHORT(data + 2) != 0) + return 0; // Minor version 0 - lookupListOffset = ttUSHORT(data+8); - lookupList = data + lookupListOffset; - lookupCount = ttUSHORT(lookupList); + lookupListOffset = ttUSHORT(data + 8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); - for (i=0; i= pairSetCount) return 0; + if (coverageIndex >= pairSetCount) + return 0; - needle=glyph2; - r=pairValueCount-1; - l=0; + needle = glyph2; + r = pairValueCount - 1; + l = 0; - // Binary search. - while (l <= r) { - stbtt_uint16 secondGlyph; - stbtt_uint8 *pairValue; - m = (l + r) >> 1; - pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; - secondGlyph = ttUSHORT(pairValue); - straw = secondGlyph; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - stbtt_int16 xAdvance = ttSHORT(pairValue + 2); - return xAdvance; - } - } - } else - return 0; - break; + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; } - - case 2: { - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? - stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); - stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); - int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); - int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); - - stbtt_uint16 class1Count = ttUSHORT(table + 12); - stbtt_uint16 class2Count = ttUSHORT(table + 14); - stbtt_uint8 *class1Records, *class2Records; - stbtt_int16 xAdvance; - - if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed - if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed - - class1Records = table + 16; - class2Records = class1Records + 2 * (glyph1class * class2Count); - xAdvance = ttSHORT(class2Records + 2 * glyph2class); - return xAdvance; - } else - return 0; - break; - } - - default: - return 0; // Unsupported position format - } + } + } else + return 0; + break; } - } - return 0; + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = + stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = + stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) + return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) + return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } + + default: + return 0; // Unsupported position format + } + } + } + + return 0; } -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) -{ - int xAdvance = 0; +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, + int g2) { + int xAdvance = 0; - if (info->gpos) - xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); - else if (info->kern) - xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); - return xAdvance; + return xAdvance; } -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) -{ - if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs - return 0; - return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, + int ch2) { + if (!info->kern && !info->gpos) // if no kerning table, don't waste time + // looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info, ch1), + stbtt_FindGlyphIndex(info, ch2)); } -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) -{ - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, + int codepoint, int *advanceWidth, + int *leftSideBearing) { + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info, codepoint), + advanceWidth, leftSideBearing); } -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, + int *descent, int *lineGap) { + if (ascent) + *ascent = ttSHORT(info->data + info->hhea + 4); + if (descent) + *descent = ttSHORT(info->data + info->hhea + 6); + if (lineGap) + *lineGap = ttSHORT(info->data + info->hhea + 8); } -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) -{ - int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); - if (!tab) - return 0; - if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); - if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); - if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); - return 1; +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, + int *typoAscent, int *typoDescent, + int *typoLineGap) { + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent) + *typoAscent = ttSHORT(info->data + tab + 68); + if (typoDescent) + *typoDescent = ttSHORT(info->data + tab + 70); + if (typoLineGap) + *typoLineGap = ttSHORT(info->data + tab + 72); + return 1; } -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) -{ - *x0 = ttSHORT(info->data + info->head + 36); - *y0 = ttSHORT(info->data + info->head + 38); - *x1 = ttSHORT(info->data + info->head + 40); - *y1 = ttSHORT(info->data + info->head + 42); +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, + int *y0, int *x1, int *y1) { + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); } -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) -{ - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); - return (float) height / fheight; +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, + float height) { + int fheight = ttSHORT(info->data + info->hhea + 4) - + ttSHORT(info->data + info->hhea + 6); + return (float)height / fheight; } -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) -{ - int unitsPerEm = ttUSHORT(info->data + info->head + 18); - return pixels / unitsPerEm; +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, + float pixels) { + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; } -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) -{ - STBTT_free(v, info->userdata); +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) { + STBTT_free(v, info->userdata); } -STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) -{ - int i; - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) { + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *)info); - int numEntries = ttUSHORT(svg_doc_list); - stbtt_uint8 *svg_docs = svg_doc_list + 2; + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; - for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) - return svg_doc; - } - return 0; + for (i = 0; i < numEntries; i++) { + stbtt_uint8 *svg_doc = svg_docs + (12 * i); + if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; } -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) -{ - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc; +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, + const char **svg) { + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; - if (info->svg == 0) - return 0; + if (info->svg == 0) + return 0; - svg_doc = stbtt_FindSVGDoc(info, gl); - if (svg_doc != NULL) { - *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); - return ttULONG(svg_doc + 8); - } else { - return 0; - } + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *)data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } } -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) -{ - return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, + int unicode_codepoint, const char **svg) { + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), + svg); } ////////////////////////////////////////////////////////////////////////////// @@ -2718,158 +3007,183 @@ STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_code // antialiasing software rasterizer // -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - // e.g. space character - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - // move to integral bboxes (treating pixels as little squares, what pixels get touched)? - if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); - if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); - if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); - if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); - } +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, + int glyph, float scale_x, + float scale_y, float shift_x, + float shift_y, int *ix0, + int *iy0, int *ix1, int *iy1) { + int x0 = 0, y0 = 0, x1, y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0, &y0, &x1, &y1)) { + // e.g. space character + if (ix0) + *ix0 = 0; + if (iy0) + *iy0 = 0; + if (ix1) + *ix1 = 0; + if (iy1) + *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels + // get touched)? + if (ix0) + *ix0 = STBTT_ifloor(x0 * scale_x + shift_x); + if (iy0) + *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) + *ix1 = STBTT_iceil(x1 * scale_x + shift_x); + if (iy1) + *iy1 = STBTT_iceil(-y0 * scale_y + shift_y); + } } -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, + float scale_x, float scale_y, int *ix0, + int *iy0, int *ix1, int *iy1) { + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, 0.0f, 0.0f, + ix0, iy0, ix1, iy1); } -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel( + const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, + float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) { + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font, codepoint), + scale_x, scale_y, shift_x, shift_y, ix0, iy0, + ix1, iy1); } -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, + int codepoint, float scale_x, + float scale_y, int *ix0, int *iy0, + int *ix1, int *iy1) { + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y, 0.0f, + 0.0f, ix0, iy0, ix1, iy1); } ////////////////////////////////////////////////////////////////////////////// // // Rasterizer -typedef struct stbtt__hheap_chunk -{ - struct stbtt__hheap_chunk *next; +typedef struct stbtt__hheap_chunk { + struct stbtt__hheap_chunk *next; } stbtt__hheap_chunk; -typedef struct stbtt__hheap -{ - struct stbtt__hheap_chunk *head; - void *first_free; - int num_remaining_in_head_chunk; +typedef struct stbtt__hheap { + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; } stbtt__hheap; -static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) -{ - if (hh->first_free) { - void *p = hh->first_free; - hh->first_free = * (void **) p; - return p; - } else { - if (hh->num_remaining_in_head_chunk == 0) { - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); - stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); - if (c == NULL) - return NULL; - c->next = hh->head; - hh->head = c; - hh->num_remaining_in_head_chunk = count; - } - --hh->num_remaining_in_head_chunk; - return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; - } +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) { + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = *(void **)p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *)STBTT_malloc( + sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *)(hh->head) + sizeof(stbtt__hheap_chunk) + + size * hh->num_remaining_in_head_chunk; + } } -static void stbtt__hheap_free(stbtt__hheap *hh, void *p) -{ - *(void **) p = hh->first_free; - hh->first_free = p; +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) { + *(void **)p = hh->first_free; + hh->first_free = p; } -static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) -{ - stbtt__hheap_chunk *c = hh->head; - while (c) { - stbtt__hheap_chunk *n = c->next; - STBTT_free(c, userdata); - c = n; - } +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) { + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } } typedef struct stbtt__edge { - float x0,y0, x1,y1; - int invert; + float x0, y0, x1, y1; + int invert; } stbtt__edge; - -typedef struct stbtt__active_edge -{ - struct stbtt__active_edge *next; - #if STBTT_RASTERIZER_VERSION==1 - int x,dx; - float ey; - int direction; - #elif STBTT_RASTERIZER_VERSION==2 - float fx,fdx,fdy; - float direction; - float sy; - float ey; - #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" - #endif +typedef struct stbtt__active_edge { + struct stbtt__active_edge *next; +#if STBTT_RASTERIZER_VERSION == 1 + int x, dx; + float ey; + int direction; +#elif STBTT_RASTERIZER_VERSION == 2 + float fx, fdx, fdy; + float direction; + float sy; + float ey; +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif } stbtt__active_edge; #if STBTT_RASTERIZER_VERSION == 1 -#define STBTT_FIXSHIFT 10 -#define STBTT_FIX (1 << STBTT_FIXSHIFT) -#define STBTT_FIXMASK (STBTT_FIX-1) +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX - 1) -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - if (!z) return z; +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, + int off_x, float start_point, + void *userdata) { + stbtt__active_edge *z = + (stbtt__active_edge *)stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) + return z; - // round dx down to avoid overshooting - if (dxdy < 0) - z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); - else - z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); - z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount - z->x -= off_x * STBTT_FIX; + z->x = STBTT_ifloor( + STBTT_FIX * e->x0 + + z->dx * + (start_point - + e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; - z->ey = e->y1; - z->next = 0; - z->direction = e->invert ? 1 : -1; - return z; + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; } #elif STBTT_RASTERIZER_VERSION == 2 -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - //STBTT_assert(e->y0 <= start_point); - if (!z) return z; - z->fdx = dxdy; - z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; - z->fx = e->x0 + dxdy * (start_point - e->y0); - z->fx -= off_x; - z->direction = e->invert ? 1.0f : -1.0f; - z->sy = e->y0; - z->ey = e->y1; - z->next = 0; - return z; +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, + int off_x, float start_point, + void *userdata) { + stbtt__active_edge *z = + (stbtt__active_edge *)stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + // STBTT_assert(e->y0 <= start_point); + if (!z) + return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f / dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; } #else #error "Unrecognized value of STBTT_RASTERIZER_VERSION" @@ -2879,929 +3193,1058 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i // note: this routine clips fills that extend off the edges... ideally this // wouldn't happen, but it could happen if the truetype glyph bounding boxes // are wrong, or if the user supplies a too-small bitmap -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) -{ - // non-zero winding fill - int x0=0, w=0; +static void stbtt__fill_active_edges(unsigned char *scanline, int len, + stbtt__active_edge *e, int max_weight) { + // non-zero winding fill + int x0 = 0, w = 0; - while (e) { + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; + w += e->direction; + } else { + int x1 = e->x; + w += e->direction; + // if we went to zero, we need to draw if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->direction; - } else { - int x1 = e->x; w += e->direction; - // if we went to zero, we need to draw - if (w == 0) { - int i = x0 >> STBTT_FIXSHIFT; - int j = x1 >> STBTT_FIXSHIFT; + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); - else - i = -1; // clip + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8)((x1 - x0) * max_weight >> + STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + + (stbtt_uint8)(((STBTT_FIX - (x0 & STBTT_FIXMASK)) * + max_weight) >> + STBTT_FIXSHIFT); + else + i = -1; // clip - if (j < len) // add antialiasing for x1 - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); - else - j = len; // clip + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + + (stbtt_uint8)(((x1 & STBTT_FIXMASK) * max_weight) >> + STBTT_FIXSHIFT); + else + j = len; // clip - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; - } - } - } + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8)max_weight; + } + } } + } - e = e->next; - } + e = e->next; + } } -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0; - int max_weight = (255 / vsubsample); // weight per vertical scanline - int s; // vertical subsample index - unsigned char scanline_data[512], *scanline; +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, + int n, int vsubsample, int off_x, + int off_y, void *userdata) { + stbtt__hheap hh = {0, 0, 0}; + stbtt__active_edge *active = NULL; + int y, j = 0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; - if (result->w > 512) - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); - else - scanline = scanline_data; + if (result->w > 512) + scanline = (unsigned char *)STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; - y = off_y * vsubsample; - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float)vsubsample + 1; - while (j < result->h) { - STBTT_memset(scanline, 0, result->w); - for (s=0; s < vsubsample; ++s) { - // find center of pixel for this scanline - float scan_y = y + 0.5f; - stbtt__active_edge **step = &active; + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s = 0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - } - - // resort the list if needed - for(;;) { - int changed=0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - stbtt__active_edge *t = *step; - stbtt__active_edge *q = t->next; - - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e->y0 <= scan_y) { - if (e->y1 > scan_y) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); - if (z != NULL) { - // find insertion point - if (active == NULL) - active = z; - else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } - } - ++e; - } - - // now process all active edges in XOR fashion - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); - - ++y; + // update all active edges; + // remove all active edges that terminate before the center of this + // scanline + while (*step) { + stbtt__active_edge *z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } } - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); - ++j; - } - stbtt__hheap_cleanup(&hh, userdata); + // resort the list if needed + for (;;) { + int changed = 0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; - if (scanline != scanline_data) - STBTT_free(scanline, userdata); + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) + break; + } + + // insert all edges that start before the center of this scanline -- omit + // ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = + stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); } #elif STBTT_RASTERIZER_VERSION == 2 -// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 -// (i.e. it has already been clipped to those) -static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) -{ - if (y0 == y1) return; - STBTT_assert(y0 < y1); - STBTT_assert(e->sy <= e->ey); - if (y0 > e->ey) return; - if (y1 < e->sy) return; - if (y0 < e->sy) { - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); - y0 = e->sy; - } - if (y1 > e->ey) { - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); - y1 = e->ey; - } +// the edge passed in here does not cross the vertical line at x or the vertical +// line at x+1 (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, + stbtt__active_edge *e, float x0, + float y0, float x1, float y1) { + if (y0 == y1) + return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) + return; + if (y1 < e->sy) + return; + if (y0 < e->sy) { + x0 += (x1 - x0) * (e->sy - y0) / (y1 - y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1 - x0) * (e->ey - y1) / (y1 - y0); + y1 = e->ey; + } - if (x0 == x) - STBTT_assert(x1 <= x+1); - else if (x0 == x+1) - STBTT_assert(x1 >= x); - else if (x0 <= x) - STBTT_assert(x1 <= x); - else if (x0 >= x+1) - STBTT_assert(x1 >= x+1); - else - STBTT_assert(x1 >= x && x1 <= x+1); + if (x0 == x) + STBTT_assert(x1 <= x + 1); + else if (x0 == x + 1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x + 1) + STBTT_assert(x1 >= x + 1); + else + STBTT_assert(x1 >= x && x1 <= x + 1); - if (x0 <= x && x1 <= x) - scanline[x] += e->direction * (y1-y0); - else if (x0 >= x+1 && x1 >= x+1) - ; - else { - STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); - scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position - } + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1 - y0); + else if (x0 >= x + 1 && x1 >= x + 1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x + 1 && x1 >= x && x1 <= x + 1); + scanline[x] += + e->direction * (y1 - y0) * + (1 - ((x0 - x) + (x1 - x)) / 2); // coverage = 1 - average x position + } } -static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) -{ - STBTT_assert(top_width >= 0); - STBTT_assert(bottom_width >= 0); - return (top_width + bottom_width) / 2.0f * height; +static float stbtt__sized_trapezoid_area(float height, float top_width, + float bottom_width) { + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; } -static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) -{ - return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, + float bx0, float bx1) { + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); } -static float stbtt__sized_triangle_area(float height, float width) -{ - return height * width / 2; +static float stbtt__sized_triangle_area(float height, float width) { + return height * width / 2; } -static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) -{ - float y_bottom = y_top+1; +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, + int len, stbtt__active_edge *e, + float y_top) { + float y_bottom = y_top + 1; - while (e) { - // brute force every pixel + while (e) { + // brute force every pixel - // compute intersection points with top & bottom - STBTT_assert(e->ey >= y_top); + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); - if (e->fdx == 0) { - float x0 = e->fx; - if (x0 < len) { - if (x0 >= 0) { - stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); - stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); - } else { - stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); - } - } - } else { - float x0 = e->fx; - float dx = e->fdx; - float xb = x0 + dx; - float x_top, x_bottom; - float sy0,sy1; - float dy = e->fdy; - STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); - - // compute endpoints of line segment clipped to this scanline (if the - // line segment starts on this scanline. x0 is the intersection of the - // line with y_top, but that may be off the line segment. - if (e->sy > y_top) { - x_top = x0 + dx * (e->sy - y_top); - sy0 = e->sy; - } else { - x_top = x0; - sy0 = y_top; - } - if (e->ey < y_bottom) { - x_bottom = x0 + dx * (e->ey - y_top); - sy1 = e->ey; - } else { - x_bottom = xb; - sy1 = y_bottom; - } - - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { - // from here on, we don't have to range check x values - - if ((int) x_top == (int) x_bottom) { - float height; - // simple case, only spans one pixel - int x = (int) x_top; - height = (sy1 - sy0) * e->direction; - STBTT_assert(x >= 0 && x < len); - scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); - scanline_fill[x] += height; // everything right of this pixel is filled - } else { - int x,x1,x2; - float y_crossing, y_final, step, sign, area; - // covers 2+ pixels - if (x_top > x_bottom) { - // flip scanline vertically; signed area is the same - float t; - sy0 = y_bottom - (sy0 - y_top); - sy1 = y_bottom - (sy1 - y_top); - t = sy0, sy0 = sy1, sy1 = t; - t = x_bottom, x_bottom = x_top, x_top = t; - dx = -dx; - dy = -dy; - t = x0, x0 = xb, xb = t; - } - STBTT_assert(dy >= 0); - STBTT_assert(dx >= 0); - - x1 = (int) x_top; - x2 = (int) x_bottom; - // compute intersection with y axis at x1+1 - y_crossing = y_top + dy * (x1+1 - x0); - - // compute intersection with y axis at x2 - y_final = y_top + dy * (x2 - x0); - - // x1 x_top x2 x_bottom - // y_top +------|-----+------------+------------+--------|---+------------+ - // | | | | | | - // | | | | | | - // sy0 | Txxxxx|............|............|............|............| - // y_crossing | *xxxxx.......|............|............|............| - // | | xxxxx..|............|............|............| - // | | /- xx*xxxx........|............|............| - // | | dy < | xxxxxx..|............|............| - // y_final | | \- | xx*xxx.........|............| - // sy1 | | | | xxxxxB...|............| - // | | | | | | - // | | | | | | - // y_bottom +------------+------------+------------+------------+------------+ - // - // goal is to measure the area covered by '.' in each pixel - - // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 - // @TODO: maybe test against sy1 rather than y_bottom? - if (y_crossing > y_bottom) - y_crossing = y_bottom; - - sign = e->direction; - - // area of the rectangle covered from sy0..y_crossing - area = sign * (y_crossing-sy0); - - // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) - scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); - - // check if final y_crossing is blown up; no test case for this - if (y_final > y_bottom) { - y_final = y_bottom; - dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom - } - - // in second pixel, area covered by line segment found in first pixel - // is always a rectangle 1 wide * the height of that line segment; this - // is exactly what the variable 'area' stores. it also gets a contribution - // from the line segment within it. the THIRD pixel will get the first - // pixel's rectangle contribution, the second pixel's rectangle contribution, - // and its own contribution. the 'own contribution' is the same in every pixel except - // the leftmost and rightmost, a trapezoid that slides down in each pixel. - // the second pixel's contribution to the third pixel will be the - // rectangle 1 wide times the height change in the second pixel, which is dy. - - step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, - // which multiplied by 1-pixel-width is how much pixel area changes for each step in x - // so the area advances by 'step' every time - - for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; // area of trapezoid is 1*step/2 - area += step; - } - STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down - STBTT_assert(sy1 > y_final-0.01f); - - // area covered in the last pixel is the rectangle from all the pixels to the left, - // plus the trapezoid filled by the line segment in this pixel all the way to the right edge - scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); - - // the rest of the line is filled based on the total height of the line segment in this pixel - scanline_fill[x2] += sign * (sy1-sy0); - } - } else { - // if edge goes outside of box we're drawing, we require - // clipping logic. since this does not match the intended use - // of this library, we use a different, very slow brute - // force implementation - // note though that this does happen some of the time because - // x_top and x_bottom can be extrapolated at the top & bottom of - // the shape and actually lie outside the bounding box - int x; - for (x=0; x < len; ++x) { - // cases: - // - // there can be up to two intersections with the pixel. any intersection - // with left or right edges can be handled by splitting into two (or three) - // regions. intersections with top & bottom do not necessitate case-wise logic. - // - // the old way of doing this found the intersections with the left & right edges, - // then used some simple logic to produce up to three segments in sorted order - // from top-to-bottom. however, this had a problem: if an x edge was epsilon - // across the x border, then the corresponding y position might not be distinct - // from the other y segment, and it might ignored as an empty segment. to avoid - // that, we need to explicitly produce segments based on x positions. - - // rename variables to clearly-defined pairs - float y0 = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - - // x = e->x + e->dx * (y-y_top) - // (y-y_top) = (x - e->x) / e->dx - // y = (x - e->x) / e->dx + y_top - float y1 = (x - x0) / dx + y_top; - float y2 = (x+1 - x0) / dx + y_top; - - if (x0 < x1 && x3 > x2) { // three segments descending down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x1 && x0 > x2) { // three segments descending down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else { // one segment - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); - } - } - } + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline, (int)x0, e, x0, y_top, x0, + y_bottom); + stbtt__handle_clipped_edge(scanline_fill - 1, (int)x0 + 1, e, x0, + y_top, x0, y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill - 1, 0, e, x0, y_top, x0, + y_bottom); + } } - e = e->next; - } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0, sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int)x_top == (int)x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int)x_top; + height = (sy1 - sy0) * e->direction; + STBTT_assert(x >= 0 && x < len); + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x + 1.0f, + x_bottom, x + 1.0f); + scanline_fill[x] += + height; // everything right of this pixel is filled + } else { + int x, x1, x2; + float y_crossing, y_final, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); + + x1 = (int)x_top; + x2 = (int)x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = y_top + dy * (x1 + 1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top + // +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | + // Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | + // xxxxx..|............|............|............| | | /- + // xx*xxxx........|............|............| | | dy < | + // xxxxxx..|............|............| + // y_final | | \- | + // xx*xxx.........|............| + // sy1 | | | | + // xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom + // +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, + // github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; + + sign = e->direction; + + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing - sy0); + + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1 + 1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + y_final = y_bottom; + dy = (y_final - y_crossing) / + (x2 - (x1 + 1)); // if denom=0, y_final = y_crossing, so + // y_final <= y_bottom + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; + // this is exactly what the variable 'area' stores. it also gets a + // contribution from the line segment within it. the THIRD pixel will + // get the first pixel's rectangle contribution, the second pixel's + // rectangle contribution, and its own contribution. the 'own + // contribution' is the same in every pixel except the leftmost and + // rightmost, a trapezoid that slides down in each pixel. the second + // pixel's contribution to the third pixel will be the rectangle 1 + // wide times the height change in the second pixel, which is dy. + + step = sign * dy * + 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes + // for each step in x so the area advances by 'step' every time + + for (x = x1 + 1; x < x2; ++x) { + scanline[x] += area + step / 2; // area of trapezoid is 1*step/2 + area += step; + } + STBTT_assert(STBTT_fabs(area) <= + 1.01f); // accumulated error from area += step unless we + // round step down + STBTT_assert(sy1 > y_final - 0.01f); + + // area covered in the last pixel is the rectangle from all the pixels + // to the left, plus the trapezoid filled by the line segment in this + // pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area( + sy1 - y_final, (float)x2, x2 + 1.0f, + x_bottom, x2 + 1.0f); + + // the rest of the line is filled based on the total height of the + // line segment in this pixel + scanline_fill[x2] += sign * (sy1 - sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box + int x; + for (x = 0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any + // intersection with left or right edges can be handled by splitting + // into two (or three) regions. intersections with top & bottom do not + // necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & + // right edges, then used some simple logic to produce up to three + // segments in sorted order from top-to-bottom. however, this had a + // problem: if an x edge was epsilon across the x border, then the + // corresponding y position might not be distinct from the other y + // segment, and it might ignored as an empty segment. to avoid that, + // we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float)(x); + float x2 = (float)(x + 1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x + 1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); + } else if (x3 < x1 && + x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1); + stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3); + } else if (x0 < x2 && + x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2); + stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x3, y3); + } + } + } + } + e = e->next; + } } // directly AA rasterize edges w/o supersampling -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0, i; - float scanline_data[129], *scanline, *scanline2; +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, + int n, int vsubsample, int off_x, + int off_y, void *userdata) { + stbtt__hheap hh = {0, 0, 0}; + stbtt__active_edge *active = NULL; + int y, j = 0, i; + float scanline_data[129], *scanline, *scanline2; - STBTT__NOTUSED(vsubsample); + STBTT__NOTUSED(vsubsample); - if (result->w > 64) - scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); - else - scanline = scanline_data; + if (result->w > 64) + scanline = + (float *)STBTT_malloc((result->w * 2 + 1) * sizeof(float), userdata); + else + scanline = scanline_data; - scanline2 = scanline + result->w; + scanline2 = scanline + result->w; - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; + y = off_y; + e[n].y0 = (float)(off_y + result->h) + 1; - while (j < result->h) { - // find center of pixel for this scanline - float scan_y_top = y + 0.0f; - float scan_y_bottom = y + 1.0f; - stbtt__active_edge **step = &active; + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; - STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); - STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + STBTT_memset(scanline, 0, result->w * sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w + 1) * sizeof(scanline[0])); - // update all active edges; - // remove all active edges that terminate before the top of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y_top) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - step = &((*step)->next); // advance through list - } + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge *z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list } + } - // insert all edges that start before the bottom of this scanline - while (e->y0 <= scan_y_bottom) { - if (e->y0 != e->y1) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); - if (z != NULL) { - if (j == 0 && off_y != 0) { - if (z->ey < scan_y_top) { - // this can happen due to subpixel positioning and some kind of fp rounding error i think - z->ey = scan_y_top; - } - } - STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds - // insert at front - z->next = active; - active = z; + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = + stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp + // rounding error i think + z->ey = scan_y_top; } - } - ++e; + } + STBTT_assert(z->ey >= + scan_y_top); // if we get really unlucky a tiny bit of an + // edge can be out of bounds + // insert at front + z->next = active; + active = z; + } } + ++e; + } - // now process all active edges - if (active) - stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2 + 1, result->w, active, + scan_y_top); - { - float sum = 0; - for (i=0; i < result->w; ++i) { - float k; - int m; - sum += scanline2[i]; - k = scanline[i] + sum; - k = (float) STBTT_fabs(k)*255 + 0.5f; - m = (int) k; - if (m > 255) m = 255; - result->pixels[j*result->stride + i] = (unsigned char) m; - } - } - // advance all the edges - step = &active; - while (*step) { - stbtt__active_edge *z = *step; - z->fx += z->fdx; // advance to position for current scanline - step = &((*step)->next); // advance through list + { + float sum = 0; + for (i = 0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float)STBTT_fabs(k) * 255 + 0.5f; + m = (int)k; + if (m > 255) + m = 255; + result->pixels[j * result->stride + i] = (unsigned char)m; } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } - ++y; - ++j; - } + ++y; + ++j; + } - stbtt__hheap_cleanup(&hh, userdata); + stbtt__hheap_cleanup(&hh, userdata); - if (scanline != scanline_data) - STBTT_free(scanline, userdata); + if (scanline != scanline_data) + STBTT_free(scanline, userdata); } #else #error "Unrecognized value of STBTT_RASTERIZER_VERSION" #endif -#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) +#define STBTT__COMPARE(a, b) ((a)->y0 < (b)->y0) -static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) -{ - int i,j; - for (i=1; i < n; ++i) { - stbtt__edge t = p[i], *a = &t; - j = i; - while (j > 0) { - stbtt__edge *b = &p[j-1]; - int c = STBTT__COMPARE(a,b); - if (!c) break; - p[j] = p[j-1]; - --j; - } - if (i != j) - p[j] = t; - } +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) { + int i, j; + for (i = 1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j - 1]; + int c = STBTT__COMPARE(a, b); + if (!c) + break; + p[j] = p[j - 1]; + --j; + } + if (i != j) + p[j] = t; + } } -static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) -{ - /* threshold for transitioning to insertion sort */ - while (n > 12) { - stbtt__edge t; - int c01,c12,c,m,i,j; +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) { + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01, c12, c, m, i, j; - /* compute median of three */ - m = n >> 1; - c01 = STBTT__COMPARE(&p[0],&p[m]); - c12 = STBTT__COMPARE(&p[m],&p[n-1]); - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ - if (c01 != c12) { - /* otherwise, we'll need to swap something else to middle */ - int z; - c = STBTT__COMPARE(&p[0],&p[n-1]); - /* 0>mid && midn => n; 0 0 */ - /* 0n: 0>n => 0; 0 n */ - z = (c == c12) ? 0 : n-1; - t = p[z]; - p[z] = p[m]; - p[m] = t; - } - /* now p[m] is the median-of-three */ - /* swap it to the beginning so it won't move around */ - t = p[0]; - p[0] = p[m]; + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0], &p[m]); + c12 = STBTT__COMPARE(&p[m], &p[n - 1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0], &p[n - 1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n - 1; + t = p[z]; + p[z] = p[m]; p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; - /* partition loop */ - i=1; - j=n-1; - for(;;) { - /* handling of equality is crucial here */ - /* for sentinels & efficiency with duplicates */ - for (;;++i) { - if (!STBTT__COMPARE(&p[i], &p[0])) break; - } - for (;;--j) { - if (!STBTT__COMPARE(&p[0], &p[j])) break; - } - /* make sure we haven't crossed */ - if (i >= j) break; - t = p[i]; - p[i] = p[j]; - p[j] = t; + /* partition loop */ + i = 1; + j = n - 1; + for (;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;; ++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) + break; + } + for (;; --j) { + if (!STBTT__COMPARE(&p[0], &p[j])) + break; + } + /* make sure we haven't crossed */ + if (i >= j) + break; + t = p[i]; + p[i] = p[j]; + p[j] = t; - ++i; - --j; - } - /* recurse on smaller side, iterate on larger */ - if (j < (n-i)) { - stbtt__sort_edges_quicksort(p,j); - p = p+i; - n = n-i; - } else { - stbtt__sort_edges_quicksort(p+i, n-i); - n = j; - } - } + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n - i)) { + stbtt__sort_edges_quicksort(p, j); + p = p + i; + n = n - i; + } else { + stbtt__sort_edges_quicksort(p + i, n - i); + n = j; + } + } } -static void stbtt__sort_edges(stbtt__edge *p, int n) -{ - stbtt__sort_edges_quicksort(p, n); - stbtt__sort_edges_ins_sort(p, n); +static void stbtt__sort_edges(stbtt__edge *p, int n) { + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); } -typedef struct -{ - float x,y; +typedef struct { + float x, y; } stbtt__point; -static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - stbtt__edge *e; - int n,i,j,k,m; +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, + int *wcount, int windings, float scale_x, + float scale_y, float shift_x, float shift_y, + int off_x, int off_y, int invert, void *userdata) { + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n, i, j, k, m; #if STBTT_RASTERIZER_VERSION == 1 - int vsubsample = result->h < 8 ? 15 : 5; + int vsubsample = result->h < 8 ? 15 : 5; #elif STBTT_RASTERIZER_VERSION == 2 - int vsubsample = 1; + int vsubsample = 1; #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" #endif - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity - // now we have to blow out the windings into explicit edge lists - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i = 0; i < windings; ++i) + n += wcount[i]; - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel - if (e == 0) return; - n = 0; + e = (stbtt__edge *)STBTT_malloc(sizeof(*e) * (n + 1), + userdata); // add an extra one as a sentinel + if (e == 0) + return; + n = 0; - m=0; - for (i=0; i < windings; ++i) { - stbtt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - // skip the edge if horizontal - if (p[j].y == p[k].y) - continue; - // add edge from j to k to the list - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; - ++n; + m = 0; + for (i = 0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i] - 1; + for (k = 0; k < wcount[i]; j = k++) { + int a = k, b = j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a = j, b = k; } - } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } - // now sort the edges by their highest point (should snap to integer, and then by x) - //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); - stbtt__sort_edges(e, n); + // now sort the edges by their highest point (should snap to integer, and then + // by x) + // STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); - // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + // now, traverse the scanlines and find the intersections on each scanline, + // use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, + userdata); - STBTT_free(e, userdata); + STBTT_free(e, userdata); } -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) -{ - if (!points) return; // during first pass, it's unallocated - points[n].x = x; - points[n].y = y; +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) { + if (!points) + return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; } -// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching -static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) -{ - // midpoint - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - // versus directly drawn line - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) // 65536 segments on one curve better be enough! - return 1; - if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; +// tessellate until threshold p is happy... @TODO warped to compensate for +// non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, + float x0, float y0, float x1, float y1, + float x2, float y2, + float objspace_flatness_squared, int n) { + // midpoint + float mx = (x0 + 2 * x1 + x2) / 4; + float my = (y0 + 2 * y1 + y2) / 4; + // versus directly drawn line + float dx = (x0 + x2) / 2 - mx; + float dy = (y0 + y2) / 2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx * dx + dy * dy > + objspace_flatness_squared) { // half-pixel error allowed... need to be + // smaller if AA + stbtt__tesselate_curve(points, num_points, x0, y0, (x0 + x1) / 2.0f, + (y0 + y1) / 2.0f, mx, my, objspace_flatness_squared, + n + 1); + stbtt__tesselate_curve(points, num_points, mx, my, (x1 + x2) / 2.0f, + (y1 + y2) / 2.0f, x2, y2, objspace_flatness_squared, + n + 1); + } else { + stbtt__add_point(points, *num_points, x2, y2); + *num_points = *num_points + 1; + } + return 1; } -static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) -{ - // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough - float dx0 = x1-x0; - float dy0 = y1-y0; - float dx1 = x2-x1; - float dy1 = y2-y1; - float dx2 = x3-x2; - float dy2 = y3-y2; - float dx = x3-x0; - float dy = y3-y0; - float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); - float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); - float flatness_squared = longlen*longlen-shortlen*shortlen; +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, + float x0, float y0, float x1, float y1, + float x2, float y2, float x3, float y3, + float objspace_flatness_squared, int n) { + // @TODO this "flatness" calculation is just made-up nonsense that seems to + // work well enough + float dx0 = x1 - x0; + float dy0 = y1 - y0; + float dx1 = x2 - x1; + float dy1 = y2 - y1; + float dx2 = x3 - x2; + float dy2 = y3 - y2; + float dx = x3 - x0; + float dy = y3 - y0; + float longlen = (float)(STBTT_sqrt(dx0 * dx0 + dy0 * dy0) + + STBTT_sqrt(dx1 * dx1 + dy1 * dy1) + + STBTT_sqrt(dx2 * dx2 + dy2 * dy2)); + float shortlen = (float)STBTT_sqrt(dx * dx + dy * dy); + float flatness_squared = longlen * longlen - shortlen * shortlen; - if (n > 16) // 65536 segments on one curve better be enough! - return; + if (n > 16) // 65536 segments on one curve better be enough! + return; - if (flatness_squared > objspace_flatness_squared) { - float x01 = (x0+x1)/2; - float y01 = (y0+y1)/2; - float x12 = (x1+x2)/2; - float y12 = (y1+y2)/2; - float x23 = (x2+x3)/2; - float y23 = (y2+y3)/2; + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0 + x1) / 2; + float y01 = (y0 + y1) / 2; + float x12 = (x1 + x2) / 2; + float y12 = (y1 + y2) / 2; + float x23 = (x2 + x3) / 2; + float y23 = (y2 + y3) / 2; - float xa = (x01+x12)/2; - float ya = (y01+y12)/2; - float xb = (x12+x23)/2; - float yb = (y12+y23)/2; + float xa = (x01 + x12) / 2; + float ya = (y01 + y12) / 2; + float xb = (x12 + x23) / 2; + float yb = (y12 + y23) / 2; - float mx = (xa+xb)/2; - float my = (ya+yb)/2; + float mx = (xa + xb) / 2; + float my = (ya + yb) / 2; - stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x3,y3); - *num_points = *num_points+1; - } + stbtt__tesselate_cubic(points, num_points, x0, y0, x01, y01, xa, ya, mx, my, + objspace_flatness_squared, n + 1); + stbtt__tesselate_cubic(points, num_points, mx, my, xb, yb, x23, y23, x3, y3, + objspace_flatness_squared, n + 1); + } else { + stbtt__add_point(points, *num_points, x3, y3); + *num_points = *num_points + 1; + } } // returns number of contours -static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) -{ - stbtt__point *points=0; - int num_points=0; +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, + float objspace_flatness, + int **contour_lengths, + int *num_contours, void *userdata) { + stbtt__point *points = 0; + int num_points = 0; - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i,n=0,start=0, pass; + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i, n = 0, start = 0, pass; - // count how many "moves" there are to get the contour count - for (i=0; i < num_verts; ++i) - if (vertices[i].type == STBTT_vmove) - ++n; + // count how many "moves" there are to get the contour count + for (i = 0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; - *num_contours = n; - if (n == 0) return 0; + *num_contours = n; + if (n == 0) + return 0; - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + *contour_lengths = + (int *)STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } - // make two passes through the points so we don't need to realloc - for (pass=0; pass < 2; ++pass) { - float x=0,y=0; - if (pass == 1) { - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); - if (points == NULL) goto error; + // make two passes through the points so we don't need to realloc + for (pass = 0; pass < 2; ++pass) { + float x = 0, y = 0; + if (pass == 1) { + points = (stbtt__point *)STBTT_malloc(num_points * sizeof(points[0]), + userdata); + if (points == NULL) + goto error; + } + num_points = 0; + n = -1; + for (i = 0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x, y, vertices[i].cx, + vertices[i].cy, vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x, y, vertices[i].cx, + vertices[i].cy, vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; } - num_points = 0; - n= -1; - for (i=0; i < num_verts; ++i) { - switch (vertices[i].type) { - case STBTT_vmove: - // start the next contour - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; + } + (*contour_lengths)[n] = num_points - start; + } - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x,y); - break; - case STBTT_vline: - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x, y); - break; - case STBTT_vcurve: - stbtt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - case STBTT_vcubic: - stbtt__tesselate_cubic(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].cx1, vertices[i].cy1, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - } - } - (*contour_lengths)[n] = num_points - start; - } - - return points; + return points; error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; } -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count = 0; - int *winding_lengths = NULL; - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); - if (windings) { - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); - STBTT_free(winding_lengths, userdata); - STBTT_free(windings, userdata); - } +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, + stbtt_vertex *vertices, int num_verts, + float scale_x, float scale_y, float shift_x, + float shift_y, int x_off, int y_off, int invert, + void *userdata) { + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = + stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, + &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, + scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } } -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) { + STBTT_free(bitmap, userdata); } -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - int ix0,iy0,ix1,iy1; - stbtt__bitmap gbm; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel( + const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, + float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) { + int ix0, iy0, ix1, iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) { - STBTT_free(vertices, info->userdata); - return NULL; - } - scale_y = scale_x; - } + if (scale_x == 0) + scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, + shift_y, &ix0, &iy0, &ix1, &iy1); - // now we get the size - gbm.w = (ix1 - ix0); - gbm.h = (iy1 - iy0); - gbm.pixels = NULL; // in case we error + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error - if (width ) *width = gbm.w; - if (height) *height = gbm.h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; + if (width) + *width = gbm.w; + if (height) + *height = gbm.h; + if (xoff) + *xoff = ix0; + if (yoff) + *yoff = iy0; - if (gbm.w && gbm.h) { - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); - if (gbm.pixels) { - gbm.stride = gbm.w; + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *)STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); - } - } - STBTT_free(vertices, info->userdata); - return gbm.pixels; + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, + shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; } -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +STBTT_DEF unsigned char * +stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, + int glyph, int *width, int *height, int *xoff, int *yoff) { + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, + width, height, xoff, yoff); } -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) -{ - int ix0,iy0; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, + unsigned char *output, int out_w, + int out_h, int out_stride, + float scale_x, float scale_y, + float shift_x, float shift_y, + int glyph) { + int ix0, iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, + shift_y, &ix0, &iy0, 0, 0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; - if (gbm.w && gbm.h) - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, + shift_y, ix0, iy0, 1, info->userdata); - STBTT_free(vertices, info->userdata); + STBTT_free(vertices, info->userdata); } -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, + unsigned char *output, int out_w, + int out_h, int out_stride, float scale_x, + float scale_y, int glyph) { + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, + scale_y, 0.0f, 0.0f, glyph); } -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +STBTT_DEF unsigned char * +stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, + float scale_y, float shift_x, float shift_y, + int codepoint, int *width, int *height, + int *xoff, int *yoff) { + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, shift_x, shift_y, + stbtt_FindGlyphIndex(info, codepoint), + width, height, xoff, yoff); } -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter( + const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, + int oversample_x, int oversample_y, float *sub_x, float *sub_y, + int codepoint) { + stbtt_MakeGlyphBitmapSubpixelPrefilter( + info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, + shift_y, oversample_x, oversample_y, sub_x, sub_y, + stbtt_FindGlyphIndex(info, codepoint)); } -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, + unsigned char *output, + int out_w, int out_h, + int out_stride, float scale_x, + float scale_y, float shift_x, + float shift_y, int codepoint) { + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, + scale_y, shift_x, shift_y, + stbtt_FindGlyphIndex(info, codepoint)); } -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, + float scale_x, float scale_y, + int codepoint, int *width, + int *height, int *xoff, + int *yoff) { + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, + codepoint, width, height, xoff, yoff); } -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) -{ - stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, + unsigned char *output, int out_w, + int out_h, int out_stride, + float scale_x, float scale_y, + int codepoint) { + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, + scale_x, scale_y, 0.0f, 0.0f, codepoint); } ////////////////////////////////////////////////////////////////////////////// @@ -3810,71 +4253,75 @@ STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned ch // // This is SUPER-CRAPPY packing to keep source code small -static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata) -{ - float scale; - int x,y,bottom_y, i; - stbtt_fontinfo f; - f.userdata = NULL; - if (!stbtt_InitFont(&f, data, offset)) - return -1; - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - x=y=1; - bottom_y = 1; +static int stbtt_BakeFontBitmap_internal( + unsigned char *data, + int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) { + float scale; + int x, y, bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw * ph); // background of 0 around pixels + x = y = 1; + bottom_y = 1; - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); - for (i=0; i < num_chars; ++i) { - int advance, lsb, x0,y0,x1,y1,gw,gh; - int g = stbtt_FindGlyphIndex(&f, first_char + i); - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); - gw = x1-x0; - gh = y1-y0; - if (x + gw + 1 >= pw) - y = bottom_y, x = 1; // advance to next row - if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row - return -i; - STBTT_assert(x+gw < pw); - STBTT_assert(y+gh < ph); - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); - chardata[i].x0 = (stbtt_int16) x; - chardata[i].y0 = (stbtt_int16) y; - chardata[i].x1 = (stbtt_int16) (x + gw); - chardata[i].y1 = (stbtt_int16) (y + gh); - chardata[i].xadvance = scale * advance; - chardata[i].xoff = (float) x0; - chardata[i].yoff = (float) y0; - x = x + gw + 1; - if (y+gh+1 > bottom_y) - bottom_y = y+gh+1; - } - return bottom_y; + for (i = 0; i < num_chars; ++i) { + int advance, lsb, x0, y0, x1, y1, gw, gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1); + gw = x1 - x0; + gh = y1 - y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= + ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x + gw < pw); + STBTT_assert(y + gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale, scale, g); + chardata[i].x0 = (stbtt_int16)x; + chardata[i].y0 = (stbtt_int16)y; + chardata[i].x1 = (stbtt_int16)(x + gw); + chardata[i].y1 = (stbtt_int16)(y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float)x0; + chardata[i].yoff = (float)y0; + x = x + gw + 1; + if (y + gh + 1 > bottom_y) + bottom_y = y + gh + 1; + } + return bottom_y; } -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, + int ph, int char_index, float *xpos, + float *ypos, stbtt_aligned_quad *q, + int opengl_fillrule) { + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); - q->x0 = round_x + d3d_bias; - q->y0 = round_y + d3d_bias; - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; - *xpos += b->xadvance; + *xpos += b->xadvance; } ////////////////////////////////////////////////////////////////////////////// @@ -3889,61 +4336,58 @@ typedef int stbrp_coord; //////////////////////////////////////////////////////////////////////////////////// // // // // -// COMPILER WARNING ?!?!? // +// COMPILER WARNING ?!?!? // // // // // -// if you get a compile warning due to these symbols being defined more than // -// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // // // //////////////////////////////////////////////////////////////////////////////////// -typedef struct -{ - int width,height; - int x,y,bottom_y; +typedef struct { + int width, height; + int x, y, bottom_y; } stbrp_context; -typedef struct -{ - unsigned char x; +typedef struct { + unsigned char x; } stbrp_node; -struct stbrp_rect -{ - stbrp_coord x,y; - int id,w,h,was_packed; +struct stbrp_rect { + stbrp_coord x, y; + int id, w, h, was_packed; }; -static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) -{ - con->width = pw; - con->height = ph; - con->x = 0; - con->y = 0; - con->bottom_y = 0; - STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); +static void stbrp_init_target(stbrp_context *con, int pw, int ph, + stbrp_node *nodes, int num_nodes) { + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); } -static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) -{ - int i; - for (i=0; i < num_rects; ++i) { - if (con->x + rects[i].w > con->width) { - con->x = 0; - con->y = con->bottom_y; - } - if (con->y + rects[i].h > con->height) - break; - rects[i].x = con->x; - rects[i].y = con->y; - rects[i].was_packed = 1; - con->x += rects[i].w; - if (con->y + rects[i].h > con->bottom_y) - con->bottom_y = con->y + rects[i].h; - } - for ( ; i < num_rects; ++i) - rects[i].was_packed = 0; +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, + int num_rects) { + int i; + for (i = 0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for (; i < num_rects; ++i) + rects[i].was_packed = 0; } #endif @@ -3954,437 +4398,468 @@ static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rect // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) -{ - stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); - int num_nodes = pw - padding; - stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, + int pw, int ph, int stride_in_bytes, int padding, + void *alloc_context) { + stbrp_context *context = + (stbrp_context *)STBTT_malloc(sizeof(*context), alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = + (stbrp_node *)STBTT_malloc(sizeof(*nodes) * num_nodes, alloc_context); - if (context == NULL || nodes == NULL) { - if (context != NULL) STBTT_free(context, alloc_context); - if (nodes != NULL) STBTT_free(nodes , alloc_context); - return 0; - } + if (context == NULL || nodes == NULL) { + if (context != NULL) + STBTT_free(context, alloc_context); + if (nodes != NULL) + STBTT_free(nodes, alloc_context); + return 0; + } - spc->user_allocator_context = alloc_context; - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - spc->skip_missing = 0; + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; - stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + stbrp_init_target(context, pw - padding, ph - padding, nodes, num_nodes); - if (pixels) - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + if (pixels) + STBTT_memset(pixels, 0, pw * ph); // background of 0 around pixels - return 1; + return 1; } -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) -{ - STBTT_free(spc->nodes , spc->user_allocator_context); - STBTT_free(spc->pack_info, spc->user_allocator_context); +STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc) { + STBTT_free(spc->nodes, spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); } -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) -{ - STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); - STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); - if (h_oversample <= STBTT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= STBTT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, + unsigned int h_oversample, + unsigned int v_oversample) { + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; } -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) -{ - spc->skip_missing = skip; +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, + int skip) { + spc->skip_missing = skip; } -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE - 1) -static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_w = w - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < h; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, + int stride_in_bytes, unsigned int kernel_width) { + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset( + buffer, 0, + STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j = 0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); - total = 0; + total = 0; - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / kernel_width); - } - break; + // make kernel_width a constant in common cases so compiler can optimize out + // the divide + switch (kernel_width) { + case 2: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 2); + } + break; + case 3: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 3); + } + break; + case 4: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 4); + } + break; + case 5: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / 5); + } + break; + default: + for (i = 0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char)(total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char)(total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, + int stride_in_bytes, unsigned int kernel_width) { + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset( + buffer, 0, + STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j = 0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out + // the divide + switch (kernel_width) { + case 2: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = + pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 2); + } + break; + case 3: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = + pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 3); + } + break; + case 4: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = + pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 4); + } + break; + case 5: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = + pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / 5); + } + break; + default: + for (i = 0; i <= safe_h; ++i) { + total += pixels[i * stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i + kernel_width) & STBTT__OVER_MASK] = + pixels[i * stride_in_bytes]; + pixels[i * stride_in_bytes] = (unsigned char)(total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i * stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i * stride_in_bytes] = (unsigned char)(total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) { + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given +// ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, + const stbtt_fontinfo *info, + stbtt_pack_range *ranges, + int num_ranges, + stbrp_rect *rects) { + int i, j, k; + int missing_glyph_added = 0; + + k = 0; + for (i = 0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) + : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char)spc->h_oversample; + ranges[i].v_oversample = (unsigned char)spc->v_oversample; + for (j = 0; j < ranges[i].num_chars; ++j) { + int x0, y0, x1, y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL + ? ranges[i].first_unicode_codepoint_in_range + j + : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale * spc->h_oversample, + scale * spc->v_oversample, 0, 0, &x0, + &y0, &x1, &y1); + rects[k].w = + (stbrp_coord)(x1 - x0 + spc->padding + spc->h_oversample - 1); + rects[k].h = + (stbrp_coord)(y1 - y0 + spc->padding + spc->v_oversample - 1); + if (glyph == 0) + missing_glyph_added = 1; + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter( + const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, + int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, + int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) { + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), out_stride, scale_x, + scale_y, shift_x, shift_y, glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given +// ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, + const stbtt_fontinfo *info, + stbtt_pack_range *ranges, + int num_ranges, + stbrp_rect *rects) { + int i, j, k, missing_glyph = -1, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i = 0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) + : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h, recip_v, sub_x, sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j = 0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0, y0, x1, y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL + ? ranges[i].first_unicode_codepoint_in_range + j + : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord)spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, scale * spc->h_oversample, + scale * spc->v_oversample, &x0, &y0, &x1, &y1); + stbtt_MakeGlyphBitmapSubpixel( + info, spc->pixels + r->x + r->y * spc->stride_in_bytes, + r->w - spc->h_oversample + 1, r->h - spc->v_oversample + 1, + spc->stride_in_bytes, scale * spc->h_oversample, + scale * spc->v_oversample, 0, 0, glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y * spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y * spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16)r->x; + bc->y0 = (stbtt_int16)r->y; + bc->x1 = (stbtt_int16)(r->x + r->w); + bc->y1 = (stbtt_int16)(r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float)x0 * recip_h + sub_x; + bc->yoff = (float)y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && + missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = + ranges[i].chardata_for_range[missing_glyph]; + } else { + return_value = 0; // if any fail, report failure } - for (; i < w; ++i) { - STBTT_assert(pixels[i] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i] = (unsigned char) (total / kernel_width); - } + ++k; + } + } - pixels += stride_in_bytes; - } + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; } -static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_h = h - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < w; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < h; ++i) { - STBTT_assert(pixels[i*stride_in_bytes] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - - pixels += 1; - } +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, + stbrp_rect *rects, int num_rects) { + stbrp_pack_rects((stbrp_context *)spc->pack_info, rects, num_rects); } -static float stbtt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, + const unsigned char *fontdata, + int font_index, stbtt_pack_range *ranges, + int num_ranges) { + stbtt_fontinfo info; + int i, j, n, return_value = 1; + // stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; - // The prefilter is a box filter of width "oversample", - // which shifts phase by (oversample - 1)/2 pixels in - // oversampled space. We want to shift in the opposite - // direction to counter this. - return (float)-(oversample - 1) / (2.0f * (float)oversample); + // flag all characters as NOT packed + for (i = 0; i < num_ranges; ++i) + for (j = 0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i = 0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *)STBTT_malloc(sizeof(*rects) * n, + spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, + stbtt_GetFontOffsetForIndex(fontdata, font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, + num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; } -// rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k; - int missing_glyph_added = 0; - - k=0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - ranges[i].h_oversample = (unsigned char) spc->h_oversample; - ranges[i].v_oversample = (unsigned char) spc->v_oversample; - for (j=0; j < ranges[i].num_chars; ++j) { - int x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { - rects[k].w = rects[k].h = 0; - } else { - stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - &x0,&y0,&x1,&y1); - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); - if (glyph == 0) - missing_glyph_added = 1; - } - ++k; - } - } - - return k; +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, + const unsigned char *fontdata, int font_index, + float font_size, + int first_unicode_codepoint_in_range, + int num_chars_in_range, + stbtt_packedchar *chardata_for_range) { + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); } -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, - output, - out_w - (prefilter_x - 1), - out_h - (prefilter_y - 1), - out_stride, - scale_x, - scale_y, - shift_x, - shift_y, - glyph); - - if (prefilter_x > 1) - stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); - - if (prefilter_y > 1) - stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); - - *sub_x = stbtt__oversample_shift(prefilter_x); - *sub_y = stbtt__oversample_shift(prefilter_y); +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, + int index, float size, float *ascent, + float *descent, float *lineGap) { + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) + : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float)i_ascent * scale; + *descent = (float)i_descent * scale; + *lineGap = (float)i_lineGap * scale; } -// rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k, missing_glyph = -1, return_value = 1; +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, + int ph, int char_index, float *xpos, + float *ypos, stbtt_aligned_quad *q, + int align_to_integer) { + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; - // save current values - int old_h_over = spc->h_oversample; - int old_v_over = spc->v_oversample; + if (align_to_integer) { + float x = (float)STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float)STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } - k = 0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - float recip_h,recip_v,sub_x,sub_y; - spc->h_oversample = ranges[i].h_oversample; - spc->v_oversample = ranges[i].v_oversample; - recip_h = 1.0f / spc->h_oversample; - recip_v = 1.0f / spc->v_oversample; - sub_x = stbtt__oversample_shift(spc->h_oversample); - sub_y = stbtt__oversample_shift(spc->v_oversample); - for (j=0; j < ranges[i].num_chars; ++j) { - stbrp_rect *r = &rects[k]; - if (r->was_packed && r->w != 0 && r->h != 0) { - stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - stbrp_coord pad = (stbrp_coord) spc->padding; + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; - // pad on left and top - r->x += pad; - r->y += pad; - r->w -= pad; - r->h -= pad; - stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); - stbtt_GetGlyphBitmapBox(info, glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - &x0,&y0,&x1,&y1); - stbtt_MakeGlyphBitmapSubpixel(info, - spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w - spc->h_oversample+1, - r->h - spc->v_oversample+1, - spc->stride_in_bytes, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - glyph); - - if (spc->h_oversample > 1) - stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->h_oversample); - - if (spc->v_oversample > 1) - stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->v_oversample); - - bc->x0 = (stbtt_int16) r->x; - bc->y0 = (stbtt_int16) r->y; - bc->x1 = (stbtt_int16) (r->x + r->w); - bc->y1 = (stbtt_int16) (r->y + r->h); - bc->xadvance = scale * advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = (x0 + r->w) * recip_h + sub_x; - bc->yoff2 = (y0 + r->h) * recip_v + sub_y; - - if (glyph == 0) - missing_glyph = j; - } else if (spc->skip_missing) { - return_value = 0; - } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { - ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; - } else { - return_value = 0; // if any fail, report failure - } - - ++k; - } - } - - // restore original values - spc->h_oversample = old_h_over; - spc->v_oversample = old_v_over; - - return return_value; -} - -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) -{ - stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); -} - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) -{ - stbtt_fontinfo info; - int i,j,n, return_value = 1; - //stbrp_context *context = (stbrp_context *) spc->pack_info; - stbrp_rect *rects; - - // flag all characters as NOT packed - for (i=0; i < num_ranges; ++i) - for (j=0; j < ranges[i].num_chars; ++j) - ranges[i].chardata_for_range[j].x0 = - ranges[i].chardata_for_range[j].y0 = - ranges[i].chardata_for_range[j].x1 = - ranges[i].chardata_for_range[j].y1 = 0; - - n = 0; - for (i=0; i < num_ranges; ++i) - n += ranges[i].num_chars; - - rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); - if (rects == NULL) - return 0; - - info.userdata = spc->user_allocator_context; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); - - n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); - - stbtt_PackFontRangesPackRects(spc, rects, n); - - return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); - - STBTT_free(rects, spc->user_allocator_context); - return return_value; -} - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) -{ - stbtt_pack_range range; - range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; - range.array_of_unicode_codepoints = NULL; - range.num_chars = num_chars_in_range; - range.chardata_for_range = chardata_for_range; - range.font_size = font_size; - return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); -} - -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) -{ - int i_ascent, i_descent, i_lineGap; - float scale; - stbtt_fontinfo info; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); - scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); - stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); - *ascent = (float) i_ascent * scale; - *descent = (float) i_descent * scale; - *lineGap = (float) i_lineGap * scale; -} - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) -{ - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_packedchar *b = chardata + char_index; - - if (align_to_integer) { - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; + *xpos += b->xadvance; } ////////////////////////////////////////////////////////////////////////////// @@ -4392,379 +4867,413 @@ STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int // sdf computation // -#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) -#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) +#define STBTT_min(a, b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a, b) ((a) < (b) ? (b) : (a)) -static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) -{ - float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; - float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; - float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; - float roperp = orig[1]*ray[0] - orig[0]*ray[1]; +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], + float q1[2], float q2[2], + float hits[2][2]) { + float q0perp = q0[1] * ray[0] - q0[0] * ray[1]; + float q1perp = q1[1] * ray[0] - q1[0] * ray[1]; + float q2perp = q2[1] * ray[0] - q2[0] * ray[1]; + float roperp = orig[1] * ray[0] - orig[0] * ray[1]; - float a = q0perp - 2*q1perp + q2perp; - float b = q1perp - q0perp; - float c = q0perp - roperp; + float a = q0perp - 2 * q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; - float s0 = 0., s1 = 0.; - int num_s = 0; + float s0 = 0., s1 = 0.; + int num_s = 0; - if (a != 0.0) { - float discr = b*b - a*c; - if (discr > 0.0) { - float rcpna = -1 / a; - float d = (float) STBTT_sqrt(discr); - s0 = (b+d) * rcpna; - s1 = (b-d) * rcpna; - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { - if (num_s == 0) s0 = s1; - ++num_s; - } - } - } else { - // 2*b*s + c = 0 - // s = -c / (2*b) - s0 = c / (-2 * b); + if (a != 0.0) { + float discr = b * b - a * c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float)STBTT_sqrt(discr); + s0 = (b + d) * rcpna; + s1 = (b - d) * rcpna; if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - } - - if (num_s == 0) - return 0; - else { - float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); - float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; - - float q0d = q0[0]*rayn_x + q0[1]*rayn_y; - float q1d = q1[0]*rayn_x + q1[1]*rayn_y; - float q2d = q2[0]*rayn_x + q2[1]*rayn_y; - float rod = orig[0]*rayn_x + orig[1]*rayn_y; - - float q10d = q1d - q0d; - float q20d = q2d - q0d; - float q0rd = q0d - rod; - - hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; - hits[0][1] = a*s0+b; - - if (num_s > 1) { - hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; - hits[1][1] = a*s1+b; - return 2; - } else { - return 1; + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) + s0 = s1; + ++num_s; } - } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0] * ray[0] + ray[1] * ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0] * rayn_x + q0[1] * rayn_y; + float q1d = q1[0] * rayn_x + q1[1] * rayn_y; + float q2d = q2[0] * rayn_x + q2[1] * rayn_y; + float rod = orig[0] * rayn_x + orig[1] * rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0 * (2.0f - 2.0f * s0) * q10d + s0 * s0 * q20d; + hits[0][1] = a * s0 + b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1 * (2.0f - 2.0f * s1) * q10d + s1 * s1 * q20d; + hits[1][1] = a * s1 + b; + return 2; + } else { + return 1; + } + } } -static int equal(float *a, float *b) -{ - return (a[0] == b[0] && a[1] == b[1]); -} +static int equal(float *a, float *b) { return (a[0] == b[0] && a[1] == b[1]); } -static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) -{ - int i; - float orig[2], ray[2] = { 1, 0 }; - float y_frac; - int winding = 0; +static int stbtt__compute_crossings_x(float x, float y, int nverts, + stbtt_vertex *verts) { + int i; + float orig[2], ray[2] = {1, 0}; + float y_frac; + int winding = 0; - // make sure y never passes through a vertex of the shape - y_frac = (float) STBTT_fmod(y, 1.0f); - if (y_frac < 0.01f) - y += 0.01f; - else if (y_frac > 0.99f) - y -= 0.01f; + // make sure y never passes through a vertex of the shape + y_frac = (float)STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; - orig[0] = x; - orig[1] = y; + orig[0] = x; + orig[1] = y; - // test a ray from (-infinity,y) to (x,y) - for (i=0; i < nverts; ++i) { - if (verts[i].type == STBTT_vline) { - int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; - int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + // test a ray from (-infinity,y) to (x,y) + for (i = 0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int)verts[i - 1].x, y0 = (int)verts[i - 1].y; + int x1 = (int)verts[i].x, y1 = (int)verts[i].y; + if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && + x > STBTT_min(x0, x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1 - x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int)verts[i - 1].x, y0 = (int)verts[i - 1].y; + int x1 = (int)verts[i].cx, y1 = (int)verts[i].cy; + int x2 = (int)verts[i].x, y2 = (int)verts[i].y; + int ax = STBTT_min(x0, STBTT_min(x1, x2)), + ay = STBTT_min(y0, STBTT_min(y1, y2)); + int by = STBTT_max(y0, STBTT_max(y1, y2)); + if (y > ay && y < by && x > ax) { + float q0[2], q1[2], q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0, q1) || equal(q1, q2)) { + x0 = (int)verts[i - 1].x; + y0 = (int)verts[i - 1].y; + x1 = (int)verts[i].x; + y1 = (int)verts[i].y; + if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && + x > STBTT_min(x0, x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1 - x0) + x0; if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = + stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } } - if (verts[i].type == STBTT_vcurve) { - int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; - int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; - int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; - int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); - int by = STBTT_max(y0,STBTT_max(y1,y2)); - if (y > ay && y < by && x > ax) { - float q0[2],q1[2],q2[2]; - float hits[2][2]; - q0[0] = (float)x0; - q0[1] = (float)y0; - q1[0] = (float)x1; - q1[1] = (float)y1; - q2[0] = (float)x2; - q2[1] = (float)y2; - if (equal(q0,q1) || equal(q1,q2)) { - x0 = (int)verts[i-1].x; - y0 = (int)verts[i-1].y; - x1 = (int)verts[i ].x; - y1 = (int)verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } else { - int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); - if (num_hits >= 1) - if (hits[0][0] < 0) - winding += (hits[0][1] < 0 ? -1 : 1); - if (num_hits >= 2) - if (hits[1][0] < 0) - winding += (hits[1][1] < 0 ? -1 : 1); - } - } - } - } - return winding; + } + } + return winding; } -static float stbtt__cuberoot( float x ) -{ - if (x<0) - return -(float) STBTT_pow(-x,1.0f/3.0f); - else - return (float) STBTT_pow( x,1.0f/3.0f); +static float stbtt__cuberoot(float x) { + if (x < 0) + return -(float)STBTT_pow(-x, 1.0f / 3.0f); + else + return (float)STBTT_pow(x, 1.0f / 3.0f); } // x^3 + a*x^2 + b*x + c = 0 -static int stbtt__solve_cubic(float a, float b, float c, float* r) -{ - float s = -a / 3; - float p = b - a*a / 3; - float q = a * (2*a*a - 9*b) / 27 + c; - float p3 = p*p*p; - float d = q*q + 4*p3 / 27; - if (d >= 0) { - float z = (float) STBTT_sqrt(d); - float u = (-q + z) / 2; - float v = (-q - z) / 2; - u = stbtt__cuberoot(u); - v = stbtt__cuberoot(v); - r[0] = s + u + v; - return 1; - } else { - float u = (float) STBTT_sqrt(-p/3); - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative - float m = (float) STBTT_cos(v); - float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; - r[0] = s + u * 2 * m; - r[1] = s - u * (m + n); - r[2] = s - u * (m - n); +static int stbtt__solve_cubic(float a, float b, float c, float *r) { + float s = -a / 3; + float p = b - a * a / 3; + float q = a * (2 * a * a - 9 * b) / 27 + c; + float p3 = p * p * p; + float d = q * q + 4 * p3 / 27; + if (d >= 0) { + float z = (float)STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float)STBTT_sqrt(-p / 3); + float v = (float)STBTT_acos(-STBTT_sqrt(-27 / p3) * q / 2) / + 3; // p3 must be negative, since d is negative + float m = (float)STBTT_cos(v); + float n = (float)STBTT_cos(v - 3.141592 / 2) * 1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); - //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? - //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); - //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); - return 3; - } + // STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these + // asserts may not be safe at all scales, though they're in bezier t + // parameter units so maybe? STBTT_assert( + // STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); STBTT_assert( + // STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } } -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - float scale_x = scale, scale_y = scale; - int ix0,iy0,ix1,iy1; - int w,h; - unsigned char *data; +STBTT_DEF unsigned char *stbtt_GetGlyphSDF(const stbtt_fontinfo *info, + float scale, int glyph, int padding, + unsigned char onedge_value, + float pixel_dist_scale, int *width, + int *height, int *xoff, int *yoff) { + float scale_x = scale, scale_y = scale; + int ix0, iy0, ix1, iy1; + int w, h; + unsigned char *data; - if (scale == 0) return NULL; + if (scale == 0) + return NULL; - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f, 0.0f, &ix0, + &iy0, &ix1, &iy1); - // if empty, return NULL - if (ix0 == ix1 || iy0 == iy1) - return NULL; + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; - ix0 -= padding; - iy0 -= padding; - ix1 += padding; - iy1 += padding; + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; - w = (ix1 - ix0); - h = (iy1 - iy0); + w = (ix1 - ix0); + h = (iy1 - iy0); - if (width ) *width = w; - if (height) *height = h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; + if (width) + *width = w; + if (height) + *height = h; + if (xoff) + *xoff = ix0; + if (yoff) + *yoff = iy0; - // invert for y-downwards bitmaps - scale_y = -scale_y; + // invert for y-downwards bitmaps + scale_y = -scale_y; - { - int x,y,i,j; - float *precompute; - stbtt_vertex *verts; - int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); - data = (unsigned char *) STBTT_malloc(w * h, info->userdata); - precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + { + int x, y, i, j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *)STBTT_malloc(w * h, info->userdata); + precompute = + (float *)STBTT_malloc(num_verts * sizeof(float), info->userdata); - for (i=0,j=num_verts-1; i < num_verts; j=i++) { - if (verts[i].type == STBTT_vline) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; - float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); - precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; - float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; - float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float len2 = bx*bx + by*by; - if (len2 != 0.0f) - precompute[i] = 1.0f / (bx*bx + by*by); - else - precompute[i] = 0.0f; - } else - precompute[i] = 0.0f; - } + for (i = 0, j = num_verts - 1; i < num_verts; j = i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x * scale_x, y0 = verts[i].y * scale_y; + float x1 = verts[j].x * scale_x, y1 = verts[j].y * scale_y; + float dist = + (float)STBTT_sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x * scale_x, y2 = verts[j].y * scale_y; + float x1 = verts[i].cx * scale_x, y1 = verts[i].cy * scale_y; + float x0 = verts[i].x * scale_x, y0 = verts[i].y * scale_y; + float bx = x0 - 2 * x1 + x2, by = y0 - 2 * y1 + y2; + float len2 = bx * bx + by * by; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx * bx + by * by); + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } - for (y=iy0; y < iy1; ++y) { - for (x=ix0; x < ix1; ++x) { - float val; - float min_dist = 999999.0f; - float sx = (float) x + 0.5f; - float sy = (float) y + 0.5f; - float x_gspace = (sx / scale_x); - float y_gspace = (sy / scale_y); + for (y = iy0; y < iy1; ++y) { + for (x = ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float)x + 0.5f; + float sy = (float)y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); - int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + int winding = stbtt__compute_crossings_x( + x_gspace, y_gspace, num_verts, + verts); // @OPTIMIZE: this could just be a rasterization, but needs + // to be line vs. non-tesselated curves so a new path - for (i=0; i < num_verts; ++i) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + for (i = 0; i < num_verts; ++i) { + float x0 = verts[i].x * scale_x, y0 = verts[i].y * scale_y; - if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { - float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { + float x1 = verts[i - 1].x * scale_x, y1 = verts[i - 1].y * scale_y; - float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); + float dist, dist2 = (x0 - sx) * (x0 - sx) + (y0 - sy) * (y0 - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); - // coarse culling against bbox - //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && - // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) - dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; - STBTT_assert(i != 0); - if (dist < min_dist) { - // check position along line - // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) - // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) - float dx = x1-x0, dy = y1-y0; - float px = x0-sx, py = y0-sy; - // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy - // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve - float t = -(px*dx + py*dy) / (dx*dx + dy*dy); - if (t >= 0.0f && t <= 1.0f) - min_dist = dist; - } - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; - float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; - float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); - float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); - float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); - float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); - // coarse culling against bbox to avoid computing cubic unnecessarily - if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { - int num=0; - float ax = x1-x0, ay = y1-y0; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float mx = x0 - sx, my = y0 - sy; - float res[3] = {0.f,0.f,0.f}; - float px,py,t,it,dist2; - float a_inv = precompute[i]; - if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula - float a = 3*(ax*bx + ay*by); - float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); - float c = mx*ax+my*ay; - if (a == 0.0) { // if a is 0, it's linear - if (b != 0.0) { - res[num++] = -c/b; - } - } else { - float discriminant = b*b - 4*a*c; - if (discriminant < 0) - num = 0; - else { - float root = (float) STBTT_sqrt(discriminant); - res[0] = (-b - root)/(2*a); - res[1] = (-b + root)/(2*a); - num = 2; // don't bother distinguishing 1-solution case, as code below will still work - } - } - } else { - float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point - float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; - float d = (mx*ax+my*ay) * a_inv; - num = stbtt__solve_cubic(b, c, d, res); - } - dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { - t = res[0], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { - t = res[1], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { - t = res[2], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - } - } + // coarse culling against bbox + // if (sx > STBTT_min(x0,x1)-min_dist && sx < + // STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < + // STBTT_max(y0,y1)+min_dist) + dist = (float)STBTT_fabs((x1 - x0) * (y0 - sy) - + (y1 - y0) * (x0 - sx)) * + precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1 - x0, dy = y1 - y0; + float px = x0 - sx, py = y0 - sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + + // t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy derivative: 2*px*dx + + // 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px * dx + py * dy) / (dx * dx + dy * dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; } - if (winding == 0) - min_dist = -min_dist; // if outside the shape, value is negative - val = onedge_value + pixel_dist_scale * min_dist; - if (val < 0) - val = 0; - else if (val > 255) - val = 255; - data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; - } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i - 1].x * scale_x, y2 = verts[i - 1].y * scale_y; + float x1 = verts[i].cx * scale_x, y1 = verts[i].cy * scale_y; + float box_x0 = STBTT_min(STBTT_min(x0, x1), x2); + float box_y0 = STBTT_min(STBTT_min(y0, y1), y2); + float box_x1 = STBTT_max(STBTT_max(x0, x1), x2); + float box_y1 = STBTT_max(STBTT_max(y0, y1), y2); + // coarse culling against bbox to avoid computing cubic + // unnecessarily + if (sx > box_x0 - min_dist && sx < box_x1 + min_dist && + sy > box_y0 - min_dist && sy < box_y1 + min_dist) { + int num = 0; + float ax = x1 - x0, ay = y1 - y0; + float bx = x0 - 2 * x1 + x2, by = y0 - 2 * y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3] = {0.f, 0.f, 0.f}; + float px, py, t, it, dist2; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use + // quadratic formula + float a = 3 * (ax * bx + ay * by); + float b = 2 * (ax * ax + ay * ay) + (mx * bx + my * by); + float c = mx * ax + my * ay; + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { + res[num++] = -c / b; + } + } else { + float discriminant = b * b - 4 * a * c; + if (discriminant < 0) + num = 0; + else { + float root = (float)STBTT_sqrt(discriminant); + res[0] = (-b - root) / (2 * a); + res[1] = (-b + root) / (2 * a); + num = 2; // don't bother distinguishing 1-solution case, as + // code below will still work + } + } + } else { + float b = 3 * (ax * bx + ay * by) * + a_inv; // could precompute this as it doesn't depend + // on sample point + float c = + (2 * (ax * ax + ay * ay) + (mx * bx + my * by)) * a_inv; + float d = (mx * ax + my * ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + dist2 = (x0 - sx) * (x0 - sx) + (y0 - sy) * (y0 - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it * it * x0 + 2 * t * it * x1 + t * t * x2; + py = it * it * y0 + 2 * t * it * y1 + t * t * y2; + dist2 = (px - sx) * (px - sx) + (py - sy) * (py - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it * it * x0 + 2 * t * it * x1 + t * t * x2; + py = it * it * y0 + 2 * t * it * y1 + t * t * y2; + dist2 = (px - sx) * (px - sx) + (py - sy) * (py - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it * it * x0 + 2 * t * it * x1 + t * t * x2; + py = it * it * y0 + 2 * t * it * y1 + t * t * y2; + dist2 = (px - sx) * (px - sx) + (py - sy) * (py - sy); + if (dist2 < min_dist * min_dist) + min_dist = (float)STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y - iy0) * w + (x - ix0)] = (unsigned char)val; } - STBTT_free(precompute, info->userdata); - STBTT_free(verts, info->userdata); - } - return data; + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; } -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +STBTT_DEF unsigned char * +stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, + int padding, unsigned char onedge_value, + float pixel_dist_scale, int *width, int *height, + int *xoff, int *yoff) { + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), + padding, onedge_value, pixel_dist_scale, width, + height, xoff, yoff); } -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) { + STBTT_free(bitmap, userdata); } ////////////////////////////////////////////////////////////////////////////// @@ -4772,159 +5281,205 @@ STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) // font name matching -- recommended not to use this // -// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) -{ - stbtt_int32 i=0; +// check if a utf8 string contains a prefix which is the utf16 string; if so +// return length of matching utf8 string +static stbtt_int32 +stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, + stbtt_uint8 *s2, stbtt_int32 len2) { + stbtt_int32 i = 0; - // convert utf16 to utf8 and compare the results while converting - while (len2) { - stbtt_uint16 ch = s2[0]*256 + s2[1]; - if (ch < 0x80) { - if (i >= len1) return -1; - if (s1[i++] != ch) return -1; - } else if (ch < 0x800) { - if (i+1 >= len1) return -1; - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; - } else if (ch >= 0xd800 && ch < 0xdc00) { - stbtt_uint32 c; - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; - if (i+3 >= len1) return -1; - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; - if (s1[i++] != 0xf0 + (c >> 18)) return -1; - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; - s2 += 2; // plus another 2 below - len2 -= 2; - } else if (ch >= 0xdc00 && ch < 0xe000) { - return -1; - } else { - if (i+2 >= len1) return -1; - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; - } - s2 += 2; + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0] * 256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) + return -1; + if (s1[i++] != ch) + return -1; + } else if (ch < 0x800) { + if (i + 1 >= len1) + return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) + return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) + return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2] * 256 + s2[3]; + if (i + 3 >= len1) + return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) + return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) + return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) + return -1; + if (s1[i++] != 0x80 + ((c)&0x3f)) + return -1; + s2 += 2; // plus another 2 below len2 -= 2; - } - return i; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i + 2 >= len1) + return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) + return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) + return -1; + if (s1[i++] != 0x80 + ((ch)&0x3f)) + return -1; + } + s2 += 2; + len2 -= 2; + } + return i; } -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) -{ - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, + char *s2, int len2) { + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix( + (stbtt_uint8 *)s1, len1, (stbtt_uint8 *)s2, len2); } -// returns results in whatever encoding you request... but note that 2-byte encodings -// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) -{ - stbtt_int32 i,count,stringOffset; - stbtt_uint8 *fc = font->data; - stbtt_uint32 offset = font->fontstart; - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return NULL; +// returns results in whatever encoding you request... but note that 2-byte +// encodings will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to +// compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, + int *length, int platformID, + int encodingID, int languageID, + int nameID) { + stbtt_int32 i, count, stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) + return NULL; - count = ttUSHORT(fc+nm+2); - stringOffset = nm + ttUSHORT(fc+nm+4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { - *length = ttUSHORT(fc+loc+8); - return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); - } - } - return NULL; + count = ttUSHORT(fc + nm + 2); + stringOffset = nm + ttUSHORT(fc + nm + 4); + for (i = 0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc + loc + 0) && + encodingID == ttUSHORT(fc + loc + 2) && + languageID == ttUSHORT(fc + loc + 4) && + nameID == ttUSHORT(fc + loc + 6)) { + *length = ttUSHORT(fc + loc + 8); + return (const char *)(fc + stringOffset + ttUSHORT(fc + loc + 10)); + } + } + return NULL; } -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) -{ - stbtt_int32 i; - stbtt_int32 count = ttUSHORT(fc+nm+2); - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, + stbtt_int32 nlen, stbtt_int32 target_id, + stbtt_int32 next_id) { + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc + nm + 2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc + nm + 4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - stbtt_int32 id = ttUSHORT(fc+loc+6); - if (id == target_id) { - // find the encoding - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + for (i = 0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc + loc + 6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc + loc + 0), + encoding = ttUSHORT(fc + loc + 2), + language = ttUSHORT(fc + loc + 4); - // is this a Unicode encoding? - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { - stbtt_int32 slen = ttUSHORT(fc+loc+8); - stbtt_int32 off = ttUSHORT(fc+loc+10); + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || + (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc + loc + 8); + stbtt_int32 off = ttUSHORT(fc + loc + 10); - // check if there's a prefix match - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); - if (matchlen >= 0) { - // check for target_id+1 immediately following, with same encoding & language - if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { - slen = ttUSHORT(fc+loc+12+8); - off = ttUSHORT(fc+loc+12+10); - if (slen == 0) { - if (matchlen == nlen) - return 1; - } else if (matchlen < nlen && name[matchlen] == ' ') { - ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) - return 1; - } - } else { - // if nothing immediately following - if (matchlen == nlen) - return 1; - } + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix( + name, nlen, fc + stringOffset + off, slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & + // language + if (i + 1 < count && ttUSHORT(fc + loc + 12 + 6) == next_id && + ttUSHORT(fc + loc + 12) == platform && + ttUSHORT(fc + loc + 12 + 2) == encoding && + ttUSHORT(fc + loc + 12 + 4) == language) { + slen = ttUSHORT(fc + loc + 12 + 8); + off = ttUSHORT(fc + loc + 12 + 10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal( + (char *)(name + matchlen), nlen - matchlen, + (char *)(fc + stringOffset + off), slen)) + return 1; } - } - - // @TODO handle other encodings + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } } - } - return 0; + + // @TODO handle other encodings + } + } + return 0; } -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) -{ - stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); - stbtt_uint32 nm,hd; - if (!stbtt__isfont(fc+offset)) return 0; +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, + stbtt_uint8 *name, stbtt_int32 flags) { + stbtt_int32 nlen = (stbtt_int32)STBTT_strlen((char *)name); + stbtt_uint32 nm, hd; + if (!stbtt__isfont(fc + offset)) + return 0; - // check italics/bold/underline flags in macStyle... - if (flags) { - hd = stbtt__find_table(fc, offset, "head"); - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; - } + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc + hd + 44) & 7) != (flags & 7)) + return 0; + } - nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return 0; + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) + return 0; - if (flags) { - // if we checked the macStyle flags, then just check the family and ignore the subfamily - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } else { - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore + // the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) + return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) + return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) + return 1; + } - return 0; + return 0; } -static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) -{ - stbtt_int32 i; - for (i=0;;++i) { - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); - if (off < 0) return off; - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) - return off; - } +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, + char *name_utf8, stbtt_int32 flags) { + stbtt_int32 i; + for (i = 0;; ++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) + return off; + if (stbtt__matches((stbtt_uint8 *)font_collection, off, + (stbtt_uint8 *)name_utf8, flags)) + return off; + } } #if defined(__GNUC__) || defined(__clang__) @@ -4933,35 +5488,38 @@ static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char #endif STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, - float pixel_height, unsigned char *pixels, int pw, int ph, - int first_char, int num_chars, stbtt_bakedchar *chardata) -{ - return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); + float pixel_height, unsigned char *pixels, + int pw, int ph, int first_char, + int num_chars, stbtt_bakedchar *chardata) { + return stbtt_BakeFontBitmap_internal((unsigned char *)data, offset, + pixel_height, pixels, pw, ph, first_char, + num_chars, chardata); } -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) -{ - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, + int index) { + return stbtt_GetFontOffsetForIndex_internal((unsigned char *)data, index); } -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) -{ - return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) { + return stbtt_GetNumberOfFonts_internal((unsigned char *)data); } -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) -{ - return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, + int offset) { + return stbtt_InitFont_internal(info, (unsigned char *)data, offset); } -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) -{ - return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, + const char *name, int flags) { + return stbtt_FindMatchingFont_internal((unsigned char *)fontdata, + (char *)name, flags); } -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{ - return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, + const char *s2, int len2) { + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *)s1, len1, + (char *)s2, len2); } #if defined(__GNUC__) || defined(__clang__) @@ -4970,42 +5528,43 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const #endif // STB_TRUETYPE_IMPLEMENTATION - // FULL VERSION HISTORY // // 1.25 (2021-07-11) many fixes // 1.24 (2020-02-05) fix warning -// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) -// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined -// 1.21 (2019-02-25) fix warning -// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() -// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod -// 1.18 (2018-01-29) add missing function -// 1.17 (2017-07-23) make more arguments const; doc fix -// 1.16 (2017-07-12) SDF support -// 1.15 (2017-03-03) make more arguments const -// 1.14 (2017-01-16) num-fonts-in-TTC function -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but +// only kern not GPOS) 1.22 (2019-08-11) minimize missing-glyph duplication; +// fix kerning if both 'GPOS' and 'kern' are defined 1.21 (2019-02-25) fix +// warning 1.20 (2019-02-07) PackFontRange skips missing codepoints; +// GetScaleFontVMetrics() 1.19 (2018-02-11) OpenType GPOS kerning (horizontal +// only), STBTT_fmod 1.18 (2018-01-29) add missing function 1.17 (2017-07-23) +// make more arguments const; doc fix 1.16 (2017-07-12) SDF support 1.15 +// (2017-03-03) make more arguments const 1.14 (2017-01-16) num-fonts-in-TTC +// function 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts 1.12 +// (2016-10-25) suppress warnings about casting away const with -Wcast-qual // 1.11 (2016-04-02) fix unused-variable warning // 1.10 (2016-04-02) allow user-defined fabs() replacement // fix memory leak if fontsize=0.0 // fix warning from duplicate typedef -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; -// allow PackFontRanges to pack and render in separate phases; -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); -// fixed an assert() bug in the new rasterizer -// replace assert() with STBTT_assert() in new rasterizer -// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata +// for PackFontRanges 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for +// vertical & horizontal edges 1.07 (2015-08-01) allow PackFontRanges to +// accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate +// phases; fix stbtt_GetFontOFfsetForIndex (never worked for +// non-0 input?); fixed an assert() bug in the new +// rasterizer replace assert() with STBTT_assert() in new +// rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on +// test machine) // also more precise AA rasterizer, except if shapes overlap // remove need for STBTT_sort // 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC // 1.04 (2015-04-15) typo in example -// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes -// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ -// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various +// fixes 1.02 (2014-12-10) fix various warnings & compile issues w/ +// stb_rect_pack, C++ 1.01 (2014-12-08) fix subpixel position when +// oversampling to exactly match // non-oversampled; STBTT_POINT_SIZE for packed case only // 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) diff --git a/source/Color.cpp b/source/Color.cpp index 7d9299f..ce10739 100644 --- a/source/Color.cpp +++ b/source/Color.cpp @@ -1,18 +1,40 @@ #include +#include #define RGBA8(r, g, b, a) \ ((((r)&0xFF) << 0) | (((g)&0xFF) << 8) | (((b)&0xFF) << 16) | \ (((a)&0xFF) << 24)) -uint32_t RenderD7::Color::Hex(const std::string color, uint8_t a) { +// uint32_t RenderD7::Color::Hex(const std::string &color, uint8_t a) { +// if (color.length() < 7 || +// std::regex_search(color.substr(1), +// std::regex("[^0-9A-Fa-f]"))) { // invalid color. +// return RenderD7::Color::Hex("#000000", 0); +// } +// int r = std::stoi(color.substr(1, 2), nullptr, 16); +// int g = std::stoi(color.substr(3, 2), nullptr, 16); +// int b = std::stoi(color.substr(5, 2), nullptr, 16); +// return RGBA8(r, g, b, a); +// } + +// Lookup-Table für Hex-to-Dez-Konvertierung +static const std::map HEX_TO_DEC = { + {'0', 0}, {'1', 1}, {'2', 2}, {'3', 3}, {'4', 4}, {'5', 5}, + {'6', 6}, {'7', 7}, {'8', 8}, {'9', 9}, {'a', 10}, {'b', 11}, + {'c', 12}, {'d', 13}, {'e', 14}, {'f', 15}, {'A', 10}, {'B', 11}, + {'C', 12}, {'D', 13}, {'E', 14}, {'F', 15}}; + +uint32_t RenderD7::Color::Hex(const std::string &color, uint8_t a) { if (color.length() < 7 || - std::regex_search(color.substr(1), - std::regex("[^0-9A-Fa-f]"))) { // invalid color. + std::find_if(color.begin() + 1, color.end(), + [](char c) { return !std::isxdigit(c); }) != color.end()) { return RenderD7::Color::Hex("#000000", 0); } - int r = std::stoi(color.substr(1, 2), nullptr, 16); - int g = std::stoi(color.substr(3, 2), nullptr, 16); - int b = std::stoi(color.substr(5, 2), nullptr, 16); + + int r = HEX_TO_DEC.at(color[1]) * 16 + HEX_TO_DEC.at(color[2]); + int g = HEX_TO_DEC.at(color[3]) * 16 + HEX_TO_DEC.at(color[4]); + int b = HEX_TO_DEC.at(color[5]) * 16 + HEX_TO_DEC.at(color[6]); + return RGBA8(r, g, b, a); } diff --git a/source/FileSystem.cpp b/source/FileSystem.cpp index 63dbc87..bc4db98 100644 --- a/source/FileSystem.cpp +++ b/source/FileSystem.cpp @@ -9,12 +9,13 @@ #include -std::vector RenderD7::FileSystem::GetDirContent(std::string path) -{ +std::vector +RenderD7::FileSystem::GetDirContent(std::string path) { std::vector res; - for(const auto& entry : std::filesystem::directory_iterator(std::filesystem::path(path))) - { - res.push_back({entry.path().string(), GetFileName(entry.path().string()), entry.is_directory()}); + for (const auto &entry : + std::filesystem::directory_iterator(std::filesystem::path(path))) { + res.push_back({entry.path().string(), GetFileName(entry.path().string()), + entry.is_directory()}); } return res; } \ No newline at end of file diff --git a/source/Image.cpp b/source/Image.cpp index 7aa3312..a1b589a 100644 --- a/source/Image.cpp +++ b/source/Image.cpp @@ -77,76 +77,82 @@ static bool C3DTexToC2DImage(C2D_Image *texture, u32 width, u32 height, return false; } -static void OLD_C3DTexToC2DImage(C3D_Tex *tex, Tex3DS_SubTexture *subtex, u8 *buf, u32 size, u32 width, u32 height, GPU_TEXCOLOR format) { - // RGBA -> ABGR - for (u32 row = 0; row < width; row++) { - for (u32 col = 0; col < height; col++) { - u32 z = (row + col * width) * 4; +static void OLD_C3DTexToC2DImage(C3D_Tex *tex, Tex3DS_SubTexture *subtex, + u8 *buf, u32 size, u32 width, u32 height, + GPU_TEXCOLOR format) { + // RGBA -> ABGR + for (u32 row = 0; row < width; row++) { + for (u32 col = 0; col < height; col++) { + u32 z = (row + col * width) * 4; - u8 r = *(u8 *)(buf + z); - u8 g = *(u8 *)(buf + z + 1); - u8 b = *(u8 *)(buf + z + 2); - u8 a = *(u8 *)(buf + z + 3); + u8 r = *(u8 *)(buf + z); + u8 g = *(u8 *)(buf + z + 1); + u8 b = *(u8 *)(buf + z + 2); + u8 a = *(u8 *)(buf + z + 3); - *(buf + z) = a; - *(buf + z + 1) = b; - *(buf + z + 2) = g; - *(buf + z + 3) = r; - } - } + *(buf + z) = a; + *(buf + z + 1) = b; + *(buf + z + 2) = g; + *(buf + z + 3) = r; + } + } - u32 w_pow2 = GetNextPowerOf2(width); - u32 h_pow2 = GetNextPowerOf2(height); + u32 w_pow2 = GetNextPowerOf2(width); + u32 h_pow2 = GetNextPowerOf2(height); - subtex->width = (u16)width; - subtex->height = (u16)height; - subtex->left = 0.0f; - subtex->top = 1.0f; - subtex->right = (width / (float)w_pow2); - subtex->bottom = 1.0 - (height / (float)h_pow2); + subtex->width = (u16)width; + subtex->height = (u16)height; + subtex->left = 0.0f; + subtex->top = 1.0f; + subtex->right = (width / (float)w_pow2); + subtex->bottom = 1.0 - (height / (float)h_pow2); - C3D_TexInit(tex, (u16)w_pow2, (u16)h_pow2, format); - C3D_TexSetFilter(tex, GPU_NEAREST, GPU_NEAREST); + C3D_TexInit(tex, (u16)w_pow2, (u16)h_pow2, format); + C3D_TexSetFilter(tex, GPU_NEAREST, GPU_NEAREST); - u32 pixel_size = (size / width / height); + u32 pixel_size = (size / width / height); - memset(tex->data, 0, tex->size); + memset(tex->data, 0, tex->size); - for (u32 x = 0; x < width; x++) { - for (u32 y = 0; y < height; y++) { - u32 dst_pos = ((((y >> 3) * (w_pow2 >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))) * pixel_size; - u32 src_pos = (y * width + x) * pixel_size; + for (u32 x = 0; x < width; x++) { + for (u32 y = 0; y < height; y++) { + u32 dst_pos = ((((y >> 3) * (w_pow2 >> 3) + (x >> 3)) << 6) + + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | + ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))) * + pixel_size; + u32 src_pos = (y * width + x) * pixel_size; - memcpy(&((u8*)tex->data)[dst_pos], &((u8*)buf)[src_pos], pixel_size); - } - } + memcpy(&((u8 *)tex->data)[dst_pos], &((u8 *)buf)[src_pos], pixel_size); + } + } - C3D_TexFlush(tex); + C3D_TexFlush(tex); - tex->border = 0x00000000; - C3D_TexSetWrap(tex, GPU_CLAMP_TO_BORDER, GPU_CLAMP_TO_BORDER); - linearFree(buf); + tex->border = 0x00000000; + C3D_TexSetWrap(tex, GPU_CLAMP_TO_BORDER, GPU_CLAMP_TO_BORDER); + linearFree(buf); } bool IMG_LoadImageFile(C2D_Image *texture, const char *path) { - stbi_uc *image = NULL; - int width = 0, height = 0; + stbi_uc *image = NULL; + int width = 0, height = 0; int nc; - image = stbi_load(path, &width, &height, &nc, 4); + image = stbi_load(path, &width, &height, &nc, 4); - if (width > 1024 || height > 1024) { - stbi_image_free(image); - return false; - } + if (width > 1024 || height > 1024) { + stbi_image_free(image); + return false; + } - C3D_Tex *tex = new C3D_Tex; - Tex3DS_SubTexture *subtex = new Tex3DS_SubTexture; - OLD_C3DTexToC2DImage(tex, subtex, image, (u32)(width * height * 4), (u32)width, (u32)height, GPU_RGBA8); - texture->tex = tex; - texture->subtex = subtex; - stbi_image_free(image); - return true; + C3D_Tex *tex = new C3D_Tex; + Tex3DS_SubTexture *subtex = new Tex3DS_SubTexture; + OLD_C3DTexToC2DImage(tex, subtex, image, (u32)(width * height * 4), + (u32)width, (u32)height, GPU_RGBA8); + texture->tex = tex; + texture->subtex = subtex; + stbi_image_free(image); + return true; } extern "C" { diff --git a/source/ResultDecoder.cpp b/source/ResultDecoder.cpp index bb8a06b..58607d2 100644 --- a/source/ResultDecoder.cpp +++ b/source/ResultDecoder.cpp @@ -162,7 +162,7 @@ static std::map descos = { {47, "Invalid command header."}, }; -//Need to Fix The Range based Values +// Need to Fix The Range based Values static std::map descfs = { {101, "Archive not mounted or mount-point not found."}, {120, "Title or object not found."}, @@ -262,9 +262,9 @@ static std::map descmvd = { static std::map descqtm = { {8, "Camera is already in use or busy."}, -}; +}; -//Need to Fix The Range based Values +// Need to Fix The Range based Values static std::map descapplication = { {0, "The application raised an error. Please consult the application's " "source code or ask the author for assistance with it."}, diff --git a/source/renderd7.cpp b/source/renderd7.cpp index f3082d8..55b4bc0 100644 --- a/source/renderd7.cpp +++ b/source/renderd7.cpp @@ -432,7 +432,7 @@ Result RenderD7::Init::Main(std::string app_name) { cfgfile = std::make_unique(cfgpath + "/config.ini"); cfgfile->read(cfgstruct); std::string Fps = cfgstruct["settings"]["forceFrameRate"]; - C3D_FrameRate(RenderD7::Convert::StringtoFloat(Fps)); + ////C3D_FrameRate(RenderD7::Convert::StringtoFloat(Fps)); metrikd = RenderD7::Convert::FloatToBool(RenderD7::Convert::StringtoFloat( cfgstruct["metrik-settings"]["enableoverlay"])); mt_txtcolor = @@ -547,7 +547,7 @@ Result RenderD7::Init::Minimal(std::string app_name) { cfgfile = std::make_unique(cfgpath + "/config.ini"); cfgfile->read(cfgstruct); std::string Fps = cfgstruct["settings"]["forceFrameRate"]; - C3D_FrameRate(RenderD7::Convert::StringtoFloat(Fps)); + //C3D_FrameRate(RenderD7::Convert::StringtoFloat(Fps)); metrikd = RenderD7::Convert::FloatToBool(RenderD7::Convert::StringtoFloat( cfgstruct["metrik-settings"]["enableoverlay"])); mt_txtcolor = @@ -1020,9 +1020,8 @@ void RenderD7::RSettings::Draw(void) const { RenderD7::OnScreen(Top); RenderD7::Draw::Rect(0, 21, 400, 220, RenderD7::Color::Hex("#eeeeee")); - RenderD7::Draw::Text(5, 30, 0.7f, DSEVENBLACK, - std::string(CHANGELOG)); - + RenderD7::Draw::Text(5, 30, 0.7f, DSEVENBLACK, std::string(CHANGELOG)); + RenderD7::Draw::Rect(0, 0, 400, 21, RenderD7::Color::Hex("#111111")); RenderD7::Draw::Text(0, 0, 0.7f, DSEVENWHITE, "RenderD7->Changelog"); RenderD7::Draw::TextRight(400, 0, 0.7f, RenderD7::Color::Hex("#ffffff"), @@ -1030,7 +1029,8 @@ void RenderD7::RSettings::Draw(void) const { RenderD7::OnScreen(Bottom); RenderD7::Draw::Rect(0, 0, 320, 240, RenderD7::Color::Hex("#eeeeee")); RenderD7::Draw::Text(0, 0, 0.7f, RenderD7::Color::Hex("#111111"), - "Press B to Get back!\ntxty: " + std::to_string(txtposy)); + "Press B to Get back!\ntxty: " + + std::to_string(txtposy)); } else if (m_state == RINFO) { std::string rd7ver = RENDERD7VSTRING; @@ -1103,8 +1103,8 @@ void RenderD7::RSettings::Logic(u32 hDown, u32 hHeld, u32 hUp, if (d7_hDown & KEY_TOUCH && RenderD7::touchTObj(d7_touch, buttons[3]) && !metrikd) { cfgstruct["settings"]["forceFrameRate"] = Kbd(2, SWKBD_TYPE_NUMPAD); - C3D_FrameRate(RenderD7::Convert::StringtoFloat( - cfgstruct["settings"]["forceFrameRate"])); + //C3D_FrameRate(RenderD7::Convert::StringtoFloat( + //cfgstruct["settings"]["forceFrameRate"])); } if (d7_hDown & KEY_TOUCH && RenderD7::touchTObj(d7_touch, buttons[4])) { mt_screen = mt_screen ? 0 : 1; diff --git a/tools/rd7cc/source/main.cpp b/tools/rd7cc/source/main.cpp index f09a9dc..84d0ec6 100644 --- a/tools/rd7cc/source/main.cpp +++ b/tools/rd7cc/source/main.cpp @@ -1,11 +1,10 @@ -//rd7cc -#include +// rd7cc #include -int main(int argc, char* argv[]) -{ - std::ofstream result ("result.hpp"); +#include +int main(int argc, char *argv[]) { + std::ofstream result("result.hpp"); - result << "//Result" << std::endl; + result << "//Result" << std::endl; - result.close(); + result.close(); }