diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10a3369..0d07f58 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,6 +68,7 @@ set(FPNG_SRC_LIST ${COMMON_SRC_LIST}
src/fpng.cpp
src/fpng_test.cpp
src/lodepng.cpp
+ src/pvpngreader.cpp
)
if (APPLE)
diff --git a/fpng.vcxproj b/fpng.vcxproj
index 8044e45..5b97797 100644
--- a/fpng.vcxproj
+++ b/fpng.vcxproj
@@ -147,6 +147,7 @@
+
@@ -154,6 +155,8 @@
+
+
diff --git a/fpng.vcxproj.filters b/fpng.vcxproj.filters
index 357fcd9..16620a6 100644
--- a/fpng.vcxproj.filters
+++ b/fpng.vcxproj.filters
@@ -24,6 +24,9 @@
Source Files
+
+ Source Files
+
@@ -41,5 +44,11 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
\ No newline at end of file
diff --git a/src/fpng_test.cpp b/src/fpng_test.cpp
index 7636daa..b0a25fb 100644
--- a/src/fpng_test.cpp
+++ b/src/fpng_test.cpp
@@ -27,6 +27,9 @@
#define WUFFS_CONFIG__STATIC_FUNCTIONS
#include "wuffs-v0.3.c"
+#include "basisu_miniz.h"
+#include "pvpngreader.h"
+
typedef std::vector uint8_vec;
typedef uint64_t timer_ticks;
@@ -1228,7 +1231,7 @@ int main(int arg_c, char **arg_v)
#endif
}
- double fpng_decode_time = 0.0f, lodepng_decode_time = 0.0f, stbi_decode_time = 0.0f, qoi_decode_time = 0.0f, wuffs_decode_time = 0.0f;
+ double fpng_decode_time = 0.0f, lodepng_decode_time = 0.0f, stbi_decode_time = 0.0f, qoi_decode_time = 0.0f, wuffs_decode_time = 0.0f, pvpng_decode_time = 0.0f;
// Decode the file using our decompressor
{
@@ -1542,21 +1545,65 @@ int main(int arg_c, char **arg_v)
// Validate QOI's output file
{
+ qoi_decode_time = 1e+9f;
+
qoi_desc qddesc;
- tm.start();
- void* pQOI_decomp_data = qoi_decode(pQOI_data, qoi_len, &qddesc, 4);
- qoi_decode_time = tm.get_elapsed_secs();
-
- if (memcmp(pQOI_decomp_data, pSource_pixels32, total_source_pixels * 4) != 0)
+ for (uint32_t i = 0; i < NUM_TIMES_TO_ENCODE; i++)
{
- fprintf(stderr, "QOI verification failure!\n");
- return EXIT_FAILURE;
+ tm.start();
+ void* pQOI_decomp_data = qoi_decode(pQOI_data, qoi_len, &qddesc, 4);
+
+ qoi_decode_time = minimum(qoi_decode_time, tm.get_elapsed_secs());
+
+ if (memcmp(pQOI_decomp_data, pSource_pixels32, total_source_pixels * 4) != 0)
+ {
+ fprintf(stderr, "QOI verification failure!\n");
+ return EXIT_FAILURE;
+ }
+
+ free(pQOI_decomp_data);
}
- free(pQOI_decomp_data);
}
free(pQOI_data);
pQOI_data = nullptr;
+
+ {
+ // Decode the PNG file using pvpng, which ships with BasisU and uses miniz for decompression.
+
+ pvpng_decode_time = 1e+9f;
+
+ for (uint32_t i = 0; i < NUM_TIMES_TO_ENCODE; i++)
+ {
+ uint32_t width = 0, height = 0, num_chans = 0;
+
+ tm.start();
+
+ void* pImage_data = pv_png::load_png(fpng_file_buf.data(), fpng_file_buf.size(), source_chans, width, height, num_chans);
+
+ pvpng_decode_time = minimum(pvpng_decode_time, tm.get_elapsed_secs());
+
+ if (!pImage_data)
+ {
+ fprintf(stderr, "Failed decoding using pvpng! (1)\n");
+ return EXIT_FAILURE;
+ }
+
+ if ((num_chans != source_chans) || (width != source_width) || (height != source_height))
+ {
+ fprintf(stderr, "Failed decoding using pvpng! (2)\n");
+ return EXIT_FAILURE;
+ }
+
+ if (memcmp((source_chans == 3) ? (const void*)pSource_pixels24 : (const void*)pSource_pixels32, pImage_data, width * height * source_chans) != 0)
+ {
+ fprintf(stderr, "Failed decoding using pvpng! (3)\n");
+ return EXIT_FAILURE;
+ }
+
+ free(pImage_data);
+ }
+ }
if (!csv_flag)
{
@@ -1565,6 +1612,7 @@ int main(int arg_c, char **arg_v)
printf("lodepng: %3.6f secs, %4.3f MP/sec\n", lodepng_decode_time, (total_source_pixels / (1024.0f * 1024.0f)) / lodepng_decode_time);
printf("stbi: %3.6f secs, %4.3f MP/sec\n", stbi_decode_time, (total_source_pixels / (1024.0f * 1024.0f)) / stbi_decode_time);
printf("wuffs: %3.6f secs, %4.3f MP/sec\n", wuffs_decode_time, (total_source_pixels / (1024.0f * 1024.0f)) / wuffs_decode_time);
+ printf("pvpng: %3.6f secs, %4.3f MP/sec\n", pvpng_decode_time, (total_source_pixels / (1024.0f * 1024.0f)) / pvpng_decode_time);
printf("qoi: %3.6f secs, %4.3f MP/sec\n", qoi_decode_time, (total_source_pixels / (1024.0f * 1024.0f)) / qoi_decode_time);
}
@@ -1574,12 +1622,13 @@ int main(int arg_c, char **arg_v)
const double source_megapixels = total_source_pixels / (1024.0f * 1024.0f);
- printf("%s, %u, %u, %u, %f, %f, %f, %4.1f, %4.1f, %f, %f, %f, %4.1f, %4.1f, %f, %f, %f, %4.1f, %4.1f, %f, %f, %f, %4.1f, %4.1f\n",
+ printf("%s, %u, %u, %u, %f, %f, %f, %4.3f, %4.3f, %f, %f, %f, %4.3f, %4.3f, %f, %f, %f, %4.3f, %4.3f, %f, %f, %f, %4.3f, %4.3f, %4.3f, %4.3f\n",
pFilename, source_width, source_height, source_chans,
qoi_best_time, (double)qoi_len / MB, qoi_decode_time, source_megapixels / qoi_best_time, source_megapixels / qoi_decode_time,
fpng_best_time, (double)fpng_file_buf.size() / MB, fpng_decode_time, source_megapixels / fpng_best_time, source_megapixels / fpng_decode_time,
lodepng_best_time, (double)lodepng_file_buf.size() / MB, lodepng_decode_time, source_megapixels / lodepng_best_time, source_megapixels / lodepng_decode_time,
- stbi_best_time, (double)stbi_file_buf.size() / MB, stbi_decode_time, source_megapixels / stbi_best_time, source_megapixels / stbi_decode_time
+ stbi_best_time, (double)stbi_file_buf.size() / MB, stbi_decode_time, source_megapixels / stbi_best_time, source_megapixels / stbi_decode_time,
+ pvpng_decode_time, source_megapixels / pvpng_decode_time
);
}
diff --git a/src/lodepng.cpp b/src/lodepng.cpp
index c6e7f38..6ab9694 100644
--- a/src/lodepng.cpp
+++ b/src/lodepng.cpp
@@ -1,7 +1,7 @@
/*
-LodePNG version 20210627
+LodePNG version 20230410
-Copyright (c) 2005-2021 Lode Vandevenne
+Copyright (c) 2005-2023 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -44,10 +44,10 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for
#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 = "20210627";
+const char* LODEPNG_VERSION_STRING = "20230410";
/*
-This source file is built up in the following large parts. The code sections
+This source file is divided into 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, ...)
@@ -140,7 +140,6 @@ static size_t lodepng_strlen(const char* a) {
#define LODEPNG_MAX(a, b) (((a) > (b)) ? (a) : (b))
#define LODEPNG_MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define LODEPNG_ABS(x) ((x) < 0 ? -(x) : (x))
#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER)
/* Safely check if adding two integers will overflow (no undefined
@@ -267,7 +266,7 @@ typedef struct ucvector {
} ucvector;
/*returns 1 if success, 0 if failure ==> nothing done*/
-static unsigned ucvector_resize(ucvector* p, size_t size) {
+static unsigned ucvector_reserve(ucvector* p, size_t size) {
if(size > p->allocsize) {
size_t newsize = size + (p->allocsize >> 1u);
void* data = lodepng_realloc(p->data, newsize);
@@ -277,10 +276,15 @@ static unsigned ucvector_resize(ucvector* p, size_t size) {
}
else return 0; /*error: not enough memory*/
}
- p->size = size;
return 1; /*success*/
}
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned ucvector_resize(ucvector* p, size_t size) {
+ p->size = size;
+ return ucvector_reserve(p, size);
+}
+
static ucvector ucvector_init(unsigned char* buffer, size_t size) {
ucvector v;
v.data = buffer;
@@ -480,71 +484,62 @@ static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned c
ensureBits functions:
Ensures the reader can at least read nbits bits in one or more readBits calls,
safely even if not enough bits are available.
-Returns 1 if there are enough bits available, 0 if not.
+The nbits parameter is unused but is given for documentation purposes, error
+checking for amount of bits must be done beforehand.
*/
-/*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;
-}*/
-
/*See ensureBits documentation above. This one ensures up to 9 bits */
-static unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits) {
+static LODEPNG_INLINE void 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);
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;
}
+ (void)nbits;
}
/*See ensureBits documentation above. This one ensures up to 17 bits */
-static unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits) {
+static LODEPNG_INLINE void 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) |
((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);
reader->buffer >>= (reader->bp & 7u);
- return reader->bp + nbits <= reader->bitsize;
}
+ (void)nbits;
}
/*See ensureBits documentation above. This one ensures up to 25 bits */
-static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits) {
+static LODEPNG_INLINE void 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);
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);
reader->buffer >>= (reader->bp & 7u);
- return reader->bp + nbits <= reader->bitsize;
}
+ (void)nbits;
}
/*See ensureBits documentation above. This one ensures up to 32 bits */
-static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits) {
+static LODEPNG_INLINE void ensureBits32(LodePNGBitReader* reader, size_t nbits) {
size_t start = reader->bp >> 3u;
size_t size = reader->size;
if(start + 4u < size) {
@@ -552,7 +547,6 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi
((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)));
- return 1;
} else {
reader->buffer = 0;
if(start + 0u < size) reader->buffer |= reader->data[start + 0];
@@ -560,48 +554,28 @@ static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbi
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;
}
+ (void)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) {
+static LODEPNG_INLINE 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 LODEPNG_INLINE 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 LODEPNG_INLINE 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) {
- size_t i;
- LodePNGBitReader reader;
- unsigned error = LodePNGBitReader_init(&reader, data, size);
- 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;
- result[i] = readBits(&reader, step);
- }
- return 1;
-}
#endif /*LODEPNG_COMPILE_DECODER*/
static unsigned reverseBits(unsigned bits, unsigned num) {
@@ -736,10 +710,11 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
numpresent = 0;
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 reverse = reverseBits(symbol, l);
+ unsigned symbol, reverse;
if(l == 0) continue;
+ 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*/
+ reverse = reverseBits(symbol, l);
numpresent++;
if(l <= FIRSTBITS) {
@@ -1103,11 +1078,10 @@ static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree*
advanceBits(reader, l);
return value;
} else {
- unsigned index2;
advanceBits(reader, FIRSTBITS);
- index2 = value + peekBits(reader, l - FIRSTBITS);
- advanceBits(reader, codetree->table_len[index2] - FIRSTBITS);
- return codetree->table_value[index2];
+ value += peekBits(reader, l - FIRSTBITS);
+ advanceBits(reader, codetree->table_len[value] - FIRSTBITS);
+ return codetree->table_value[value];
}
}
#endif /*LODEPNG_COMPILE_DECODER*/
@@ -1140,7 +1114,8 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_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(reader->bitsize - reader->bp < 14) return 49; /*error: the bit pointer is or will go past the memory*/
+ ensureBits17(reader, 14);
/*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
HLIT = readBits(reader, 5) + 257;
@@ -1265,6 +1240,10 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
unsigned error = 0;
HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
HuffmanTree tree_d; /*the huffman tree for distance codes*/
+ const size_t reserved_size = 260; /* must be at least 258 for max length, and a few extra for adding a few extra literals */
+ int done = 0;
+
+ if(!ucvector_reserve(out, out->size + reserved_size)) return 83; /*alloc fail*/
HuffmanTree_init(&tree_ll);
HuffmanTree_init(&tree_d);
@@ -1272,14 +1251,21 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* 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 && !done) /*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 */
+ /* ensure enough bits for 2 huffman code reads (15 bits each): if the first is a literal, a second literal is read at once. This
+ appears to be slightly faster, than ensuring 20 bits here for 1 huffman symbol and the potential 5 extra bits for the length symbol.*/
+ ensureBits32(reader, 30);
code_ll = huffmanDecodeSymbol(reader, &tree_ll);
+ if(code_ll <= 255) {
+ /*slightly faster code path if multiple literals in a row*/
+ out->data[out->size++] = (unsigned char)code_ll;
+ code_ll = huffmanDecodeSymbol(reader, &tree_ll);
+ }
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;
+ out->data[out->size++] = (unsigned char)code_ll;
} 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*/
@@ -1292,6 +1278,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
if(numextrabits_l != 0) {
/* bits already ensured above */
+ ensureBits25(reader, 5);
length += readBits(reader, numextrabits_l);
}
@@ -1319,7 +1306,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
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*/);
+ out->size += length;
if(distance < length) {
size_t forward;
lodepng_memcpy(out->data + start, out->data + backward, distance);
@@ -1331,10 +1318,13 @@ static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
lodepng_memcpy(out->data + start, out->data + backward, length);
}
} else if(code_ll == 256) {
- break; /*end code, break the loop*/
+ done = 1; /*end code, finish the loop*/
} else /*if(code_ll == INVALIDSYMBOL)*/ {
ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
}
+ if(out->allocsize - out->size < reserved_size) {
+ if(!ucvector_reserve(out, out->size + reserved_size)) ERROR_BREAK(83); /*alloc fail*/
+ }
/*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
@@ -1377,8 +1367,11 @@ static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader,
/*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*/
- lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
- bytepos += LEN;
+ /*out->data can be NULL (when LEN is zero), and arithmetics on NULL ptr is undefined*/
+ if (LEN) {
+ lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
+ bytepos += LEN;
+ }
reader->bp = bytepos << 3u;
@@ -1396,7 +1389,8 @@ static unsigned lodepng_inflatev(ucvector* out,
while(!BFINAL) {
unsigned BTYPE;
- if(!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/
+ if(reader.bitsize - reader.bp < 3) return 52; /*error, bit pointer will jump past memory*/
+ ensureBits9(&reader, 3);
BFINAL = readBits(&reader, 1);
BTYPE = readBits(&reader, 2);
@@ -2378,55 +2372,331 @@ const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0,
/* ////////////////////////////////////////////////////////////////////////// */
-#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
+#ifdef LODEPNG_COMPILE_CRC
+
+static const unsigned lodepng_crc32_table0[256] = {
+ 0x00000000u, 0x77073096u, 0xee0e612cu, 0x990951bau, 0x076dc419u, 0x706af48fu, 0xe963a535u, 0x9e6495a3u,
+ 0x0edb8832u, 0x79dcb8a4u, 0xe0d5e91eu, 0x97d2d988u, 0x09b64c2bu, 0x7eb17cbdu, 0xe7b82d07u, 0x90bf1d91u,
+ 0x1db71064u, 0x6ab020f2u, 0xf3b97148u, 0x84be41deu, 0x1adad47du, 0x6ddde4ebu, 0xf4d4b551u, 0x83d385c7u,
+ 0x136c9856u, 0x646ba8c0u, 0xfd62f97au, 0x8a65c9ecu, 0x14015c4fu, 0x63066cd9u, 0xfa0f3d63u, 0x8d080df5u,
+ 0x3b6e20c8u, 0x4c69105eu, 0xd56041e4u, 0xa2677172u, 0x3c03e4d1u, 0x4b04d447u, 0xd20d85fdu, 0xa50ab56bu,
+ 0x35b5a8fau, 0x42b2986cu, 0xdbbbc9d6u, 0xacbcf940u, 0x32d86ce3u, 0x45df5c75u, 0xdcd60dcfu, 0xabd13d59u,
+ 0x26d930acu, 0x51de003au, 0xc8d75180u, 0xbfd06116u, 0x21b4f4b5u, 0x56b3c423u, 0xcfba9599u, 0xb8bda50fu,
+ 0x2802b89eu, 0x5f058808u, 0xc60cd9b2u, 0xb10be924u, 0x2f6f7c87u, 0x58684c11u, 0xc1611dabu, 0xb6662d3du,
+ 0x76dc4190u, 0x01db7106u, 0x98d220bcu, 0xefd5102au, 0x71b18589u, 0x06b6b51fu, 0x9fbfe4a5u, 0xe8b8d433u,
+ 0x7807c9a2u, 0x0f00f934u, 0x9609a88eu, 0xe10e9818u, 0x7f6a0dbbu, 0x086d3d2du, 0x91646c97u, 0xe6635c01u,
+ 0x6b6b51f4u, 0x1c6c6162u, 0x856530d8u, 0xf262004eu, 0x6c0695edu, 0x1b01a57bu, 0x8208f4c1u, 0xf50fc457u,
+ 0x65b0d9c6u, 0x12b7e950u, 0x8bbeb8eau, 0xfcb9887cu, 0x62dd1ddfu, 0x15da2d49u, 0x8cd37cf3u, 0xfbd44c65u,
+ 0x4db26158u, 0x3ab551ceu, 0xa3bc0074u, 0xd4bb30e2u, 0x4adfa541u, 0x3dd895d7u, 0xa4d1c46du, 0xd3d6f4fbu,
+ 0x4369e96au, 0x346ed9fcu, 0xad678846u, 0xda60b8d0u, 0x44042d73u, 0x33031de5u, 0xaa0a4c5fu, 0xdd0d7cc9u,
+ 0x5005713cu, 0x270241aau, 0xbe0b1010u, 0xc90c2086u, 0x5768b525u, 0x206f85b3u, 0xb966d409u, 0xce61e49fu,
+ 0x5edef90eu, 0x29d9c998u, 0xb0d09822u, 0xc7d7a8b4u, 0x59b33d17u, 0x2eb40d81u, 0xb7bd5c3bu, 0xc0ba6cadu,
+ 0xedb88320u, 0x9abfb3b6u, 0x03b6e20cu, 0x74b1d29au, 0xead54739u, 0x9dd277afu, 0x04db2615u, 0x73dc1683u,
+ 0xe3630b12u, 0x94643b84u, 0x0d6d6a3eu, 0x7a6a5aa8u, 0xe40ecf0bu, 0x9309ff9du, 0x0a00ae27u, 0x7d079eb1u,
+ 0xf00f9344u, 0x8708a3d2u, 0x1e01f268u, 0x6906c2feu, 0xf762575du, 0x806567cbu, 0x196c3671u, 0x6e6b06e7u,
+ 0xfed41b76u, 0x89d32be0u, 0x10da7a5au, 0x67dd4accu, 0xf9b9df6fu, 0x8ebeeff9u, 0x17b7be43u, 0x60b08ed5u,
+ 0xd6d6a3e8u, 0xa1d1937eu, 0x38d8c2c4u, 0x4fdff252u, 0xd1bb67f1u, 0xa6bc5767u, 0x3fb506ddu, 0x48b2364bu,
+ 0xd80d2bdau, 0xaf0a1b4cu, 0x36034af6u, 0x41047a60u, 0xdf60efc3u, 0xa867df55u, 0x316e8eefu, 0x4669be79u,
+ 0xcb61b38cu, 0xbc66831au, 0x256fd2a0u, 0x5268e236u, 0xcc0c7795u, 0xbb0b4703u, 0x220216b9u, 0x5505262fu,
+ 0xc5ba3bbeu, 0xb2bd0b28u, 0x2bb45a92u, 0x5cb36a04u, 0xc2d7ffa7u, 0xb5d0cf31u, 0x2cd99e8bu, 0x5bdeae1du,
+ 0x9b64c2b0u, 0xec63f226u, 0x756aa39cu, 0x026d930au, 0x9c0906a9u, 0xeb0e363fu, 0x72076785u, 0x05005713u,
+ 0x95bf4a82u, 0xe2b87a14u, 0x7bb12baeu, 0x0cb61b38u, 0x92d28e9bu, 0xe5d5be0du, 0x7cdcefb7u, 0x0bdbdf21u,
+ 0x86d3d2d4u, 0xf1d4e242u, 0x68ddb3f8u, 0x1fda836eu, 0x81be16cdu, 0xf6b9265bu, 0x6fb077e1u, 0x18b74777u,
+ 0x88085ae6u, 0xff0f6a70u, 0x66063bcau, 0x11010b5cu, 0x8f659effu, 0xf862ae69u, 0x616bffd3u, 0x166ccf45u,
+ 0xa00ae278u, 0xd70dd2eeu, 0x4e048354u, 0x3903b3c2u, 0xa7672661u, 0xd06016f7u, 0x4969474du, 0x3e6e77dbu,
+ 0xaed16a4au, 0xd9d65adcu, 0x40df0b66u, 0x37d83bf0u, 0xa9bcae53u, 0xdebb9ec5u, 0x47b2cf7fu, 0x30b5ffe9u,
+ 0xbdbdf21cu, 0xcabac28au, 0x53b39330u, 0x24b4a3a6u, 0xbad03605u, 0xcdd70693u, 0x54de5729u, 0x23d967bfu,
+ 0xb3667a2eu, 0xc4614ab8u, 0x5d681b02u, 0x2a6f2b94u, 0xb40bbe37u, 0xc30c8ea1u, 0x5a05df1bu, 0x2d02ef8du
};
-/*Return the CRC of the bytes buf[0..len-1].*/
+static const unsigned lodepng_crc32_table1[256] = {
+ 0x00000000u, 0x191b3141u, 0x32366282u, 0x2b2d53c3u, 0x646cc504u, 0x7d77f445u, 0x565aa786u, 0x4f4196c7u,
+ 0xc8d98a08u, 0xd1c2bb49u, 0xfaefe88au, 0xe3f4d9cbu, 0xacb54f0cu, 0xb5ae7e4du, 0x9e832d8eu, 0x87981ccfu,
+ 0x4ac21251u, 0x53d92310u, 0x78f470d3u, 0x61ef4192u, 0x2eaed755u, 0x37b5e614u, 0x1c98b5d7u, 0x05838496u,
+ 0x821b9859u, 0x9b00a918u, 0xb02dfadbu, 0xa936cb9au, 0xe6775d5du, 0xff6c6c1cu, 0xd4413fdfu, 0xcd5a0e9eu,
+ 0x958424a2u, 0x8c9f15e3u, 0xa7b24620u, 0xbea97761u, 0xf1e8e1a6u, 0xe8f3d0e7u, 0xc3de8324u, 0xdac5b265u,
+ 0x5d5daeaau, 0x44469febu, 0x6f6bcc28u, 0x7670fd69u, 0x39316baeu, 0x202a5aefu, 0x0b07092cu, 0x121c386du,
+ 0xdf4636f3u, 0xc65d07b2u, 0xed705471u, 0xf46b6530u, 0xbb2af3f7u, 0xa231c2b6u, 0x891c9175u, 0x9007a034u,
+ 0x179fbcfbu, 0x0e848dbau, 0x25a9de79u, 0x3cb2ef38u, 0x73f379ffu, 0x6ae848beu, 0x41c51b7du, 0x58de2a3cu,
+ 0xf0794f05u, 0xe9627e44u, 0xc24f2d87u, 0xdb541cc6u, 0x94158a01u, 0x8d0ebb40u, 0xa623e883u, 0xbf38d9c2u,
+ 0x38a0c50du, 0x21bbf44cu, 0x0a96a78fu, 0x138d96ceu, 0x5ccc0009u, 0x45d73148u, 0x6efa628bu, 0x77e153cau,
+ 0xbabb5d54u, 0xa3a06c15u, 0x888d3fd6u, 0x91960e97u, 0xded79850u, 0xc7cca911u, 0xece1fad2u, 0xf5facb93u,
+ 0x7262d75cu, 0x6b79e61du, 0x4054b5deu, 0x594f849fu, 0x160e1258u, 0x0f152319u, 0x243870dau, 0x3d23419bu,
+ 0x65fd6ba7u, 0x7ce65ae6u, 0x57cb0925u, 0x4ed03864u, 0x0191aea3u, 0x188a9fe2u, 0x33a7cc21u, 0x2abcfd60u,
+ 0xad24e1afu, 0xb43fd0eeu, 0x9f12832du, 0x8609b26cu, 0xc94824abu, 0xd05315eau, 0xfb7e4629u, 0xe2657768u,
+ 0x2f3f79f6u, 0x362448b7u, 0x1d091b74u, 0x04122a35u, 0x4b53bcf2u, 0x52488db3u, 0x7965de70u, 0x607eef31u,
+ 0xe7e6f3feu, 0xfefdc2bfu, 0xd5d0917cu, 0xcccba03du, 0x838a36fau, 0x9a9107bbu, 0xb1bc5478u, 0xa8a76539u,
+ 0x3b83984bu, 0x2298a90au, 0x09b5fac9u, 0x10aecb88u, 0x5fef5d4fu, 0x46f46c0eu, 0x6dd93fcdu, 0x74c20e8cu,
+ 0xf35a1243u, 0xea412302u, 0xc16c70c1u, 0xd8774180u, 0x9736d747u, 0x8e2de606u, 0xa500b5c5u, 0xbc1b8484u,
+ 0x71418a1au, 0x685abb5bu, 0x4377e898u, 0x5a6cd9d9u, 0x152d4f1eu, 0x0c367e5fu, 0x271b2d9cu, 0x3e001cddu,
+ 0xb9980012u, 0xa0833153u, 0x8bae6290u, 0x92b553d1u, 0xddf4c516u, 0xc4eff457u, 0xefc2a794u, 0xf6d996d5u,
+ 0xae07bce9u, 0xb71c8da8u, 0x9c31de6bu, 0x852aef2au, 0xca6b79edu, 0xd37048acu, 0xf85d1b6fu, 0xe1462a2eu,
+ 0x66de36e1u, 0x7fc507a0u, 0x54e85463u, 0x4df36522u, 0x02b2f3e5u, 0x1ba9c2a4u, 0x30849167u, 0x299fa026u,
+ 0xe4c5aeb8u, 0xfdde9ff9u, 0xd6f3cc3au, 0xcfe8fd7bu, 0x80a96bbcu, 0x99b25afdu, 0xb29f093eu, 0xab84387fu,
+ 0x2c1c24b0u, 0x350715f1u, 0x1e2a4632u, 0x07317773u, 0x4870e1b4u, 0x516bd0f5u, 0x7a468336u, 0x635db277u,
+ 0xcbfad74eu, 0xd2e1e60fu, 0xf9ccb5ccu, 0xe0d7848du, 0xaf96124au, 0xb68d230bu, 0x9da070c8u, 0x84bb4189u,
+ 0x03235d46u, 0x1a386c07u, 0x31153fc4u, 0x280e0e85u, 0x674f9842u, 0x7e54a903u, 0x5579fac0u, 0x4c62cb81u,
+ 0x8138c51fu, 0x9823f45eu, 0xb30ea79du, 0xaa1596dcu, 0xe554001bu, 0xfc4f315au, 0xd7626299u, 0xce7953d8u,
+ 0x49e14f17u, 0x50fa7e56u, 0x7bd72d95u, 0x62cc1cd4u, 0x2d8d8a13u, 0x3496bb52u, 0x1fbbe891u, 0x06a0d9d0u,
+ 0x5e7ef3ecu, 0x4765c2adu, 0x6c48916eu, 0x7553a02fu, 0x3a1236e8u, 0x230907a9u, 0x0824546au, 0x113f652bu,
+ 0x96a779e4u, 0x8fbc48a5u, 0xa4911b66u, 0xbd8a2a27u, 0xf2cbbce0u, 0xebd08da1u, 0xc0fdde62u, 0xd9e6ef23u,
+ 0x14bce1bdu, 0x0da7d0fcu, 0x268a833fu, 0x3f91b27eu, 0x70d024b9u, 0x69cb15f8u, 0x42e6463bu, 0x5bfd777au,
+ 0xdc656bb5u, 0xc57e5af4u, 0xee530937u, 0xf7483876u, 0xb809aeb1u, 0xa1129ff0u, 0x8a3fcc33u, 0x9324fd72u
+};
+
+static const unsigned lodepng_crc32_table2[256] = {
+ 0x00000000u, 0x01c26a37u, 0x0384d46eu, 0x0246be59u, 0x0709a8dcu, 0x06cbc2ebu, 0x048d7cb2u, 0x054f1685u,
+ 0x0e1351b8u, 0x0fd13b8fu, 0x0d9785d6u, 0x0c55efe1u, 0x091af964u, 0x08d89353u, 0x0a9e2d0au, 0x0b5c473du,
+ 0x1c26a370u, 0x1de4c947u, 0x1fa2771eu, 0x1e601d29u, 0x1b2f0bacu, 0x1aed619bu, 0x18abdfc2u, 0x1969b5f5u,
+ 0x1235f2c8u, 0x13f798ffu, 0x11b126a6u, 0x10734c91u, 0x153c5a14u, 0x14fe3023u, 0x16b88e7au, 0x177ae44du,
+ 0x384d46e0u, 0x398f2cd7u, 0x3bc9928eu, 0x3a0bf8b9u, 0x3f44ee3cu, 0x3e86840bu, 0x3cc03a52u, 0x3d025065u,
+ 0x365e1758u, 0x379c7d6fu, 0x35dac336u, 0x3418a901u, 0x3157bf84u, 0x3095d5b3u, 0x32d36beau, 0x331101ddu,
+ 0x246be590u, 0x25a98fa7u, 0x27ef31feu, 0x262d5bc9u, 0x23624d4cu, 0x22a0277bu, 0x20e69922u, 0x2124f315u,
+ 0x2a78b428u, 0x2bbade1fu, 0x29fc6046u, 0x283e0a71u, 0x2d711cf4u, 0x2cb376c3u, 0x2ef5c89au, 0x2f37a2adu,
+ 0x709a8dc0u, 0x7158e7f7u, 0x731e59aeu, 0x72dc3399u, 0x7793251cu, 0x76514f2bu, 0x7417f172u, 0x75d59b45u,
+ 0x7e89dc78u, 0x7f4bb64fu, 0x7d0d0816u, 0x7ccf6221u, 0x798074a4u, 0x78421e93u, 0x7a04a0cau, 0x7bc6cafdu,
+ 0x6cbc2eb0u, 0x6d7e4487u, 0x6f38fadeu, 0x6efa90e9u, 0x6bb5866cu, 0x6a77ec5bu, 0x68315202u, 0x69f33835u,
+ 0x62af7f08u, 0x636d153fu, 0x612bab66u, 0x60e9c151u, 0x65a6d7d4u, 0x6464bde3u, 0x662203bau, 0x67e0698du,
+ 0x48d7cb20u, 0x4915a117u, 0x4b531f4eu, 0x4a917579u, 0x4fde63fcu, 0x4e1c09cbu, 0x4c5ab792u, 0x4d98dda5u,
+ 0x46c49a98u, 0x4706f0afu, 0x45404ef6u, 0x448224c1u, 0x41cd3244u, 0x400f5873u, 0x4249e62au, 0x438b8c1du,
+ 0x54f16850u, 0x55330267u, 0x5775bc3eu, 0x56b7d609u, 0x53f8c08cu, 0x523aaabbu, 0x507c14e2u, 0x51be7ed5u,
+ 0x5ae239e8u, 0x5b2053dfu, 0x5966ed86u, 0x58a487b1u, 0x5deb9134u, 0x5c29fb03u, 0x5e6f455au, 0x5fad2f6du,
+ 0xe1351b80u, 0xe0f771b7u, 0xe2b1cfeeu, 0xe373a5d9u, 0xe63cb35cu, 0xe7fed96bu, 0xe5b86732u, 0xe47a0d05u,
+ 0xef264a38u, 0xeee4200fu, 0xeca29e56u, 0xed60f461u, 0xe82fe2e4u, 0xe9ed88d3u, 0xebab368au, 0xea695cbdu,
+ 0xfd13b8f0u, 0xfcd1d2c7u, 0xfe976c9eu, 0xff5506a9u, 0xfa1a102cu, 0xfbd87a1bu, 0xf99ec442u, 0xf85cae75u,
+ 0xf300e948u, 0xf2c2837fu, 0xf0843d26u, 0xf1465711u, 0xf4094194u, 0xf5cb2ba3u, 0xf78d95fau, 0xf64fffcdu,
+ 0xd9785d60u, 0xd8ba3757u, 0xdafc890eu, 0xdb3ee339u, 0xde71f5bcu, 0xdfb39f8bu, 0xddf521d2u, 0xdc374be5u,
+ 0xd76b0cd8u, 0xd6a966efu, 0xd4efd8b6u, 0xd52db281u, 0xd062a404u, 0xd1a0ce33u, 0xd3e6706au, 0xd2241a5du,
+ 0xc55efe10u, 0xc49c9427u, 0xc6da2a7eu, 0xc7184049u, 0xc25756ccu, 0xc3953cfbu, 0xc1d382a2u, 0xc011e895u,
+ 0xcb4dafa8u, 0xca8fc59fu, 0xc8c97bc6u, 0xc90b11f1u, 0xcc440774u, 0xcd866d43u, 0xcfc0d31au, 0xce02b92du,
+ 0x91af9640u, 0x906dfc77u, 0x922b422eu, 0x93e92819u, 0x96a63e9cu, 0x976454abu, 0x9522eaf2u, 0x94e080c5u,
+ 0x9fbcc7f8u, 0x9e7eadcfu, 0x9c381396u, 0x9dfa79a1u, 0x98b56f24u, 0x99770513u, 0x9b31bb4au, 0x9af3d17du,
+ 0x8d893530u, 0x8c4b5f07u, 0x8e0de15eu, 0x8fcf8b69u, 0x8a809decu, 0x8b42f7dbu, 0x89044982u, 0x88c623b5u,
+ 0x839a6488u, 0x82580ebfu, 0x801eb0e6u, 0x81dcdad1u, 0x8493cc54u, 0x8551a663u, 0x8717183au, 0x86d5720du,
+ 0xa9e2d0a0u, 0xa820ba97u, 0xaa6604ceu, 0xaba46ef9u, 0xaeeb787cu, 0xaf29124bu, 0xad6fac12u, 0xacadc625u,
+ 0xa7f18118u, 0xa633eb2fu, 0xa4755576u, 0xa5b73f41u, 0xa0f829c4u, 0xa13a43f3u, 0xa37cfdaau, 0xa2be979du,
+ 0xb5c473d0u, 0xb40619e7u, 0xb640a7beu, 0xb782cd89u, 0xb2cddb0cu, 0xb30fb13bu, 0xb1490f62u, 0xb08b6555u,
+ 0xbbd72268u, 0xba15485fu, 0xb853f606u, 0xb9919c31u, 0xbcde8ab4u, 0xbd1ce083u, 0xbf5a5edau, 0xbe9834edu
+};
+
+static const unsigned lodepng_crc32_table3[256] = {
+ 0x00000000u, 0xb8bc6765u, 0xaa09c88bu, 0x12b5afeeu, 0x8f629757u, 0x37def032u, 0x256b5fdcu, 0x9dd738b9u,
+ 0xc5b428efu, 0x7d084f8au, 0x6fbde064u, 0xd7018701u, 0x4ad6bfb8u, 0xf26ad8ddu, 0xe0df7733u, 0x58631056u,
+ 0x5019579fu, 0xe8a530fau, 0xfa109f14u, 0x42acf871u, 0xdf7bc0c8u, 0x67c7a7adu, 0x75720843u, 0xcdce6f26u,
+ 0x95ad7f70u, 0x2d111815u, 0x3fa4b7fbu, 0x8718d09eu, 0x1acfe827u, 0xa2738f42u, 0xb0c620acu, 0x087a47c9u,
+ 0xa032af3eu, 0x188ec85bu, 0x0a3b67b5u, 0xb28700d0u, 0x2f503869u, 0x97ec5f0cu, 0x8559f0e2u, 0x3de59787u,
+ 0x658687d1u, 0xdd3ae0b4u, 0xcf8f4f5au, 0x7733283fu, 0xeae41086u, 0x525877e3u, 0x40edd80du, 0xf851bf68u,
+ 0xf02bf8a1u, 0x48979fc4u, 0x5a22302au, 0xe29e574fu, 0x7f496ff6u, 0xc7f50893u, 0xd540a77du, 0x6dfcc018u,
+ 0x359fd04eu, 0x8d23b72bu, 0x9f9618c5u, 0x272a7fa0u, 0xbafd4719u, 0x0241207cu, 0x10f48f92u, 0xa848e8f7u,
+ 0x9b14583du, 0x23a83f58u, 0x311d90b6u, 0x89a1f7d3u, 0x1476cf6au, 0xaccaa80fu, 0xbe7f07e1u, 0x06c36084u,
+ 0x5ea070d2u, 0xe61c17b7u, 0xf4a9b859u, 0x4c15df3cu, 0xd1c2e785u, 0x697e80e0u, 0x7bcb2f0eu, 0xc377486bu,
+ 0xcb0d0fa2u, 0x73b168c7u, 0x6104c729u, 0xd9b8a04cu, 0x446f98f5u, 0xfcd3ff90u, 0xee66507eu, 0x56da371bu,
+ 0x0eb9274du, 0xb6054028u, 0xa4b0efc6u, 0x1c0c88a3u, 0x81dbb01au, 0x3967d77fu, 0x2bd27891u, 0x936e1ff4u,
+ 0x3b26f703u, 0x839a9066u, 0x912f3f88u, 0x299358edu, 0xb4446054u, 0x0cf80731u, 0x1e4da8dfu, 0xa6f1cfbau,
+ 0xfe92dfecu, 0x462eb889u, 0x549b1767u, 0xec277002u, 0x71f048bbu, 0xc94c2fdeu, 0xdbf98030u, 0x6345e755u,
+ 0x6b3fa09cu, 0xd383c7f9u, 0xc1366817u, 0x798a0f72u, 0xe45d37cbu, 0x5ce150aeu, 0x4e54ff40u, 0xf6e89825u,
+ 0xae8b8873u, 0x1637ef16u, 0x048240f8u, 0xbc3e279du, 0x21e91f24u, 0x99557841u, 0x8be0d7afu, 0x335cb0cau,
+ 0xed59b63bu, 0x55e5d15eu, 0x47507eb0u, 0xffec19d5u, 0x623b216cu, 0xda874609u, 0xc832e9e7u, 0x708e8e82u,
+ 0x28ed9ed4u, 0x9051f9b1u, 0x82e4565fu, 0x3a58313au, 0xa78f0983u, 0x1f336ee6u, 0x0d86c108u, 0xb53aa66du,
+ 0xbd40e1a4u, 0x05fc86c1u, 0x1749292fu, 0xaff54e4au, 0x322276f3u, 0x8a9e1196u, 0x982bbe78u, 0x2097d91du,
+ 0x78f4c94bu, 0xc048ae2eu, 0xd2fd01c0u, 0x6a4166a5u, 0xf7965e1cu, 0x4f2a3979u, 0x5d9f9697u, 0xe523f1f2u,
+ 0x4d6b1905u, 0xf5d77e60u, 0xe762d18eu, 0x5fdeb6ebu, 0xc2098e52u, 0x7ab5e937u, 0x680046d9u, 0xd0bc21bcu,
+ 0x88df31eau, 0x3063568fu, 0x22d6f961u, 0x9a6a9e04u, 0x07bda6bdu, 0xbf01c1d8u, 0xadb46e36u, 0x15080953u,
+ 0x1d724e9au, 0xa5ce29ffu, 0xb77b8611u, 0x0fc7e174u, 0x9210d9cdu, 0x2aacbea8u, 0x38191146u, 0x80a57623u,
+ 0xd8c66675u, 0x607a0110u, 0x72cfaefeu, 0xca73c99bu, 0x57a4f122u, 0xef189647u, 0xfdad39a9u, 0x45115eccu,
+ 0x764dee06u, 0xcef18963u, 0xdc44268du, 0x64f841e8u, 0xf92f7951u, 0x41931e34u, 0x5326b1dau, 0xeb9ad6bfu,
+ 0xb3f9c6e9u, 0x0b45a18cu, 0x19f00e62u, 0xa14c6907u, 0x3c9b51beu, 0x842736dbu, 0x96929935u, 0x2e2efe50u,
+ 0x2654b999u, 0x9ee8defcu, 0x8c5d7112u, 0x34e11677u, 0xa9362eceu, 0x118a49abu, 0x033fe645u, 0xbb838120u,
+ 0xe3e09176u, 0x5b5cf613u, 0x49e959fdu, 0xf1553e98u, 0x6c820621u, 0xd43e6144u, 0xc68bceaau, 0x7e37a9cfu,
+ 0xd67f4138u, 0x6ec3265du, 0x7c7689b3u, 0xc4caeed6u, 0x591dd66fu, 0xe1a1b10au, 0xf3141ee4u, 0x4ba87981u,
+ 0x13cb69d7u, 0xab770eb2u, 0xb9c2a15cu, 0x017ec639u, 0x9ca9fe80u, 0x241599e5u, 0x36a0360bu, 0x8e1c516eu,
+ 0x866616a7u, 0x3eda71c2u, 0x2c6fde2cu, 0x94d3b949u, 0x090481f0u, 0xb1b8e695u, 0xa30d497bu, 0x1bb12e1eu,
+ 0x43d23e48u, 0xfb6e592du, 0xe9dbf6c3u, 0x516791a6u, 0xccb0a91fu, 0x740cce7au, 0x66b96194u, 0xde0506f1u
+};
+
+static const unsigned lodepng_crc32_table4[256] = {
+ 0x00000000u, 0x3d6029b0u, 0x7ac05360u, 0x47a07ad0u, 0xf580a6c0u, 0xc8e08f70u, 0x8f40f5a0u, 0xb220dc10u,
+ 0x30704bc1u, 0x0d106271u, 0x4ab018a1u, 0x77d03111u, 0xc5f0ed01u, 0xf890c4b1u, 0xbf30be61u, 0x825097d1u,
+ 0x60e09782u, 0x5d80be32u, 0x1a20c4e2u, 0x2740ed52u, 0x95603142u, 0xa80018f2u, 0xefa06222u, 0xd2c04b92u,
+ 0x5090dc43u, 0x6df0f5f3u, 0x2a508f23u, 0x1730a693u, 0xa5107a83u, 0x98705333u, 0xdfd029e3u, 0xe2b00053u,
+ 0xc1c12f04u, 0xfca106b4u, 0xbb017c64u, 0x866155d4u, 0x344189c4u, 0x0921a074u, 0x4e81daa4u, 0x73e1f314u,
+ 0xf1b164c5u, 0xccd14d75u, 0x8b7137a5u, 0xb6111e15u, 0x0431c205u, 0x3951ebb5u, 0x7ef19165u, 0x4391b8d5u,
+ 0xa121b886u, 0x9c419136u, 0xdbe1ebe6u, 0xe681c256u, 0x54a11e46u, 0x69c137f6u, 0x2e614d26u, 0x13016496u,
+ 0x9151f347u, 0xac31daf7u, 0xeb91a027u, 0xd6f18997u, 0x64d15587u, 0x59b17c37u, 0x1e1106e7u, 0x23712f57u,
+ 0x58f35849u, 0x659371f9u, 0x22330b29u, 0x1f532299u, 0xad73fe89u, 0x9013d739u, 0xd7b3ade9u, 0xead38459u,
+ 0x68831388u, 0x55e33a38u, 0x124340e8u, 0x2f236958u, 0x9d03b548u, 0xa0639cf8u, 0xe7c3e628u, 0xdaa3cf98u,
+ 0x3813cfcbu, 0x0573e67bu, 0x42d39cabu, 0x7fb3b51bu, 0xcd93690bu, 0xf0f340bbu, 0xb7533a6bu, 0x8a3313dbu,
+ 0x0863840au, 0x3503adbau, 0x72a3d76au, 0x4fc3fedau, 0xfde322cau, 0xc0830b7au, 0x872371aau, 0xba43581au,
+ 0x9932774du, 0xa4525efdu, 0xe3f2242du, 0xde920d9du, 0x6cb2d18du, 0x51d2f83du, 0x167282edu, 0x2b12ab5du,
+ 0xa9423c8cu, 0x9422153cu, 0xd3826fecu, 0xeee2465cu, 0x5cc29a4cu, 0x61a2b3fcu, 0x2602c92cu, 0x1b62e09cu,
+ 0xf9d2e0cfu, 0xc4b2c97fu, 0x8312b3afu, 0xbe729a1fu, 0x0c52460fu, 0x31326fbfu, 0x7692156fu, 0x4bf23cdfu,
+ 0xc9a2ab0eu, 0xf4c282beu, 0xb362f86eu, 0x8e02d1deu, 0x3c220dceu, 0x0142247eu, 0x46e25eaeu, 0x7b82771eu,
+ 0xb1e6b092u, 0x8c869922u, 0xcb26e3f2u, 0xf646ca42u, 0x44661652u, 0x79063fe2u, 0x3ea64532u, 0x03c66c82u,
+ 0x8196fb53u, 0xbcf6d2e3u, 0xfb56a833u, 0xc6368183u, 0x74165d93u, 0x49767423u, 0x0ed60ef3u, 0x33b62743u,
+ 0xd1062710u, 0xec660ea0u, 0xabc67470u, 0x96a65dc0u, 0x248681d0u, 0x19e6a860u, 0x5e46d2b0u, 0x6326fb00u,
+ 0xe1766cd1u, 0xdc164561u, 0x9bb63fb1u, 0xa6d61601u, 0x14f6ca11u, 0x2996e3a1u, 0x6e369971u, 0x5356b0c1u,
+ 0x70279f96u, 0x4d47b626u, 0x0ae7ccf6u, 0x3787e546u, 0x85a73956u, 0xb8c710e6u, 0xff676a36u, 0xc2074386u,
+ 0x4057d457u, 0x7d37fde7u, 0x3a978737u, 0x07f7ae87u, 0xb5d77297u, 0x88b75b27u, 0xcf1721f7u, 0xf2770847u,
+ 0x10c70814u, 0x2da721a4u, 0x6a075b74u, 0x576772c4u, 0xe547aed4u, 0xd8278764u, 0x9f87fdb4u, 0xa2e7d404u,
+ 0x20b743d5u, 0x1dd76a65u, 0x5a7710b5u, 0x67173905u, 0xd537e515u, 0xe857cca5u, 0xaff7b675u, 0x92979fc5u,
+ 0xe915e8dbu, 0xd475c16bu, 0x93d5bbbbu, 0xaeb5920bu, 0x1c954e1bu, 0x21f567abu, 0x66551d7bu, 0x5b3534cbu,
+ 0xd965a31au, 0xe4058aaau, 0xa3a5f07au, 0x9ec5d9cau, 0x2ce505dau, 0x11852c6au, 0x562556bau, 0x6b457f0au,
+ 0x89f57f59u, 0xb49556e9u, 0xf3352c39u, 0xce550589u, 0x7c75d999u, 0x4115f029u, 0x06b58af9u, 0x3bd5a349u,
+ 0xb9853498u, 0x84e51d28u, 0xc34567f8u, 0xfe254e48u, 0x4c059258u, 0x7165bbe8u, 0x36c5c138u, 0x0ba5e888u,
+ 0x28d4c7dfu, 0x15b4ee6fu, 0x521494bfu, 0x6f74bd0fu, 0xdd54611fu, 0xe03448afu, 0xa794327fu, 0x9af41bcfu,
+ 0x18a48c1eu, 0x25c4a5aeu, 0x6264df7eu, 0x5f04f6ceu, 0xed242adeu, 0xd044036eu, 0x97e479beu, 0xaa84500eu,
+ 0x4834505du, 0x755479edu, 0x32f4033du, 0x0f942a8du, 0xbdb4f69du, 0x80d4df2du, 0xc774a5fdu, 0xfa148c4du,
+ 0x78441b9cu, 0x4524322cu, 0x028448fcu, 0x3fe4614cu, 0x8dc4bd5cu, 0xb0a494ecu, 0xf704ee3cu, 0xca64c78cu
+};
+
+static const unsigned lodepng_crc32_table5[256] = {
+ 0x00000000u, 0xcb5cd3a5u, 0x4dc8a10bu, 0x869472aeu, 0x9b914216u, 0x50cd91b3u, 0xd659e31du, 0x1d0530b8u,
+ 0xec53826du, 0x270f51c8u, 0xa19b2366u, 0x6ac7f0c3u, 0x77c2c07bu, 0xbc9e13deu, 0x3a0a6170u, 0xf156b2d5u,
+ 0x03d6029bu, 0xc88ad13eu, 0x4e1ea390u, 0x85427035u, 0x9847408du, 0x531b9328u, 0xd58fe186u, 0x1ed33223u,
+ 0xef8580f6u, 0x24d95353u, 0xa24d21fdu, 0x6911f258u, 0x7414c2e0u, 0xbf481145u, 0x39dc63ebu, 0xf280b04eu,
+ 0x07ac0536u, 0xccf0d693u, 0x4a64a43du, 0x81387798u, 0x9c3d4720u, 0x57619485u, 0xd1f5e62bu, 0x1aa9358eu,
+ 0xebff875bu, 0x20a354feu, 0xa6372650u, 0x6d6bf5f5u, 0x706ec54du, 0xbb3216e8u, 0x3da66446u, 0xf6fab7e3u,
+ 0x047a07adu, 0xcf26d408u, 0x49b2a6a6u, 0x82ee7503u, 0x9feb45bbu, 0x54b7961eu, 0xd223e4b0u, 0x197f3715u,
+ 0xe82985c0u, 0x23755665u, 0xa5e124cbu, 0x6ebdf76eu, 0x73b8c7d6u, 0xb8e41473u, 0x3e7066ddu, 0xf52cb578u,
+ 0x0f580a6cu, 0xc404d9c9u, 0x4290ab67u, 0x89cc78c2u, 0x94c9487au, 0x5f959bdfu, 0xd901e971u, 0x125d3ad4u,
+ 0xe30b8801u, 0x28575ba4u, 0xaec3290au, 0x659ffaafu, 0x789aca17u, 0xb3c619b2u, 0x35526b1cu, 0xfe0eb8b9u,
+ 0x0c8e08f7u, 0xc7d2db52u, 0x4146a9fcu, 0x8a1a7a59u, 0x971f4ae1u, 0x5c439944u, 0xdad7ebeau, 0x118b384fu,
+ 0xe0dd8a9au, 0x2b81593fu, 0xad152b91u, 0x6649f834u, 0x7b4cc88cu, 0xb0101b29u, 0x36846987u, 0xfdd8ba22u,
+ 0x08f40f5au, 0xc3a8dcffu, 0x453cae51u, 0x8e607df4u, 0x93654d4cu, 0x58399ee9u, 0xdeadec47u, 0x15f13fe2u,
+ 0xe4a78d37u, 0x2ffb5e92u, 0xa96f2c3cu, 0x6233ff99u, 0x7f36cf21u, 0xb46a1c84u, 0x32fe6e2au, 0xf9a2bd8fu,
+ 0x0b220dc1u, 0xc07ede64u, 0x46eaaccau, 0x8db67f6fu, 0x90b34fd7u, 0x5bef9c72u, 0xdd7beedcu, 0x16273d79u,
+ 0xe7718facu, 0x2c2d5c09u, 0xaab92ea7u, 0x61e5fd02u, 0x7ce0cdbau, 0xb7bc1e1fu, 0x31286cb1u, 0xfa74bf14u,
+ 0x1eb014d8u, 0xd5ecc77du, 0x5378b5d3u, 0x98246676u, 0x852156ceu, 0x4e7d856bu, 0xc8e9f7c5u, 0x03b52460u,
+ 0xf2e396b5u, 0x39bf4510u, 0xbf2b37beu, 0x7477e41bu, 0x6972d4a3u, 0xa22e0706u, 0x24ba75a8u, 0xefe6a60du,
+ 0x1d661643u, 0xd63ac5e6u, 0x50aeb748u, 0x9bf264edu, 0x86f75455u, 0x4dab87f0u, 0xcb3ff55eu, 0x006326fbu,
+ 0xf135942eu, 0x3a69478bu, 0xbcfd3525u, 0x77a1e680u, 0x6aa4d638u, 0xa1f8059du, 0x276c7733u, 0xec30a496u,
+ 0x191c11eeu, 0xd240c24bu, 0x54d4b0e5u, 0x9f886340u, 0x828d53f8u, 0x49d1805du, 0xcf45f2f3u, 0x04192156u,
+ 0xf54f9383u, 0x3e134026u, 0xb8873288u, 0x73dbe12du, 0x6eded195u, 0xa5820230u, 0x2316709eu, 0xe84aa33bu,
+ 0x1aca1375u, 0xd196c0d0u, 0x5702b27eu, 0x9c5e61dbu, 0x815b5163u, 0x4a0782c6u, 0xcc93f068u, 0x07cf23cdu,
+ 0xf6999118u, 0x3dc542bdu, 0xbb513013u, 0x700de3b6u, 0x6d08d30eu, 0xa65400abu, 0x20c07205u, 0xeb9ca1a0u,
+ 0x11e81eb4u, 0xdab4cd11u, 0x5c20bfbfu, 0x977c6c1au, 0x8a795ca2u, 0x41258f07u, 0xc7b1fda9u, 0x0ced2e0cu,
+ 0xfdbb9cd9u, 0x36e74f7cu, 0xb0733dd2u, 0x7b2fee77u, 0x662adecfu, 0xad760d6au, 0x2be27fc4u, 0xe0beac61u,
+ 0x123e1c2fu, 0xd962cf8au, 0x5ff6bd24u, 0x94aa6e81u, 0x89af5e39u, 0x42f38d9cu, 0xc467ff32u, 0x0f3b2c97u,
+ 0xfe6d9e42u, 0x35314de7u, 0xb3a53f49u, 0x78f9ececu, 0x65fcdc54u, 0xaea00ff1u, 0x28347d5fu, 0xe368aefau,
+ 0x16441b82u, 0xdd18c827u, 0x5b8cba89u, 0x90d0692cu, 0x8dd55994u, 0x46898a31u, 0xc01df89fu, 0x0b412b3au,
+ 0xfa1799efu, 0x314b4a4au, 0xb7df38e4u, 0x7c83eb41u, 0x6186dbf9u, 0xaada085cu, 0x2c4e7af2u, 0xe712a957u,
+ 0x15921919u, 0xdececabcu, 0x585ab812u, 0x93066bb7u, 0x8e035b0fu, 0x455f88aau, 0xc3cbfa04u, 0x089729a1u,
+ 0xf9c19b74u, 0x329d48d1u, 0xb4093a7fu, 0x7f55e9dau, 0x6250d962u, 0xa90c0ac7u, 0x2f987869u, 0xe4c4abccu
+};
+
+static const unsigned lodepng_crc32_table6[256] = {
+ 0x00000000u, 0xa6770bb4u, 0x979f1129u, 0x31e81a9du, 0xf44f2413u, 0x52382fa7u, 0x63d0353au, 0xc5a73e8eu,
+ 0x33ef4e67u, 0x959845d3u, 0xa4705f4eu, 0x020754fau, 0xc7a06a74u, 0x61d761c0u, 0x503f7b5du, 0xf64870e9u,
+ 0x67de9cceu, 0xc1a9977au, 0xf0418de7u, 0x56368653u, 0x9391b8ddu, 0x35e6b369u, 0x040ea9f4u, 0xa279a240u,
+ 0x5431d2a9u, 0xf246d91du, 0xc3aec380u, 0x65d9c834u, 0xa07ef6bau, 0x0609fd0eu, 0x37e1e793u, 0x9196ec27u,
+ 0xcfbd399cu, 0x69ca3228u, 0x582228b5u, 0xfe552301u, 0x3bf21d8fu, 0x9d85163bu, 0xac6d0ca6u, 0x0a1a0712u,
+ 0xfc5277fbu, 0x5a257c4fu, 0x6bcd66d2u, 0xcdba6d66u, 0x081d53e8u, 0xae6a585cu, 0x9f8242c1u, 0x39f54975u,
+ 0xa863a552u, 0x0e14aee6u, 0x3ffcb47bu, 0x998bbfcfu, 0x5c2c8141u, 0xfa5b8af5u, 0xcbb39068u, 0x6dc49bdcu,
+ 0x9b8ceb35u, 0x3dfbe081u, 0x0c13fa1cu, 0xaa64f1a8u, 0x6fc3cf26u, 0xc9b4c492u, 0xf85cde0fu, 0x5e2bd5bbu,
+ 0x440b7579u, 0xe27c7ecdu, 0xd3946450u, 0x75e36fe4u, 0xb044516au, 0x16335adeu, 0x27db4043u, 0x81ac4bf7u,
+ 0x77e43b1eu, 0xd19330aau, 0xe07b2a37u, 0x460c2183u, 0x83ab1f0du, 0x25dc14b9u, 0x14340e24u, 0xb2430590u,
+ 0x23d5e9b7u, 0x85a2e203u, 0xb44af89eu, 0x123df32au, 0xd79acda4u, 0x71edc610u, 0x4005dc8du, 0xe672d739u,
+ 0x103aa7d0u, 0xb64dac64u, 0x87a5b6f9u, 0x21d2bd4du, 0xe47583c3u, 0x42028877u, 0x73ea92eau, 0xd59d995eu,
+ 0x8bb64ce5u, 0x2dc14751u, 0x1c295dccu, 0xba5e5678u, 0x7ff968f6u, 0xd98e6342u, 0xe86679dfu, 0x4e11726bu,
+ 0xb8590282u, 0x1e2e0936u, 0x2fc613abu, 0x89b1181fu, 0x4c162691u, 0xea612d25u, 0xdb8937b8u, 0x7dfe3c0cu,
+ 0xec68d02bu, 0x4a1fdb9fu, 0x7bf7c102u, 0xdd80cab6u, 0x1827f438u, 0xbe50ff8cu, 0x8fb8e511u, 0x29cfeea5u,
+ 0xdf879e4cu, 0x79f095f8u, 0x48188f65u, 0xee6f84d1u, 0x2bc8ba5fu, 0x8dbfb1ebu, 0xbc57ab76u, 0x1a20a0c2u,
+ 0x8816eaf2u, 0x2e61e146u, 0x1f89fbdbu, 0xb9fef06fu, 0x7c59cee1u, 0xda2ec555u, 0xebc6dfc8u, 0x4db1d47cu,
+ 0xbbf9a495u, 0x1d8eaf21u, 0x2c66b5bcu, 0x8a11be08u, 0x4fb68086u, 0xe9c18b32u, 0xd82991afu, 0x7e5e9a1bu,
+ 0xefc8763cu, 0x49bf7d88u, 0x78576715u, 0xde206ca1u, 0x1b87522fu, 0xbdf0599bu, 0x8c184306u, 0x2a6f48b2u,
+ 0xdc27385bu, 0x7a5033efu, 0x4bb82972u, 0xedcf22c6u, 0x28681c48u, 0x8e1f17fcu, 0xbff70d61u, 0x198006d5u,
+ 0x47abd36eu, 0xe1dcd8dau, 0xd034c247u, 0x7643c9f3u, 0xb3e4f77du, 0x1593fcc9u, 0x247be654u, 0x820cede0u,
+ 0x74449d09u, 0xd23396bdu, 0xe3db8c20u, 0x45ac8794u, 0x800bb91au, 0x267cb2aeu, 0x1794a833u, 0xb1e3a387u,
+ 0x20754fa0u, 0x86024414u, 0xb7ea5e89u, 0x119d553du, 0xd43a6bb3u, 0x724d6007u, 0x43a57a9au, 0xe5d2712eu,
+ 0x139a01c7u, 0xb5ed0a73u, 0x840510eeu, 0x22721b5au, 0xe7d525d4u, 0x41a22e60u, 0x704a34fdu, 0xd63d3f49u,
+ 0xcc1d9f8bu, 0x6a6a943fu, 0x5b828ea2u, 0xfdf58516u, 0x3852bb98u, 0x9e25b02cu, 0xafcdaab1u, 0x09baa105u,
+ 0xfff2d1ecu, 0x5985da58u, 0x686dc0c5u, 0xce1acb71u, 0x0bbdf5ffu, 0xadcafe4bu, 0x9c22e4d6u, 0x3a55ef62u,
+ 0xabc30345u, 0x0db408f1u, 0x3c5c126cu, 0x9a2b19d8u, 0x5f8c2756u, 0xf9fb2ce2u, 0xc813367fu, 0x6e643dcbu,
+ 0x982c4d22u, 0x3e5b4696u, 0x0fb35c0bu, 0xa9c457bfu, 0x6c636931u, 0xca146285u, 0xfbfc7818u, 0x5d8b73acu,
+ 0x03a0a617u, 0xa5d7ada3u, 0x943fb73eu, 0x3248bc8au, 0xf7ef8204u, 0x519889b0u, 0x6070932du, 0xc6079899u,
+ 0x304fe870u, 0x9638e3c4u, 0xa7d0f959u, 0x01a7f2edu, 0xc400cc63u, 0x6277c7d7u, 0x539fdd4au, 0xf5e8d6feu,
+ 0x647e3ad9u, 0xc209316du, 0xf3e12bf0u, 0x55962044u, 0x90311ecau, 0x3646157eu, 0x07ae0fe3u, 0xa1d90457u,
+ 0x579174beu, 0xf1e67f0au, 0xc00e6597u, 0x66796e23u, 0xa3de50adu, 0x05a95b19u, 0x34414184u, 0x92364a30u
+};
+
+static const unsigned lodepng_crc32_table7[256] = {
+ 0x00000000u, 0xccaa009eu, 0x4225077du, 0x8e8f07e3u, 0x844a0efau, 0x48e00e64u, 0xc66f0987u, 0x0ac50919u,
+ 0xd3e51bb5u, 0x1f4f1b2bu, 0x91c01cc8u, 0x5d6a1c56u, 0x57af154fu, 0x9b0515d1u, 0x158a1232u, 0xd92012acu,
+ 0x7cbb312bu, 0xb01131b5u, 0x3e9e3656u, 0xf23436c8u, 0xf8f13fd1u, 0x345b3f4fu, 0xbad438acu, 0x767e3832u,
+ 0xaf5e2a9eu, 0x63f42a00u, 0xed7b2de3u, 0x21d12d7du, 0x2b142464u, 0xe7be24fau, 0x69312319u, 0xa59b2387u,
+ 0xf9766256u, 0x35dc62c8u, 0xbb53652bu, 0x77f965b5u, 0x7d3c6cacu, 0xb1966c32u, 0x3f196bd1u, 0xf3b36b4fu,
+ 0x2a9379e3u, 0xe639797du, 0x68b67e9eu, 0xa41c7e00u, 0xaed97719u, 0x62737787u, 0xecfc7064u, 0x205670fau,
+ 0x85cd537du, 0x496753e3u, 0xc7e85400u, 0x0b42549eu, 0x01875d87u, 0xcd2d5d19u, 0x43a25afau, 0x8f085a64u,
+ 0x562848c8u, 0x9a824856u, 0x140d4fb5u, 0xd8a74f2bu, 0xd2624632u, 0x1ec846acu, 0x9047414fu, 0x5ced41d1u,
+ 0x299dc2edu, 0xe537c273u, 0x6bb8c590u, 0xa712c50eu, 0xadd7cc17u, 0x617dcc89u, 0xeff2cb6au, 0x2358cbf4u,
+ 0xfa78d958u, 0x36d2d9c6u, 0xb85dde25u, 0x74f7debbu, 0x7e32d7a2u, 0xb298d73cu, 0x3c17d0dfu, 0xf0bdd041u,
+ 0x5526f3c6u, 0x998cf358u, 0x1703f4bbu, 0xdba9f425u, 0xd16cfd3cu, 0x1dc6fda2u, 0x9349fa41u, 0x5fe3fadfu,
+ 0x86c3e873u, 0x4a69e8edu, 0xc4e6ef0eu, 0x084cef90u, 0x0289e689u, 0xce23e617u, 0x40ace1f4u, 0x8c06e16au,
+ 0xd0eba0bbu, 0x1c41a025u, 0x92cea7c6u, 0x5e64a758u, 0x54a1ae41u, 0x980baedfu, 0x1684a93cu, 0xda2ea9a2u,
+ 0x030ebb0eu, 0xcfa4bb90u, 0x412bbc73u, 0x8d81bcedu, 0x8744b5f4u, 0x4beeb56au, 0xc561b289u, 0x09cbb217u,
+ 0xac509190u, 0x60fa910eu, 0xee7596edu, 0x22df9673u, 0x281a9f6au, 0xe4b09ff4u, 0x6a3f9817u, 0xa6959889u,
+ 0x7fb58a25u, 0xb31f8abbu, 0x3d908d58u, 0xf13a8dc6u, 0xfbff84dfu, 0x37558441u, 0xb9da83a2u, 0x7570833cu,
+ 0x533b85dau, 0x9f918544u, 0x111e82a7u, 0xddb48239u, 0xd7718b20u, 0x1bdb8bbeu, 0x95548c5du, 0x59fe8cc3u,
+ 0x80de9e6fu, 0x4c749ef1u, 0xc2fb9912u, 0x0e51998cu, 0x04949095u, 0xc83e900bu, 0x46b197e8u, 0x8a1b9776u,
+ 0x2f80b4f1u, 0xe32ab46fu, 0x6da5b38cu, 0xa10fb312u, 0xabcaba0bu, 0x6760ba95u, 0xe9efbd76u, 0x2545bde8u,
+ 0xfc65af44u, 0x30cfafdau, 0xbe40a839u, 0x72eaa8a7u, 0x782fa1beu, 0xb485a120u, 0x3a0aa6c3u, 0xf6a0a65du,
+ 0xaa4de78cu, 0x66e7e712u, 0xe868e0f1u, 0x24c2e06fu, 0x2e07e976u, 0xe2ade9e8u, 0x6c22ee0bu, 0xa088ee95u,
+ 0x79a8fc39u, 0xb502fca7u, 0x3b8dfb44u, 0xf727fbdau, 0xfde2f2c3u, 0x3148f25du, 0xbfc7f5beu, 0x736df520u,
+ 0xd6f6d6a7u, 0x1a5cd639u, 0x94d3d1dau, 0x5879d144u, 0x52bcd85du, 0x9e16d8c3u, 0x1099df20u, 0xdc33dfbeu,
+ 0x0513cd12u, 0xc9b9cd8cu, 0x4736ca6fu, 0x8b9ccaf1u, 0x8159c3e8u, 0x4df3c376u, 0xc37cc495u, 0x0fd6c40bu,
+ 0x7aa64737u, 0xb60c47a9u, 0x3883404au, 0xf42940d4u, 0xfeec49cdu, 0x32464953u, 0xbcc94eb0u, 0x70634e2eu,
+ 0xa9435c82u, 0x65e95c1cu, 0xeb665bffu, 0x27cc5b61u, 0x2d095278u, 0xe1a352e6u, 0x6f2c5505u, 0xa386559bu,
+ 0x061d761cu, 0xcab77682u, 0x44387161u, 0x889271ffu, 0x825778e6u, 0x4efd7878u, 0xc0727f9bu, 0x0cd87f05u,
+ 0xd5f86da9u, 0x19526d37u, 0x97dd6ad4u, 0x5b776a4au, 0x51b26353u, 0x9d1863cdu, 0x1397642eu, 0xdf3d64b0u,
+ 0x83d02561u, 0x4f7a25ffu, 0xc1f5221cu, 0x0d5f2282u, 0x079a2b9bu, 0xcb302b05u, 0x45bf2ce6u, 0x89152c78u,
+ 0x50353ed4u, 0x9c9f3e4au, 0x121039a9u, 0xdeba3937u, 0xd47f302eu, 0x18d530b0u, 0x965a3753u, 0x5af037cdu,
+ 0xff6b144au, 0x33c114d4u, 0xbd4e1337u, 0x71e413a9u, 0x7b211ab0u, 0xb78b1a2eu, 0x39041dcdu, 0xf5ae1d53u,
+ 0x2c8e0fffu, 0xe0240f61u, 0x6eab0882u, 0xa201081cu, 0xa8c40105u, 0x646e019bu, 0xeae10678u, 0x264b06e6u
+};
+
+/* Computes the cyclic redundancy check as used by PNG chunks*/
unsigned lodepng_crc32(const unsigned char* data, size_t length) {
+ /*Using the Slicing by Eight algorithm*/
unsigned r = 0xffffffffu;
- size_t i;
- for(i = 0; i < length; ++i) {
- r = lodepng_crc32_table[(r ^ data[i]) & 0xffu] ^ (r >> 8u);
+ while(length >= 8) {
+ r = lodepng_crc32_table7[(data[0] ^ (r & 0xffu))] ^
+ lodepng_crc32_table6[(data[1] ^ ((r >> 8) & 0xffu))] ^
+ lodepng_crc32_table5[(data[2] ^ ((r >> 16) & 0xffu))] ^
+ lodepng_crc32_table4[(data[3] ^ ((r >> 24) & 0xffu))] ^
+ lodepng_crc32_table3[data[4]] ^
+ lodepng_crc32_table2[data[5]] ^
+ lodepng_crc32_table1[data[6]] ^
+ lodepng_crc32_table0[data[7]];
+ data += 8;
+ length -= 8;
+ }
+ while(length--) {
+ r = lodepng_crc32_table0[(r ^ *data++) & 0xffu] ^ (r >> 8);
}
return r ^ 0xffffffffu;
}
-#else /* !LODEPNG_NO_COMPILE_CRC */
+#else /* LODEPNG_COMPILE_CRC */
+/*in this case, the function is only declared here, and must be defined externally
+so that it will be linked in.
+
+Example implementation that uses a much smaller lookup table for memory constrained cases:
+
+unsigned lodepng_crc32(const unsigned char* data, size_t length) {
+ unsigned r = 0xffffffffu;
+ static const unsigned table[16] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ while(length--) {
+ r = table[(r ^ *data) & 0xf] ^ (r >> 4);
+ r = table[(r ^ (*data >> 4)) & 0xf] ^ (r >> 4);
+ data++;
+ }
+ return r ^ 0xffffffffu;
+}
+*/
unsigned lodepng_crc32(const unsigned char* data, size_t length);
-#endif /* !LODEPNG_NO_COMPILE_CRC */
+#endif /* LODEPNG_COMPILE_CRC */
/* ////////////////////////////////////////////////////////////////////////// */
/* / Reading and writing PNG color channel bits / */
@@ -2464,7 +2734,7 @@ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream,
/* ////////////////////////////////////////////////////////////////////////// */
unsigned lodepng_chunk_length(const unsigned char* chunk) {
- return lodepng_read32bitInt(&chunk[0]);
+ return lodepng_read32bitInt(chunk);
}
void lodepng_chunk_type(char type[5], const unsigned char* chunk) {
@@ -2514,34 +2784,32 @@ void lodepng_chunk_generate_crc(unsigned char* chunk) {
}
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*/
+ size_t available_size = (size_t)(end - chunk);
+ if(chunk >= end || available_size < 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;
- result = chunk + total_chunk_length;
- if(result < chunk) return end; /*pointer overflow*/
- return result;
+ if(total_chunk_length > available_size) return end; /*outside of range*/
+ return chunk + total_chunk_length;
}
}
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*/
+ size_t available_size = (size_t)(end - chunk);
+ if(chunk >= end || available_size < 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;
- result = chunk + total_chunk_length;
- if(result < chunk) return end; /*pointer overflow*/
- return result;
+ if(total_chunk_length > available_size) return end; /*outside of range*/
+ return chunk + total_chunk_length;
}
}
@@ -3051,6 +3319,9 @@ void lodepng_info_init(LodePNGInfo* info) {
info->iccp_name = NULL;
info->iccp_profile = NULL;
+ info->sbit_defined = 0;
+ info->sbit_r = info->sbit_g = info->sbit_b = info->sbit_a = 0;
+
LodePNGUnknownChunks_init(info);
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
}
@@ -3945,7 +4216,7 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out,
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_cleanup(mode_out); /*clears palette, keeps the above set colortype and bitdepth fields as-is*/
lodepng_color_mode_copy(mode_out, mode_in);
}
} else /*8-bit or 16-bit per channel*/ {
@@ -3966,15 +4237,14 @@ static unsigned auto_choose_color(LodePNGColorMode* mode_out,
#endif /* #ifdef LODEPNG_COMPILE_ENCODER */
-/*
-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.
-*/
-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);
+/*Paeth predictor, used by PNG filter type 4*/
+static unsigned char paethPredictor(unsigned char a, unsigned char b, unsigned char c) {
+ /* the subtractions of unsigned char cast it to a signed type.
+ With gcc, short is faster than int, with clang int is as fast (as of april 2023)*/
+ short pa = (b - c) < 0 ? -(b - c) : (b - c);
+ short pb = (a - c) < 0 ? -(a - c) : (a - c);
+ /* writing it out like this compiles to something faster than introducing a temp variable*/
+ short pc = (a + b - c - c) < 0 ? -(a + b - c - c) : (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 (pc < pa) ? c : a;
@@ -4135,10 +4405,9 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
too much code. Whether this speeds up anything depends on compiler and settings. */
if(bytewidth >= 4) {
for(; i + 3 < length; i += 4, j += 4) {
- unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
- unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
- unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
- unsigned char s3 = scanline[i + 3], r3 = recon[j + 3], p3 = precon[i + 3];
+ 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];
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
@@ -4146,17 +4415,18 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
}
} else if(bytewidth >= 3) {
for(; i + 2 < length; i += 3, j += 3) {
- unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
- unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
- unsigned char s2 = scanline[i + 2], r2 = recon[j + 2], p2 = precon[i + 2];
+ 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];
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
recon[i + 2] = s2 + ((r2 + p2) >> 1u);
}
} else if(bytewidth >= 2) {
for(; i + 1 < length; i += 2, j += 2) {
- unsigned char s0 = scanline[i + 0], r0 = recon[j + 0], p0 = precon[i + 0];
- unsigned char s1 = scanline[i + 1], r1 = recon[j + 1], p1 = precon[i + 1];
+ 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];
recon[i + 0] = s0 + ((r0 + p0) >> 1u);
recon[i + 1] = s1 + ((r1 + p1) >> 1u);
}
@@ -4170,47 +4440,108 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan
break;
case 4:
if(precon) {
- size_t j = 0;
- 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 is also possible but that
- adds too much code. Whether this speeds up anything depends on compiler and settings. */
- if(bytewidth >= 4) {
- for(; i + 3 < length; i += 4, j += 4) {
- 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);
+ /* Unroll independent paths of this predictor. Whether this speeds up
+ anything depends on compiler and settings. */
+ if(bytewidth == 8) {
+ unsigned char a0, b0 = 0, c0, d0 = 0, a1, b1 = 0, c1, d1 = 0;
+ unsigned char a2, b2 = 0, c2, d2 = 0, a3, b3 = 0, c3, d3 = 0;
+ unsigned char a4, b4 = 0, c4, d4 = 0, a5, b5 = 0, c5, d5 = 0;
+ unsigned char a6, b6 = 0, c6, d6 = 0, a7, b7 = 0, c7, d7 = 0;
+ for(i = 0; i + 7 < length; i += 8) {
+ c0 = b0; c1 = b1; c2 = b2; c3 = b3;
+ c4 = b4; c5 = b5; c6 = b6; c7 = b7;
+ b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2]; b3 = precon[i + 3];
+ b4 = precon[i + 4]; b5 = precon[i + 5]; b6 = precon[i + 6]; b7 = precon[i + 7];
+ a0 = d0; a1 = d1; a2 = d2; a3 = d3;
+ a4 = d4; a5 = d5; a6 = d6; a7 = d7;
+ d0 = scanline[i + 0] + paethPredictor(a0, b0, c0);
+ d1 = scanline[i + 1] + paethPredictor(a1, b1, c1);
+ d2 = scanline[i + 2] + paethPredictor(a2, b2, c2);
+ d3 = scanline[i + 3] + paethPredictor(a3, b3, c3);
+ d4 = scanline[i + 4] + paethPredictor(a4, b4, c4);
+ d5 = scanline[i + 5] + paethPredictor(a5, b5, c5);
+ d6 = scanline[i + 6] + paethPredictor(a6, b6, c6);
+ d7 = scanline[i + 7] + paethPredictor(a7, b7, c7);
+ recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2; recon[i + 3] = d3;
+ recon[i + 4] = d4; recon[i + 5] = d5; recon[i + 6] = d6; recon[i + 7] = d7;
}
- } else if(bytewidth >= 3) {
- for(; i + 2 < length; i += 3, j += 3) {
- 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 == 6) {
+ unsigned char a0, b0 = 0, c0, d0 = 0, a1, b1 = 0, c1, d1 = 0;
+ unsigned char a2, b2 = 0, c2, d2 = 0, a3, b3 = 0, c3, d3 = 0;
+ unsigned char a4, b4 = 0, c4, d4 = 0, a5, b5 = 0, c5, d5 = 0;
+ for(i = 0; i + 5 < length; i += 6) {
+ c0 = b0; c1 = b1; c2 = b2;
+ c3 = b3; c4 = b4; c5 = b5;
+ b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2];
+ b3 = precon[i + 3]; b4 = precon[i + 4]; b5 = precon[i + 5];
+ a0 = d0; a1 = d1; a2 = d2;
+ a3 = d3; a4 = d4; a5 = d5;
+ d0 = scanline[i + 0] + paethPredictor(a0, b0, c0);
+ d1 = scanline[i + 1] + paethPredictor(a1, b1, c1);
+ d2 = scanline[i + 2] + paethPredictor(a2, b2, c2);
+ d3 = scanline[i + 3] + paethPredictor(a3, b3, c3);
+ d4 = scanline[i + 4] + paethPredictor(a4, b4, c4);
+ d5 = scanline[i + 5] + paethPredictor(a5, b5, c5);
+ recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2;
+ recon[i + 3] = d3; recon[i + 4] = d4; recon[i + 5] = d5;
}
- } else if(bytewidth >= 2) {
- for(; i + 1 < length; i += 2, j += 2) {
- 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);
+ } else if(bytewidth == 4) {
+ unsigned char a0, b0 = 0, c0, d0 = 0, a1, b1 = 0, c1, d1 = 0;
+ unsigned char a2, b2 = 0, c2, d2 = 0, a3, b3 = 0, c3, d3 = 0;
+ for(i = 0; i + 3 < length; i += 4) {
+ c0 = b0; c1 = b1; c2 = b2; c3 = b3;
+ b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2]; b3 = precon[i + 3];
+ a0 = d0; a1 = d1; a2 = d2; a3 = d3;
+ d0 = scanline[i + 0] + paethPredictor(a0, b0, c0);
+ d1 = scanline[i + 1] + paethPredictor(a1, b1, c1);
+ d2 = scanline[i + 2] + paethPredictor(a2, b2, c2);
+ d3 = scanline[i + 3] + paethPredictor(a3, b3, c3);
+ recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2; recon[i + 3] = d3;
+ }
+ } else if(bytewidth == 3) {
+ unsigned char a0, b0 = 0, c0, d0 = 0;
+ unsigned char a1, b1 = 0, c1, d1 = 0;
+ unsigned char a2, b2 = 0, c2, d2 = 0;
+ for(i = 0; i + 2 < length; i += 3) {
+ c0 = b0; c1 = b1; c2 = b2;
+ b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2];
+ a0 = d0; a1 = d1; a2 = d2;
+ d0 = scanline[i + 0] + paethPredictor(a0, b0, c0);
+ d1 = scanline[i + 1] + paethPredictor(a1, b1, c1);
+ d2 = scanline[i + 2] + paethPredictor(a2, b2, c2);
+ recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2;
+ }
+ } else if(bytewidth == 2) {
+ unsigned char a0, b0 = 0, c0, d0 = 0;
+ unsigned char a1, b1 = 0, c1, d1 = 0;
+ for(i = 0; i + 1 < length; i += 2) {
+ c0 = b0; c1 = b1;
+ b0 = precon[i + 0];
+ b1 = precon[i + 1];
+ a0 = d0; a1 = d1;
+ d0 = scanline[i + 0] + paethPredictor(a0, b0, c0);
+ d1 = scanline[i + 1] + paethPredictor(a1, b1, c1);
+ recon[i + 0] = d0;
+ recon[i + 1] = d1;
+ }
+ } else if(bytewidth == 1) {
+ unsigned char a, b = 0, c, d = 0;
+ for(i = 0; i != length; ++i) {
+ c = b;
+ b = precon[i];
+ a = d;
+ d = scanline[i] + paethPredictor(a, b, c);
+ recon[i] = d;
+ }
+ } else {
+ /* Normally not a possible case, but this would handle it correctly */
+ for(i = 0; i != bytewidth; ++i) {
+ recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/
}
}
-
- for(; i != length; ++i, ++j) {
- recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[j]));
+ /* finish any remaining bytes */
+ for(; i != length; ++i) {
+ recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
}
} else {
size_t j = 0;
@@ -4732,6 +5063,47 @@ static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings*
if(!error && !info->iccp_profile_size) error = 100; /*invalid ICC profile size*/
return error;
}
+
+/*significant bits chunk (sBIT)*/
+static unsigned readChunk_sBIT(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) {
+ unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth;
+ if(info->color.colortype == LCT_GREY) {
+ /*error: this chunk must be 1 bytes for grayscale image*/
+ if(chunkLength != 1) return 114;
+ if(data[0] == 0 || data[0] > bitdepth) return 115;
+ info->sbit_defined = 1;
+ info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/
+ } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) {
+ /*error: this chunk must be 3 bytes for RGB and palette image*/
+ if(chunkLength != 3) return 114;
+ if(data[0] == 0 || data[1] == 0 || data[2] == 0) return 115;
+ if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth) return 115;
+ info->sbit_defined = 1;
+ info->sbit_r = data[0];
+ info->sbit_g = data[1];
+ info->sbit_b = data[2];
+ } else if(info->color.colortype == LCT_GREY_ALPHA) {
+ /*error: this chunk must be 2 byte for grayscale with alpha image*/
+ if(chunkLength != 2) return 114;
+ if(data[0] == 0 || data[1] == 0) return 115;
+ if(data[0] > bitdepth || data[1] > bitdepth) return 115;
+ info->sbit_defined = 1;
+ info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/
+ info->sbit_a = data[1];
+ } else if(info->color.colortype == LCT_RGBA) {
+ /*error: this chunk must be 4 bytes for grayscale image*/
+ if(chunkLength != 4) return 114;
+ if(data[0] == 0 || data[1] == 0 || data[2] == 0 || data[3] == 0) return 115;
+ if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth || data[3] > bitdepth) return 115;
+ info->sbit_defined = 1;
+ info->sbit_r = data[0];
+ info->sbit_g = data[1];
+ info->sbit_b = data[2];
+ info->sbit_a = data[3];
+ }
+
+ return 0; /* OK */
+}
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
@@ -4746,7 +5118,7 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
chunkLength = lodepng_chunk_length(chunk);
if(chunkLength > 2147483647) return 63;
data = lodepng_chunk_data_const(chunk);
- if(data + chunkLength + 4 > in + insize) return 30;
+ if(chunkLength + 12 > insize - pos) return 30;
if(lodepng_chunk_type_equals(chunk, "PLTE")) {
error = readChunk_PLTE(&state->info_png.color, data, chunkLength);
@@ -4773,6 +5145,8 @@ unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos,
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, "sBIT")) {
+ error = readChunk_sBIT(&state->info_png, data, chunkLength);
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
} else {
/* unhandled chunk is ok (is not an error) */
@@ -4791,7 +5165,7 @@ 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;
+ const unsigned char* chunk; /*points to beginning of next chunk*/
unsigned char* idat; /*the data from idat chunks, zlib compressed*/
size_t idatsize = 0;
unsigned char* scanlines = 0;
@@ -4827,14 +5201,15 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
while(!IEND && !state->error) {
unsigned chunkLength;
const unsigned char* data; /*the data in the chunk*/
+ size_t pos = (size_t)(chunk - in);
- /*error: size of the in buffer too small to contain next chunk*/
- if((size_t)((chunk - in) + 12) > insize || chunk < in) {
+ /*error: next chunk out of bounds of the in buffer*/
+ if(chunk < in || pos + 12 > insize) {
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 12 bytes for length, chunk type and CRC*/
chunkLength = lodepng_chunk_length(chunk);
/*error: chunk length larger than the max PNG chunk size*/
if(chunkLength > 2147483647) {
@@ -4842,8 +5217,8 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
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(pos + (size_t)chunkLength + 12 > insize || pos + (size_t)chunkLength + 12 < pos) {
+ CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk (or int overflow)*/
}
data = lodepng_chunk_data_const(chunk);
@@ -4917,6 +5292,9 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
} else if(lodepng_chunk_type_equals(chunk, "iCCP")) {
state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength);
if(state->error) break;
+ } else if(lodepng_chunk_type_equals(chunk, "sBIT")) {
+ state->error = readChunk_sBIT(&state->info_png, 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)*/
@@ -5152,6 +5530,10 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) {
unsigned char* chunk;
size_t i, j = 8;
+ if(info->palettesize == 0 || info->palettesize > 256) {
+ return 68; /*invalid palette size, it is only allowed to be 1-256*/
+ }
+
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE"));
for(i = 0; i != info->palettesize; ++i) {
@@ -5407,6 +5789,42 @@ static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, LodePNGCom
return error;
}
+static unsigned addChunk_sBIT(ucvector* out, const LodePNGInfo* info) {
+ unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth;
+ unsigned char* chunk = 0;
+ if(info->color.colortype == LCT_GREY) {
+ if(info->sbit_r == 0 || info->sbit_r > bitdepth) return 115;
+ CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "sBIT"));
+ chunk[8] = info->sbit_r;
+ } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) {
+ if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0) return 115;
+ if(info->sbit_r > bitdepth || info->sbit_g > bitdepth || info->sbit_b > bitdepth) return 115;
+ CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 3, "sBIT"));
+ chunk[8] = info->sbit_r;
+ chunk[9] = info->sbit_g;
+ chunk[10] = info->sbit_b;
+ } else if(info->color.colortype == LCT_GREY_ALPHA) {
+ if(info->sbit_r == 0 || info->sbit_a == 0) return 115;
+ if(info->sbit_r > bitdepth || info->sbit_a > bitdepth) return 115;
+ CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "sBIT"));
+ chunk[8] = info->sbit_r;
+ chunk[9] = info->sbit_a;
+ } else if(info->color.colortype == LCT_RGBA) {
+ if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0 || info->sbit_a == 0 ||
+ info->sbit_r > bitdepth || info->sbit_g > bitdepth ||
+ info->sbit_b > bitdepth || info->sbit_a > bitdepth) {
+ return 115;
+ }
+ CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "sBIT"));
+ chunk[8] = info->sbit_r;
+ chunk[9] = info->sbit_g;
+ chunk[10] = info->sbit_b;
+ chunk[11] = info->sbit_a;
+ }
+ if(chunk) lodepng_chunk_generate_crc(chunk);
+ return 0;
+}
+
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,
@@ -5852,8 +6270,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
ucvector outv = ucvector_init(NULL, 0);
LodePNGInfo info;
const LodePNGInfo* info_png = &state->info_png;
+ LodePNGColorMode auto_color;
lodepng_info_init(&info);
+ lodepng_color_mode_init(&auto_color);
/*provide some proper output values if error will happen*/
*out = 0;
@@ -5863,6 +6283,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
/*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)) {
+ /*this error is returned even if auto_convert is enabled and thus encoder could
+ generate the palette by itself: while allowing this could be possible in theory,
+ it may complicate the code or edge cases, and always requiring to give a palette
+ when setting this color type is a simpler contract*/
state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/
goto cleanup;
}
@@ -5883,6 +6307,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
lodepng_info_copy(&info, &state->info_png);
if(state->encoder.auto_convert) {
LodePNGColorStats stats;
+ unsigned allow_convert = 1;
lodepng_color_stats_init(&stats);
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
if(info_png->iccp_defined &&
@@ -5904,23 +6329,85 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
/*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;
}
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
- state->error = auto_choose_color(&info.color, &state->info_raw, &stats);
+ state->error = auto_choose_color(&auto_color, &state->info_raw, &stats);
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)) {
- state->error = 104;
- goto cleanup;
+ if(info_png->sbit_defined) {
+ /*if sbit is defined, due to strict requirements of which sbit values can be present for which color modes,
+ auto_convert can't be done in many cases. However, do support a few cases here.
+ TODO: more conversions may be possible, and it may also be possible to get a more appropriate color type out of
+ auto_choose_color if knowledge about sbit is used beforehand
+ */
+ unsigned sbit_max = LODEPNG_MAX(LODEPNG_MAX(LODEPNG_MAX(info_png->sbit_r, info_png->sbit_g),
+ info_png->sbit_b), info_png->sbit_a);
+ unsigned equal = (!info_png->sbit_g || info_png->sbit_g == info_png->sbit_r)
+ && (!info_png->sbit_b || info_png->sbit_b == info_png->sbit_r)
+ && (!info_png->sbit_a || info_png->sbit_a == info_png->sbit_r);
+ allow_convert = 0;
+ if(info.color.colortype == LCT_PALETTE &&
+ auto_color.colortype == LCT_PALETTE) {
+ /* input and output are palette, and in this case it may happen that palette data is
+ expected to be copied from info_raw into the info_png */
+ allow_convert = 1;
+ }
+ /*going from 8-bit RGB to palette (or 16-bit as long as sbit_max <= 8) is possible
+ since both are 8-bit RGB for sBIT's purposes*/
+ if(info.color.colortype == LCT_RGB &&
+ auto_color.colortype == LCT_PALETTE && sbit_max <= 8) {
+ allow_convert = 1;
+ }
+ /*going from 8-bit RGBA to palette is also ok but only if sbit_a is exactly 8*/
+ if(info.color.colortype == LCT_RGBA && auto_color.colortype == LCT_PALETTE &&
+ info_png->sbit_a == 8 && sbit_max <= 8) {
+ allow_convert = 1;
+ }
+ /*going from 16-bit RGB(A) to 8-bit RGB(A) is ok if all sbit values are <= 8*/
+ if((info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA) && info.color.bitdepth == 16 &&
+ auto_color.colortype == info.color.colortype && auto_color.bitdepth == 8 &&
+ sbit_max <= 8) {
+ allow_convert = 1;
+ }
+ /*going to less channels is ok if all bit values are equal (all possible values in sbit,
+ as well as the chosen bitdepth of the result). Due to how auto_convert works,
+ we already know that auto_color.colortype has less than or equal amount of channels than
+ info.colortype. Palette is not used here. This conversion is not allowed if
+ info_png->sbit_r < auto_color.bitdepth, because specifically for alpha, non-presence of
+ an sbit value heavily implies that alpha's bit depth is equal to the PNG bit depth (rather
+ than the bit depths set in the r, g and b sbit values, by how the PNG specification describes
+ handling tRNS chunk case with sBIT), so be conservative here about ignoring user input.*/
+ if(info.color.colortype != LCT_PALETTE && auto_color.colortype != LCT_PALETTE &&
+ equal && info_png->sbit_r == auto_color.bitdepth) {
+ allow_convert = 1;
}
}
+#endif
+ if(state->encoder.force_palette) {
+ if(info.color.colortype != LCT_GREY && info.color.colortype != LCT_GREY_ALPHA &&
+ (auto_color.colortype == LCT_GREY || auto_color.colortype == LCT_GREY_ALPHA)) {
+ /*user speficially forced a PLTE palette, so cannot convert to grayscale types because
+ the PNG specification only allows writing a suggested palette in PLTE for truecolor types*/
+ allow_convert = 0;
+ }
+ }
+ if(allow_convert) {
+ lodepng_color_mode_copy(&info.color, &auto_color);
+#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)) {
+ state->error = 104;
+ goto cleanup;
+ }
+ }
#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */
+ }
}
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
if(info_png->iccp_defined) {
@@ -5991,6 +6478,10 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
state->error = addChunk_cHRM(&outv, &info);
if(state->error) goto cleanup;
}
+ if(info_png->sbit_defined) {
+ state->error = addChunk_sBIT(&outv, &info);
+ if(state->error) goto cleanup;
+ }
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
/*PLTE*/
if(info.color.colortype == LCT_PALETTE) {
@@ -6097,6 +6588,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
cleanup:
lodepng_info_cleanup(&info);
lodepng_free(data);
+ lodepng_color_mode_cleanup(&auto_color);
/*instead of cleaning the vector up, give it to the output*/
*out = outv.data;
@@ -6291,6 +6783,8 @@ const char* lodepng_error_text(unsigned code) {
/*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";
+ case 114: return "sBIT chunk has wrong size for the color type of the image";
+ case 115: return "sBIT value out of range";
}
return "unknown error code";
}
@@ -6327,7 +6821,7 @@ unsigned decompress(std::vector& out, const unsigned char* in, si
size_t buffersize = 0;
unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings);
if(buffer) {
- out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;
@@ -6346,7 +6840,7 @@ unsigned compress(std::vector& out, const unsigned char* in, size
size_t buffersize = 0;
unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings);
if(buffer) {
- out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;
@@ -6391,7 +6885,7 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const
state.info_raw.colortype = colortype;
state.info_raw.bitdepth = bitdepth;
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
- out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ out.insert(out.end(), buffer, &buffer[buffersize]);
}
lodepng_free(buffer);
return error;
@@ -6409,7 +6903,7 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h,
unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
if(buffer && !error) {
size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
- out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ out.insert(out.end(), buffer, &buffer[buffersize]);
}
lodepng_free(buffer);
return error;
@@ -6441,7 +6935,7 @@ unsigned encode(std::vector& out, const unsigned char* in, unsign
size_t buffersize;
unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
if(buffer) {
- out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;
@@ -6461,7 +6955,7 @@ unsigned encode(std::vector& out,
size_t buffersize;
unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
if(buffer) {
- out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ out.insert(out.end(), buffer, &buffer[buffersize]);
lodepng_free(buffer);
}
return error;
diff --git a/src/lodepng.h b/src/lodepng.h
index 3e1da92..81d4985 100644
--- a/src/lodepng.h
+++ b/src/lodepng.h
@@ -1,7 +1,7 @@
/*
-LodePNG version 20210627
+LodePNG version 20230410
-Copyright (c) 2005-2021 Lode Vandevenne
+Copyright (c) 2005-2023 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -35,43 +35,50 @@ The following #defines are used to create code sections. They can be disabled
to disable code sections, which can give faster compile time and smaller binary.
The "NO_COMPILE" defines are designed to be used to pass as defines to the
compiler command to disable them without modifying this header, e.g.
--DLODEPNG_NO_COMPILE_ZLIB for gcc.
-In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to
-allow implementing a custom lodepng_crc32.
+-DLODEPNG_NO_COMPILE_ZLIB for gcc or clang.
*/
/*deflate & zlib. If disabled, you must specify alternative zlib functions in
the custom_zlib field of the compress and decompress settings*/
#ifndef LODEPNG_NO_COMPILE_ZLIB
+/*pass -DLODEPNG_NO_COMPILE_ZLIB to the compiler to disable this, or comment out LODEPNG_COMPILE_ZLIB below*/
#define LODEPNG_COMPILE_ZLIB
#endif
/*png encoder and png decoder*/
#ifndef LODEPNG_NO_COMPILE_PNG
+/*pass -DLODEPNG_NO_COMPILE_PNG to the compiler to disable this, or comment out LODEPNG_COMPILE_PNG below*/
#define LODEPNG_COMPILE_PNG
#endif
/*deflate&zlib decoder and png decoder*/
#ifndef LODEPNG_NO_COMPILE_DECODER
+/*pass -DLODEPNG_NO_COMPILE_DECODER to the compiler to disable this, or comment out LODEPNG_COMPILE_DECODER below*/
#define LODEPNG_COMPILE_DECODER
#endif
/*deflate&zlib encoder and png encoder*/
#ifndef LODEPNG_NO_COMPILE_ENCODER
+/*pass -DLODEPNG_NO_COMPILE_ENCODER to the compiler to disable this, or comment out LODEPNG_COMPILE_ENCODER below*/
#define LODEPNG_COMPILE_ENCODER
#endif
/*the optional built in harddisk file loading and saving functions*/
#ifndef LODEPNG_NO_COMPILE_DISK
+/*pass -DLODEPNG_NO_COMPILE_DISK to the compiler to disable this, or comment out LODEPNG_COMPILE_DISK below*/
#define LODEPNG_COMPILE_DISK
#endif
/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
+/*pass -DLODEPNG_NO_COMPILE_ANCILLARY_CHUNKS to the compiler to disable this,
+or comment out LODEPNG_COMPILE_ANCILLARY_CHUNKS below*/
#define LODEPNG_COMPILE_ANCILLARY_CHUNKS
#endif
/*ability to convert error numerical codes to English text string*/
#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT
+/*pass -DLODEPNG_NO_COMPILE_ERROR_TEXT to the compiler to disable this,
+or comment out LODEPNG_COMPILE_ERROR_TEXT below*/
#define LODEPNG_COMPILE_ERROR_TEXT
#endif
@@ -79,12 +86,27 @@ the custom_zlib field of the compress and decompress settings*/
you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your
source files with custom allocators.*/
#ifndef LODEPNG_NO_COMPILE_ALLOCATORS
+/*pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler to disable the built-in ones,
+or comment out LODEPNG_COMPILE_ALLOCATORS below*/
#define LODEPNG_COMPILE_ALLOCATORS
#endif
+/*Disable built-in CRC function, in that case a custom implementation of
+lodepng_crc32 must be defined externally so that it can be linked in.
+The default built-in CRC code comes with 8KB of lookup tables, so for memory constrained environment you may want it
+disabled and provide a much smaller implementation externally as said above. You can find such an example implementation
+in a comment in the lodepng.c(pp) file in the 'else' case of the searchable LODEPNG_COMPILE_CRC section.*/
+#ifndef LODEPNG_NO_COMPILE_CRC
+/*pass -DLODEPNG_NO_COMPILE_CRC to the compiler to disable the built-in one,
+or comment out LODEPNG_COMPILE_CRC below*/
+#define LODEPNG_COMPILE_CRC
+#endif
+
/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/
#ifdef __cplusplus
#ifndef LODEPNG_NO_COMPILE_CPP
+/*pass -DLODEPNG_NO_COMPILE_CPP to the compiler to disable C++ (not needed if a C-only compiler),
+or comment out LODEPNG_COMPILE_CPP below*/
#define LODEPNG_COMPILE_CPP
#endif
#endif
@@ -374,8 +396,10 @@ typedef struct LodePNGColorMode {
The alpha channels must be set as well, set them to 255 for opaque images.
- When decoding, by default you can ignore this palette, since LodePNG already
- fills the palette colors in the pixels of the raw RGBA output.
+ When decoding, with the default settings you can ignore this palette, since
+ LodePNG already fills the palette colors in the pixels of the raw RGBA output,
+ but when decoding to the original PNG color mode it is needed to reconstruct
+ the colors.
The palette is only supported for color type 3.
*/
@@ -465,10 +489,12 @@ typedef struct LodePNGInfo {
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.
+ in background_g and background_b are then unused. The decoder will set them
+ equal to background_r, the encoder ignores them in this case.
- So when decoding, you may get these in a different color mode than the one you requested
- for the raw pixels.
+ When decoding, you may get these in a different color mode than the one you requested
+ for the raw pixels: the colortype and bitdepth defined by info_png.color, that is the
+ ones defined in the header of the PNG image, are used.
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
@@ -535,7 +561,7 @@ typedef struct LodePNGInfo {
unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/
/*
- Color profile related chunks: gAMA, cHRM, sRGB, iCPP
+ Color profile related chunks: gAMA, cHRM, sRGB, iCPP, sBIT
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
@@ -598,6 +624,45 @@ typedef struct LodePNGInfo {
unsigned char* iccp_profile;
unsigned iccp_profile_size; /* The size of iccp_profile in bytes */
+ /*
+ sBIT chunk: significant bits. Optional metadata, only set this if needed.
+
+ If defined, these values give the bit depth of the original data. Since PNG only stores 1, 2, 4, 8 or 16-bit
+ per channel data, the significant bits value can be used to indicate the original encoded data has another
+ sample depth, such as 10 or 12.
+
+ Encoders using this value, when storing the pixel data, should use the most significant bits
+ of the data to store the original bits, and use a good sample depth scaling method such as
+ "left bit replication" to fill in the least significant bits, rather than fill zeroes.
+
+ Decoders using this value, if able to work with data that's e.g. 10-bit or 12-bit, should right
+ shift the data to go back to the original bit depth, but decoders are also allowed to ignore
+ sbit and work e.g. with the 8-bit or 16-bit data from the PNG directly, since thanks
+ to the encoder contract, the values encoded in PNG are in valid range for the PNG bit depth.
+
+ For grayscale images, sbit_g and sbit_b are not used, and for images that don't use color
+ type RGBA or grayscale+alpha, sbit_a is not used (it's not used even for palette images with
+ translucent palette values, or images with color key). The values that are used must be
+ greater than zero and smaller than or equal to the PNG bit depth.
+
+ The color type from the header in the PNG image defines these used and unused fields: if
+ decoding with a color mode conversion, such as always decoding to RGBA, this metadata still
+ only uses the color type of the original PNG, and may e.g. lack the alpha channel info
+ if the PNG was RGB. When encoding with auto_convert (as well as without), also always the
+ color model defined in info_png.color determines this.
+
+ NOTE: enabling sbit can hurt compression, because the encoder can then not always use
+ auto_convert to choose a more optimal color mode for the data, because the PNG format has
+ strict requirements for the allowed sbit values in combination with color modes.
+ For example, setting these fields to 10-bit will force the encoder to keep using a 16-bit per channel
+ color mode, even if the pixel data would in fact fit in a more efficient 8-bit mode.
+ */
+ unsigned sbit_defined; /*is significant bits given? if not, the values below are unused*/
+ unsigned sbit_r; /*red or gray component of significant bits*/
+ unsigned sbit_g; /*green component of significant bits*/
+ unsigned sbit_b; /*blue component of significant bits*/
+ unsigned sbit_a; /*alpha component of significant bits*/
+
/* End of color profile related chunks */
@@ -770,7 +835,11 @@ typedef struct LodePNGEncoderSettings {
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.*/
+ If colortype is 3, PLTE is always created. If color type is explicitely set
+ to a grayscale type (1 or 4), this is not done and is ignored. If enabling this,
+ a palette must be present in the info_png.
+ NOTE: enabling this may worsen compression if auto_convert is used to choose
+ optimal color mode, because it cannot use grayscale color modes in this case*/
unsigned force_palette;
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
/*add LodePNG identifier and version as a text chunk, for debugging*/
@@ -824,8 +893,8 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h,
#endif /*LODEPNG_COMPILE_DECODER*/
/*
-Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it
-read in the state. Returns error code on failure.
+Reads one metadata chunk (other than IHDR, which is handled by lodepng_inspect)
+of the PNG file and outputs what it read in the state. Returns error code on failure.
Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const
to find the desired chunk type, and if non null use lodepng_inspect_chunk (with
chunk_pointer - start_of_file as pos).
@@ -1103,7 +1172,7 @@ TODO:
[.] 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)
+[ ] support all public PNG chunk types (almost done except 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
@@ -1230,18 +1299,16 @@ The following features are supported by the decoder:
gAMA: RGB gamma correction
iCCP: ICC color profile
sRGB: rendering intent
+ sBIT: significant bits
1.2. features not supported
---------------------------
-The following features are _not_ supported:
+The following features are not (yet) 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
+*) The hIST and sPLT public chunks are not (yet) supported but treated as unknown chunks
2. C and C++ version
@@ -1845,6 +1912,9 @@ symbol.
Not all changes are listed here, the commit history in github lists more:
https://github.com/lvandeve/lodepng
+*) 10 apr 2023: faster CRC32 implementation, but with larger lookup table.
+*) 13 jun 2022: added support for the sBIT chunk.
+*) 09 jan 2022: minor decoder speed improvements.
*) 27 jun 2021: added warnings that file reading/writing functions don't support
wide-character filenames (support for this is not planned, opening files is
not the core part of PNG decoding/decoding and is platform dependent).
@@ -2015,5 +2085,5 @@ Domain: gmail dot com.
Account: lode dot vandevenne.
-Copyright (c) 2005-2021 Lode Vandevenne
+Copyright (c) 2005-2022 Lode Vandevenne
*/
diff --git a/src/qoi.h b/src/qoi.h
index 69063eb..6734ac4 100644
--- a/src/qoi.h
+++ b/src/qoi.h
@@ -1,39 +1,16 @@
/*
+Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org
+SPDX-License-Identifier: MIT
+
+
QOI - The "Quite OK Image" format for fast, lossless image compression
-Dominic Szablewski - https://phoboslab.org
-
-
--- LICENSE: The MIT License(MIT)
-
-Copyright(c) 2021 Dominic Szablewski
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files(the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions :
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-
-- About
-QOI encodes and decodes images in a lossless format. An encoded QOI image is
-usually around 10--30% larger than a decently optimized PNG image.
-
-QOI outperforms simpler PNG encoders in compression ratio and performance. QOI
-images are typically 20% smaller than PNGs written with stbi_image. Encoding is
-25-50x faster and decoding is 3-4x faster than stbi_image or libpng.
+QOI encodes and decodes images in a lossless format. Compared to stb_image and
+stb_image_write QOI offers 20x-50x faster encoding, 3x-4x faster decoding and
+20% better compression.
-- Synopsis
@@ -48,7 +25,7 @@ images are typically 20% smaller than PNGs written with stbi_image. Encoding is
// the input pixel data.
qoi_write("image_new.qoi", rgba_pixels, &(qoi_desc){
.width = 1920,
- .height = 1080,
+ .height = 1080,
.channels = 4,
.colorspace = QOI_SRGB
});
@@ -77,14 +54,14 @@ QOI_NO_STDIO before including this library.
This library uses malloc() and free(). To supply your own malloc implementation
you can define QOI_MALLOC and QOI_FREE before including this library.
-This library uses memset() to zero-initialize the index. To supply your own
+This library uses memset() to zero-initialize the index. To supply your own
implementation you can define QOI_ZEROARR before including this library.
-- Data Format
-A QOI file has a 14 byte header, followed by any number of data "chunks" and 8
-zero-bytes to mark the end of the data stream.
+A QOI file has a 14 byte header, followed by any number of data "chunks" and an
+8-byte end marker.
struct qoi_header_t {
char magic[4]; // magic bytes "qoif"
@@ -94,33 +71,36 @@ struct qoi_header_t {
uint8_t colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
};
-The decoder and encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous
-pixel value. Pixels are either encoded as
+Images are encoded row by row, left to right, top to bottom. The decoder and
+encoder start with {r: 0, g: 0, b: 0, a: 255} as the previous pixel value. An
+image is complete when all pixels specified by width * height have been covered.
+
+Pixels are encoded as
- a run of the previous pixel
- an index into an array of previously seen pixels
- a difference to the previous pixel value in r,g,b
- full r,g,b or r,g,b,a values
-The color channels are assumed to not be premultiplied with the alpha channel
+The color channels are assumed to not be premultiplied with the alpha channel
("un-premultiplied alpha").
-A running array[64] (zero-initialized) of previously seen pixel values is
+A running array[64] (zero-initialized) of previously seen pixel values is
maintained by the encoder and decoder. Each pixel that is seen by the encoder
and decoder is put into this array at the position formed by a hash function of
the color value. In the encoder, if the pixel value at the index matches the
-current pixel, this index position is written to the stream as QOI_OP_INDEX.
+current pixel, this index position is written to the stream as QOI_OP_INDEX.
The hash function for the index is:
index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64
-Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The
-bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All
+Each chunk starts with a 2- or 8-bit tag, followed by a number of data bits. The
+bit length of chunks is divisible by 8 - i.e. all chunks are byte aligned. All
values encoded in these data bits have the most significant bit on the left.
The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the
presence of an 8-bit tag first.
-The byte stream is padded with 8 zero-bytes at the end.
+The byte stream's end is marked with 7 0x00 bytes followed a single 0x01 byte.
The possible chunks are:
@@ -135,8 +115,11 @@ The possible chunks are:
2-bit tag b00
6-bit index into the color index array: 0..63
+A valid encoder must not issue 2 or more consecutive QOI_OP_INDEX chunks to the
+same index. QOI_OP_RUN should be used instead.
-.- QOI_OP_DIFF -----------.
+
+.- QOI_OP_DIFF -----------.
| Byte[0] |
| 7 6 5 4 3 2 1 0 |
|-------+-----+-----+-----|
@@ -147,14 +130,16 @@ The possible chunks are:
2-bit green channel difference from the previous pixel between -2..1
2-bit blue channel difference from the previous pixel between -2..1
-The difference to the current channel values are using a wraparound operation,
+The difference to the current channel values are using a wraparound operation,
so "1 - 2" will result in 255, while "255 + 1" will result in 0.
-Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
+Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
0 (b00). 1 is stored as 3 (b11).
+The alpha value remains unchanged from the previous pixel.
-.- QOI_OP_LUMA -------------------------------------.
+
+.- QOI_OP_LUMA -------------------------------------.
| Byte[0] | Byte[1] |
| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 |
|-------+-----------------+-------------+-----------|
@@ -165,18 +150,20 @@ Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
4-bit red channel difference minus green channel difference -8..7
4-bit blue channel difference minus green channel difference -8..7
-The green channel is used to indicate the general direction of change and is
-encoded in 6 bits. The red and green channels (dr and db) base their diffs off
+The green channel is used to indicate the general direction of change and is
+encoded in 6 bits. The red and blue channels (dr and db) base their diffs off
of the green channel difference and are encoded in 4 bits. I.e.:
- dr_dg = (last_px.r - cur_px.r) - (last_px.g - cur_px.g)
- db_dg = (last_px.b - cur_px.b) - (last_px.g - cur_px.g)
+ dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g)
+ db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g)
-The difference to the current channel values are using a wraparound operation,
+The difference to the current channel values are using a wraparound operation,
so "10 - 13" will result in 253, while "250 + 7" will result in 1.
-Values are stored as unsigned integers with a bias of 32 for the green channel
+Values are stored as unsigned integers with a bias of 32 for the green channel
and a bias of 8 for the red and blue channel.
+The alpha value remains unchanged from the previous pixel.
+
.- QOI_OP_RUN ------------.
| Byte[0] |
@@ -187,8 +174,8 @@ and a bias of 8 for the red and blue channel.
2-bit tag b11
6-bit run-length repeating the previous pixel: 1..62
-The run-length is stored with a bias of 1. Note that the run-lengths 63 and 64
-(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and
+The run-length is stored with a bias of -1. Note that the run-lengths 63 and 64
+(b111110 and b111111) are illegal as they are occupied by the QOI_OP_RGB and
QOI_OP_RGBA tags.
@@ -203,6 +190,8 @@ QOI_OP_RGBA tags.
8-bit green channel value
8-bit blue channel value
+The alpha value remains unchanged from the previous pixel.
+
.- QOI_OP_RGBA ---------------------------------------------------.
| Byte[0] | Byte[1] | Byte[2] | Byte[3] | Byte[4] |
@@ -216,13 +205,6 @@ QOI_OP_RGBA tags.
8-bit blue channel value
8-bit alpha channel value
-
-The byte stream is padded at the end with 8 zero bytes. Since the longest legal
-chunk is 5 bytes (QOI_OP_RGBA), with this padding it is possible to check for an
-overrun only once per decode loop iteration. These 0x00 bytes also mark the end
-of the data stream, as an encoder should never produce 8 consecutive zero bytes
-within the stream.
-
*/
@@ -236,17 +218,17 @@ Header - Public functions */
extern "C" {
#endif
-/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
-It describes either the input format (for qoi_write and qoi_encode), or is
+/* A pointer to a qoi_desc struct has to be supplied to all of qoi's functions.
+It describes either the input format (for qoi_write and qoi_encode), or is
filled with the description read from the file header (for qoi_read and
qoi_decode).
-The colorspace in this qoi_desc is an enum where
+The colorspace in this qoi_desc is an enum where
0 = sRGB, i.e. gamma scaled RGB channels and a linear alpha channel
1 = all channels are linear
-You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
+You may use the constants QOI_SRGB or QOI_LINEAR. The colorspace is purely
informative. It will be saved to the file header, but does not affect
-en-/decoding in any way. */
+how chunks are en-/decoded. */
#define QOI_SRGB 0
#define QOI_LINEAR 1
@@ -260,11 +242,11 @@ typedef struct {
#ifndef QOI_NO_STDIO
-/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file
-system. The qoi_desc struct must be filled with the image width, height,
-number of channels (3 = RGB, 4 = RGBA) and the colorspace.
+/* Encode raw RGB or RGBA pixels into a QOI image and write it to the file
+system. The qoi_desc struct must be filled with the image width, height,
+number of channels (3 = RGB, 4 = RGBA) and the colorspace.
-The function returns 0 on failure (invalid parameters, or fopen or malloc
+The function returns 0 on failure (invalid parameters, or fopen or malloc
failed) or the number of bytes written on success. */
int qoi_write(const char *filename, const void *data, const qoi_desc *desc);
@@ -275,7 +257,7 @@ number of channels from the file header is used. If channels is 3 or 4 the
output format will be forced into this number of channels.
The function either returns NULL on failure (invalid data, or malloc or fopen
-failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
+failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
will be filled with the description from the file header.
The returned pixel data should be free()d after use. */
@@ -287,8 +269,8 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels);
/* Encode raw RGB or RGBA pixels into a QOI image in memory.
-The function either returns NULL on failure (invalid parameters or malloc
-failed) or a pointer to the encoded data on success. On success the out_len
+The function either returns NULL on failure (invalid parameters or malloc
+failed) or a pointer to the encoded data on success. On success the out_len
is set to the size in bytes of the encoded data.
The returned qoi data should be free()d after use. */
@@ -298,8 +280,8 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len);
/* Decode a QOI image from memory.
-The function either returns NULL on failure (invalid parameters or malloc
-failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
+The function either returns NULL on failure (invalid parameters or malloc
+failed) or a pointer to the decoded pixels. On success, the qoi_desc struct
is filled with the description from the file header.
The returned pixel data should be free()d after use. */
@@ -342,21 +324,28 @@ Implementation */
(((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \
((unsigned int)'i') << 8 | ((unsigned int)'f'))
#define QOI_HEADER_SIZE 14
-#define QOI_PADDING 8
+
+/* 2GB is the max file size that this implementation can safely handle. We guard
+against anything larger than that, assuming the worst case with 5 bytes per
+pixel, rounded down to a nice clean value. 400 million pixels ought to be
+enough for anybody. */
+#define QOI_PIXELS_MAX ((unsigned int)400000000)
typedef union {
struct { unsigned char r, g, b, a; } rgba;
unsigned int v;
} qoi_rgba_t;
-void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) {
+static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1};
+
+static void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) {
bytes[(*p)++] = (0xff000000 & v) >> 24;
bytes[(*p)++] = (0x00ff0000 & v) >> 16;
bytes[(*p)++] = (0x0000ff00 & v) >> 8;
bytes[(*p)++] = (0x000000ff & v);
}
-unsigned int qoi_read_32(const unsigned char *bytes, int *p) {
+static unsigned int qoi_read_32(const unsigned char *bytes, int *p) {
unsigned int a = bytes[(*p)++];
unsigned int b = bytes[(*p)++];
unsigned int c = bytes[(*p)++];
@@ -376,14 +365,15 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
data == NULL || out_len == NULL || desc == NULL ||
desc->width == 0 || desc->height == 0 ||
desc->channels < 3 || desc->channels > 4 ||
- desc->colorspace > 2
+ desc->colorspace > 1 ||
+ desc->height >= QOI_PIXELS_MAX / desc->width
) {
return NULL;
}
- max_size =
- desc->width * desc->height * (desc->channels + 1) +
- QOI_HEADER_SIZE + QOI_PADDING;
+ max_size =
+ desc->width * desc->height * (desc->channels + 1) +
+ QOI_HEADER_SIZE + sizeof(qoi_padding);
p = 0;
bytes = (unsigned char *) QOI_MALLOC(max_size);
@@ -408,19 +398,18 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
px_prev.rgba.b = 0;
px_prev.rgba.a = 255;
px = px_prev;
-
+
px_len = desc->width * desc->height * desc->channels;
px_end = px_len - desc->channels;
channels = desc->channels;
for (px_pos = 0; px_pos < px_len; px_pos += channels) {
+ px.rgba.r = pixels[px_pos + 0];
+ px.rgba.g = pixels[px_pos + 1];
+ px.rgba.b = pixels[px_pos + 2];
+
if (channels == 4) {
- px = *(qoi_rgba_t *)(pixels + px_pos);
- }
- else {
- px.rgba.r = pixels[px_pos + 0];
- px.rgba.g = pixels[px_pos + 1];
- px.rgba.b = pixels[px_pos + 2];
+ px.rgba.a = pixels[px_pos + 3];
}
if (px.v == px_prev.v) {
@@ -456,14 +445,14 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
if (
vr > -3 && vr < 2 &&
- vg > -3 && vg < 2 &&
+ vg > -3 && vg < 2 &&
vb > -3 && vb < 2
) {
bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2);
}
else if (
- vg_r > -9 && vg_r < 8 &&
- vg > -33 && vg < 32 &&
+ vg_r > -9 && vg_r < 8 &&
+ vg > -33 && vg < 32 &&
vg_b > -9 && vg_b < 8
) {
bytes[p++] = QOI_OP_LUMA | (vg + 32);
@@ -488,8 +477,8 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
px_prev = px;
}
- for (i = 0; i < QOI_PADDING; i++) {
- bytes[p++] = 0;
+ for (i = 0; i < (int)sizeof(qoi_padding); i++) {
+ bytes[p++] = qoi_padding[i];
}
*out_len = p;
@@ -502,13 +491,13 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
unsigned char *pixels;
qoi_rgba_t index[64];
qoi_rgba_t px;
- int px_len, chunks_len, px_pos;
+ int px_len, chunks_len, px_pos;
int p = 0, run = 0;
if (
data == NULL || desc == NULL ||
(channels != 0 && channels != 3 && channels != 4) ||
- size < QOI_HEADER_SIZE + QOI_PADDING
+ size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding)
) {
return NULL;
}
@@ -522,10 +511,11 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
desc->colorspace = bytes[p++];
if (
- desc->width == 0 || desc->height == 0 ||
+ desc->width == 0 || desc->height == 0 ||
desc->channels < 3 || desc->channels > 4 ||
- desc->colorspace > 2 ||
- header_magic != QOI_MAGIC
+ desc->colorspace > 1 ||
+ header_magic != QOI_MAGIC ||
+ desc->height >= QOI_PIXELS_MAX / desc->width
) {
return NULL;
}
@@ -546,7 +536,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
px.rgba.b = 0;
px.rgba.a = 255;
- chunks_len = size - QOI_PADDING;
+ chunks_len = size - (int)sizeof(qoi_padding);
for (px_pos = 0; px_pos < px_len; px_pos += channels) {
if (run > 0) {
run--;
@@ -587,13 +577,12 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
index[QOI_COLOR_HASH(px) % 64] = px;
}
- if (channels == 4) {
- *(qoi_rgba_t*)(pixels + px_pos) = px;
- }
- else {
- pixels[px_pos + 0] = px.rgba.r;
- pixels[px_pos + 1] = px.rgba.g;
- pixels[px_pos + 2] = px.rgba.b;
+ pixels[px_pos + 0] = px.rgba.r;
+ pixels[px_pos + 1] = px.rgba.g;
+ pixels[px_pos + 2] = px.rgba.b;
+
+ if (channels == 4) {
+ pixels[px_pos + 3] = px.rgba.a;
}
}
@@ -616,11 +605,11 @@ int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
if (!encoded) {
fclose(f);
return 0;
- }
-
+ }
+
fwrite(encoded, 1, size, f);
fclose(f);
-
+
QOI_FREE(encoded);
return size;
}
@@ -636,6 +625,10 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
fseek(f, 0, SEEK_END);
size = ftell(f);
+ if (size <= 0) {
+ fclose(f);
+ return NULL;
+ }
fseek(f, 0, SEEK_SET);
data = QOI_MALLOC(size);
@@ -653,4 +646,4 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
}
#endif /* QOI_NO_STDIO */
-#endif /* QOI_IMPLEMENTATION */
\ No newline at end of file
+#endif /* QOI_IMPLEMENTATION */
diff --git a/src/stb_image.h b/src/stb_image.h
index 35ed429..5e807a0 100644
--- a/src/stb_image.h
+++ b/src/stb_image.h
@@ -1,4 +1,4 @@
-/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb
+/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
Do this:
@@ -48,6 +48,7 @@ LICENSE
RECENT REVISION HISTORY:
+ 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
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
@@ -108,7 +109,7 @@ RECENT REVISION HISTORY:
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
+ Josh Tobin Neil Bickford 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
@@ -140,7 +141,7 @@ RECENT REVISION HISTORY:
// // ... 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)
+// stbi_image_free(data);
//
// Standard parameters:
// int *x -- outputs image width in pixels
@@ -635,7 +636,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#endif
#endif
-#ifdef _MSC_VER
+#if defined(_MSC_VER) || defined(__SYMBIAN32__)
typedef unsigned short stbi__uint16;
typedef signed short stbi__int16;
typedef unsigned int stbi__uint32;
@@ -1063,6 +1064,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
}
#endif
+// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow.
+static int stbi__addints_valid(int a, int b)
+{
+ if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow
+ if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0.
+ return a <= INT_MAX - b;
+}
+
+// returns 1 if the product of two signed shorts is valid, 0 on overflow.
+static int stbi__mul2shorts_valid(short a, short b)
+{
+ if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
+ if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
+ if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN
+ return a >= SHRT_MIN / b;
+}
+
// stbi__err - error
// stbi__errpf - error returning pointer to float
// stbi__errpuc - error returning pointer to unsigned char
@@ -1985,9 +2003,12 @@ 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)
+ for (i=0; i < 16; ++i) {
+ for (j=0; j < count[i]; ++j) {
h->size[k++] = (stbi_uc) (i+1);
+ if(k >= 257) return stbi__err("bad size list","Corrupt JPEG");
+ }
+ }
h->size[k] = 0;
// compute actual symbols (from jpeg spec)
@@ -2112,6 +2133,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
// convert the huffman code to the symbol id
c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+ if(c < 0 || c >= 256) // symbol id out of bounds!
+ return -1;
STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
// convert the id to a symbol
@@ -2130,6 +2153,7 @@ 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);
+ if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
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);
@@ -2144,6 +2168,7 @@ 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);
+ if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
k = stbi_lrot(j->code_buffer, n);
j->code_buffer = k & ~stbi__bmask[n];
k &= stbi__bmask[n];
@@ -2155,6 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
{
unsigned int k;
if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+ if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing
k = j->code_buffer;
j->code_buffer <<= 1;
--j->code_bits;
@@ -2192,8 +2218,10 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
memset(data,0,64*sizeof(data[0]));
diff = t ? stbi__extend_receive(j, t) : 0;
+ if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG");
dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc;
+ if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
data[0] = (short) (dc * dequant[0]);
// decode AC components, see JPEG spec
@@ -2207,6 +2235,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
if (r) { // fast-AC path
k += (r >> 4) & 15; // run
s = r & 15; // combined length
+ if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
j->code_buffer <<= s;
j->code_bits -= s;
// decode into unzigzag'd location
@@ -2246,8 +2275,10 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__
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 (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG");
dc = j->img_comp[b].dc_pred + diff;
j->img_comp[b].dc_pred = dc;
+ if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
data[0] = (short) (dc * (1 << j->succ_low));
} else {
// refinement scan for DC coefficient
@@ -2282,6 +2313,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
if (r) { // fast-AC path
k += (r >> 4) & 15; // run
s = r & 15; // combined length
+ if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
j->code_buffer <<= s;
j->code_bits -= s;
zig = stbi__jpeg_dezigzag[k++];
@@ -3102,6 +3134,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
sizes[i] = stbi__get8(z->s);
n += sizes[i];
}
+ if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values!
L -= 17;
if (tc == 0) {
if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
@@ -3351,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
return 1;
}
+static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
+{
+ // some JPEGs have junk at end, skip over it but if we find what looks
+ // like a valid marker, resume there
+ while (!stbi__at_eof(j->s)) {
+ int x = stbi__get8(j->s);
+ while (x == 255) { // might be a marker
+ if (stbi__at_eof(j->s)) return STBI__MARKER_none;
+ x = stbi__get8(j->s);
+ if (x != 0x00 && x != 0xff) {
+ // not a stuffed zero or lead-in to another marker, looks
+ // like an actual marker, return it
+ return x;
+ }
+ // stuffed zero has x=0 now which ends the loop, meaning we go
+ // back to regular scan loop.
+ // repeated 0xff keeps trying to read the next byte of the marker.
+ }
+ }
+ return STBI__MARKER_none;
+}
+
// decode image to YCbCr format
static int stbi__decode_jpeg_image(stbi__jpeg *j)
{
@@ -3367,25 +3422,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
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;
- }
- }
+ j->marker = stbi__skip_jpeg_junk_at_end(j);
// 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 (STBI__RESTART(m))
+ m = stbi__get_marker(j);
} 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");
+ m = stbi__get_marker(j);
} else {
- if (!stbi__process_marker(j, m)) return 0;
+ if (!stbi__process_marker(j, m)) return 1;
+ m = stbi__get_marker(j);
}
- m = stbi__get_marker(j);
}
if (j->progressive)
stbi__jpeg_finish(j);
@@ -3976,6 +4028,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re
unsigned char* result;
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
if (!j) return stbi__errpuc("outofmem", "Out of memory");
+ memset(j, 0, sizeof(stbi__jpeg));
STBI_NOTUSED(ri);
j->s = s;
stbi__setup_jpeg(j);
@@ -3989,6 +4042,7 @@ 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");
+ memset(j, 0, sizeof(stbi__jpeg));
j->s = s;
stbi__setup_jpeg(j);
r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
@@ -4014,6 +4068,7 @@ 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");
+ memset(j, 0, sizeof(stbi__jpeg));
j->s = s;
result = stbi__jpeg_info_raw(j, x, y, comp);
STBI_FREE(j);
@@ -4256,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
a->zout = zout;
return 1;
}
+ if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
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");
+ if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data
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");
@@ -4955,7 +5011,7 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
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)
+STBIDEF void stbi_set_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;
@@ -5064,14 +5120,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
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
}
+ // even with SCAN_header, have to scan to see if we have a tRNS
break;
}
@@ -5103,6 +5158,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
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;
+ // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
+ if (scan == STBI__SCAN_header) { ++s->img_n; return 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 {
@@ -5115,7 +5172,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
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 (scan == STBI__SCAN_header) {
+ // header scan definitely stops at first IDAT
+ if (pal_img_n)
+ s->img_n = pal_img_n;
+ return 1;
+ }
+ if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes");
if ((int)(ioff + c.length) < (int)ioff) return 0;
if (ioff + c.length > idata_limit) {
stbi__uint32 idata_limit_old = idata_limit;
@@ -5498,8 +5561,22 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
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");
+ // accept some number of extra bytes after the header, but if the offset points either to before
+ // the header ends or implies a large amount of extra data, reject the file as malformed
+ int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original);
+ int header_limit = 1024; // max we actually read is below 256 bytes currently.
+ int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size.
+ if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) {
+ return stbi__errpuc("bad header", "Corrupt BMP");
+ }
+ // we established that bytes_read_so_far is positive and sensible.
+ // the first half of this test rejects offsets that are either too small positives, or
+ // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn
+ // ensures the number computed in the second half of the test can't overflow.
+ if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) {
+ return stbi__errpuc("bad offset", "Corrupt BMP");
+ } else {
+ stbi__skip(s, info.offset - bytes_read_so_far);
}
}
@@ -7187,12 +7264,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
// 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"); }
+ if ((count == 0) || (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"); }
+ if ((count == 0) || (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);
}
@@ -7446,10 +7523,17 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req
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 (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) {
+ STBI_FREE(out);
+ return stbi__errpuc("bad PNM", "PNM file truncated");
+ }
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 (ri->bits_per_channel == 16) {
+ out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y);
+ } else {
+ 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;
@@ -7486,6 +7570,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c)
while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
value = value*10 + (*c - '0');
*c = (char) stbi__get8(s);
+ if((value > 214748364) || (value == 214748364 && *c > '7'))
+ return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int");
}
return value;
@@ -7516,9 +7602,13 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
stbi__pnm_skip_whitespace(s, &c);
*x = stbi__pnm_getinteger(s, &c); // read width
+ if(*x == 0)
+ return stbi__err("invalid width", "PPM image header had zero or overflowing width");
stbi__pnm_skip_whitespace(s, &c);
*y = stbi__pnm_getinteger(s, &c); // read height
+ if (*y == 0)
+ return stbi__err("invalid width", "PPM image header had zero or overflowing width");
stbi__pnm_skip_whitespace(s, &c);
maxv = stbi__pnm_getinteger(s, &c); // read max value
@@ -7894,4 +7984,4 @@ AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
-*/
\ No newline at end of file
+*/