From 3f6c511a133ab87efabb45f0e46f0fad4118f72f Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Thu, 4 Jun 2015 22:24:37 +0800 Subject: [PATCH] [LodePNG] Update lodepng to version 20150418. --- components/external/lodepng/lodepng.c | 1736 ++++++++++++------------- components/external/lodepng/lodepng.h | 213 ++- 2 files changed, 912 insertions(+), 1037 deletions(-) diff --git a/components/external/lodepng/lodepng.c b/components/external/lodepng/lodepng.c index e9c440eb76..326b952692 100644 --- a/components/external/lodepng/lodepng.c +++ b/components/external/lodepng/lodepng.c @@ -1,7 +1,7 @@ /* -LodePNG version 20131222 +LodePNG version 20150418 -Copyright (c) 2005-2013 Lode Vandevenne +Copyright (c) 2005-2015 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 @@ -30,16 +30,19 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #include "lodepng.h" +#include #include -#include -#include - #ifdef LODEPNG_COMPILE_CPP #include #endif /*LODEPNG_COMPILE_CPP*/ -#define VERSION_STRING "20131222" +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +const char* LODEPNG_VERSION_STRING = "20150418"; /* This source file is built up in the following large parts. The code sections @@ -62,17 +65,17 @@ from here.*/ #ifdef LODEPNG_COMPILE_ALLOCATORS static void* lodepng_malloc(size_t size) { - return rtgui_malloc(size); + return malloc(size); } static void* lodepng_realloc(void* ptr, size_t new_size) { - return rtgui_realloc(ptr, new_size); + return realloc(ptr, new_size); } static void lodepng_free(void* ptr) { - rtgui_free(ptr); + free(ptr); } #else /*LODEPNG_COMPILE_ALLOCATORS*/ void* lodepng_malloc(size_t size); @@ -116,6 +119,13 @@ Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); if(error) return error;\ } +/*Set error var to the error code, and return from the void function.*/ +#define CERROR_RETURN(errorvar, code)\ +{\ + errorvar = code;\ + return;\ +} + /* About uivector, ucvector and string: -All of them wrap dynamic arrays or text strings in a similar way. @@ -142,30 +152,36 @@ static void uivector_cleanup(void* p) } /*returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned uivector_resize(uivector* p, size_t size) +static unsigned uivector_reserve(uivector* p, size_t allocsize) { - if(size * sizeof(unsigned) > p->allocsize) + if(allocsize > p->allocsize) { - size_t newsize = size * sizeof(unsigned) * 2; + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; p->data = (unsigned*)data; - p->size = size; } - else return 0; + else return 0; /*error: not enough memory*/ } - else p->size = size; return 1; } +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) +{ + if(!uivector_reserve(p, size * sizeof(unsigned))) return 0; + p->size = size; + return 1; /*success*/ +} + /*resize and give all new elements the value*/ static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) { size_t oldsize = p->size, i; if(!uivector_resize(p, size)) return 0; - for(i = oldsize; i < size; i++) p->data[i] = value; + for(i = oldsize; i < size; ++i) p->data[i] = value; return 1; } @@ -183,15 +199,6 @@ static unsigned uivector_push_back(uivector* p, unsigned c) p->data[p->size - 1] = c; return 1; } - -/*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/ -static unsigned uivector_copy(uivector* p, const uivector* q) -{ - size_t i; - if(!uivector_resize(p, q->size)) return 0; - for(i = 0; i < q->size; i++) p->data[i] = q->data[i]; - return 1; -} #endif /*LODEPNG_COMPILE_ENCODER*/ #endif /*LODEPNG_COMPILE_ZLIB*/ @@ -206,24 +213,30 @@ 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 allocsize) { - if(size * sizeof(unsigned char) > p->allocsize) + if(allocsize > p->allocsize) { - size_t newsize = size * sizeof(unsigned char) * 2; + size_t newsize = (allocsize > p->allocsize * 2) ? allocsize : (allocsize * 3 / 2); void* data = lodepng_realloc(p->data, newsize); if(data) { p->allocsize = newsize; p->data = (unsigned char*)data; - p->size = size; } else return 0; /*error: not enough memory*/ } - else p->size = size; return 1; } +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) +{ + if(!ucvector_reserve(p, size * sizeof(unsigned char))) return 0; + p->size = size; + return 1; /*success*/ +} + #ifdef LODEPNG_COMPILE_PNG static void ucvector_cleanup(void* p) @@ -245,7 +258,7 @@ static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) { size_t oldsize = p->size, i; if(!ucvector_resize(p, size)) return 0; - for(i = oldsize; i < size; i++) p->data[i] = value; + for(i = oldsize; i < size; ++i) p->data[i] = value; return 1; } #endif /*LODEPNG_COMPILE_DECODER*/ @@ -304,10 +317,10 @@ static void string_cleanup(char** out) static void string_set(char** out, const char* in) { - size_t insize = strlen(in), i = 0; + size_t insize = strlen(in), i; if(string_resize(out, insize)) { - for(i = 0; i < insize; i++) + for(i = 0; i != insize; ++i) { (*out)[i] = in[i]; } @@ -320,7 +333,7 @@ static void string_set(char** out, const char* in) unsigned lodepng_read32bitInt(const unsigned char* buffer) { - return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); } #if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) @@ -350,26 +363,27 @@ static void lodepng_add32bitInt(ucvector* buffer, unsigned value) unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) { - int fd; + FILE* file; long size; /*provide some proper output values if error will happen*/ *out = 0; *outsize = 0; - fd = open(filename, O_RDONLY, 0); - if(fd < 0) return 78; + file = fopen(filename, "rb"); + if(!file) return 78; /*get filesize:*/ - size = lseek(fd, 0 , SEEK_END); - lseek(fd, 0, SEEK_SET); + fseek(file , 0 , SEEK_END); + size = ftell(file); + rewind(file); /*read contents of the file into the vector*/ *outsize = 0; *out = (unsigned char*)lodepng_malloc((size_t)size); - if(size && (*out)) (*outsize) = read(fd, *out, (size_t)size); + if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); - close(fd); + fclose(file); if(!(*out) && size) return 83; /*the above malloc failed*/ return 0; } @@ -377,13 +391,11 @@ unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* fil /*write given buffer to the file, overwriting the file, it doesn't append to it.*/ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) { - int fd; - - fd = open(filename, O_WRONLY, 0); - if(fd < 0) return 79; - - write(fd, (char*)buffer , buffersize); - close(fd); + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); return 0; } @@ -404,19 +416,19 @@ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ - (*bitpointer)++;\ + ++(*bitpointer);\ } static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) { size_t i; - for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); } static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) { size_t i; - for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); + for(i = 0; i != nbits; ++i) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); } #endif /*LODEPNG_COMPILE_ENCODER*/ @@ -427,17 +439,17 @@ static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, uns static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) { unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); - (*bitpointer)++; + ++(*bitpointer); return result; } static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { unsigned result = 0, i; - for(i = 0; i < nbits; i++) + for(i = 0; i != nbits; ++i) { result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; - (*bitpointer)++; + ++(*bitpointer); } return result; } @@ -500,7 +512,7 @@ typedef struct HuffmanTree static void HuffmanTree_draw(HuffmanTree* tree) { std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; - for(size_t i = 0; i < tree->tree1d.size; i++) + for(size_t i = 0; i != tree->tree1d.size; ++i) { if(tree->lengths.data[i]) std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; @@ -542,17 +554,18 @@ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) There is only memory for such good tree currently, if there are more nodes (due to too long length codes), error 55 will happen */ - for(n = 0; n < tree->numcodes * 2; n++) + for(n = 0; n < tree->numcodes * 2; ++n) { tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ } - for(n = 0; n < tree->numcodes; n++) /*the codes*/ + for(n = 0; n < tree->numcodes; ++n) /*the codes*/ { - for(i = 0; i < tree->lengths[n]; i++) /*the bits for this code*/ + for(i = 0; i != tree->lengths[n]; ++i) /*the bits for this code*/ { unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); - if(treepos > tree->numcodes - 2) return 55; /*oversubscribed, see comment in lodepng_error_text*/ + /*oversubscribed, see comment in lodepng_error_text*/ + if(treepos > 2147483647 || treepos + 2 > tree->numcodes) return 55; if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ { if(i + 1 == tree->lengths[n]) /*last bit*/ @@ -564,7 +577,7 @@ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) { /*put address of the next step in here, first that address has to be found of course (it's just nodefilled + 1)...*/ - nodefilled++; + ++nodefilled; /*addresses encoded with numcodes added to it*/ tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; treepos = nodefilled; @@ -574,7 +587,7 @@ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) } } - for(n = 0; n < tree->numcodes * 2; n++) + for(n = 0; n < tree->numcodes * 2; ++n) { if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ } @@ -591,7 +604,8 @@ static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) { uivector blcount; uivector nextcode; - unsigned bits, n, error = 0; + unsigned error = 0; + unsigned bits, n; uivector_init(&blcount); uivector_init(&nextcode); @@ -606,14 +620,14 @@ static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) if(!error) { /*step 1: count number of instances of each code length*/ - for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths[bits]]++; + for(bits = 0; bits != tree->numcodes; ++bits) ++blcount.data[tree->lengths[bits]]; /*step 2: generate the nextcode values*/ - for(bits = 1; bits <= tree->maxbitlen; bits++) + for(bits = 1; bits <= tree->maxbitlen; ++bits) { nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; } /*step 3: generate all the codes*/ - for(n = 0; n < tree->numcodes; n++) + for(n = 0; n != tree->numcodes; ++n) { if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; } @@ -637,7 +651,7 @@ static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* b unsigned i; tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); if(!tree->lengths) return 83; /*alloc fail*/ - for(i = 0; i < numcodes; i++) tree->lengths[i] = bitlen[i]; + for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ tree->maxbitlen = maxbitlen; return HuffmanTree_makeFromLengths2(tree); @@ -645,101 +659,136 @@ static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* b #ifdef LODEPNG_COMPILE_ENCODER -/* -A coin, this is the terminology used for the package-merge algorithm and the -coin collector's problem. This is used to generate the huffman tree. -A coin can be multiple coins (when they're merged) -*/ -typedef struct Coin -{ - uivector symbols; - float weight; /*the sum of all weights in this coin*/ -} Coin; +/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", +Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ -static void coin_init(Coin* c) +/*chain node for boundary package merge*/ +typedef struct BPMNode { - uivector_init(&c->symbols); -} + int weight; /*the sum of all weights in this chain*/ + unsigned index; /*index of this leaf node (called "count" in the paper)*/ + struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ + int in_use; +} BPMNode; -/*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/ -static void coin_cleanup(void* c) +/*lists of chains*/ +typedef struct BPMLists { - uivector_cleanup(&((Coin*)c)->symbols); -} + /*memory pool*/ + unsigned memsize; + BPMNode* memory; + unsigned numfree; + unsigned nextfree; + BPMNode** freelist; + /*two heads of lookahead chains per list*/ + unsigned listsize; + BPMNode** chains0; + BPMNode** chains1; +} BPMLists; -static void coin_copy(Coin* c1, const Coin* c2) +/*creates a new chain node with the given parameters, from the memory in the lists */ +static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) { - c1->weight = c2->weight; - uivector_copy(&c1->symbols, &c2->symbols); -} + unsigned i; + BPMNode* result; -static void add_coins(Coin* c1, const Coin* c2) -{ - size_t i; - for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]); - c1->weight += c2->weight; -} + /*memory full, so garbage collect*/ + if(lists->nextfree >= lists->numfree) + { + /*mark only those that are in use*/ + for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; + for(i = 0; i != lists->listsize; ++i) + { + BPMNode* node; + for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; + for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; + } + /*collect those that are free*/ + lists->numfree = 0; + for(i = 0; i != lists->memsize; ++i) + { + if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; + } + lists->nextfree = 0; + } -static void init_coins(Coin* coins, size_t num) -{ - size_t i; - for(i = 0; i < num; i++) coin_init(&coins[i]); + result = lists->freelist[lists->nextfree++]; + result->weight = weight; + result->index = index; + result->tail = tail; + return result; } -static void cleanup_coins(Coin* coins, size_t num) +static int bpmnode_compare(const void* a, const void* b) { - size_t i; - for(i = 0; i < num; i++) coin_cleanup(&coins[i]); + int wa = ((const BPMNode*)a)->weight; + int wb = ((const BPMNode*)b)->weight; + if(wa < wb) return -1; + if(wa > wb) return 1; + /*make the qsort a stable sort*/ + return ((const BPMNode*)a)->index < ((const BPMNode*)b)->index ? 1 : -1; } -static int coin_compare(const void* a, const void* b) { - float wa = ((const Coin*)a)->weight; - float wb = ((const Coin*)b)->weight; - return wa > wb ? 1 : wa < wb ? -1 : 0; -} - -static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum) +/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ +static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) { - unsigned i; - unsigned j = 0; /*index of present symbols*/ - for(i = 0; i < numcodes; i++) + unsigned lastindex = lists->chains1[c]->index; + + if(c == 0) + { + if(lastindex >= numpresent) return; + lists->chains0[c] = lists->chains1[c]; + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); + } + else { - if(frequencies[i] != 0) /*only include symbols that are present*/ + /*sum of the weights of the head nodes of the previous lookahead chains.*/ + int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; + lists->chains0[c] = lists->chains1[c]; + if(lastindex < numpresent && sum > leaves[lastindex].weight) { - coins[j].weight = frequencies[i] / (float)sum; - uivector_push_back(&coins[j].symbols, i); - j++; + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); + return; + } + lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); + /*in the end we are only interested in the chain of the last list, so no + need to recurse if we're at the last one (this gives measurable speedup)*/ + if(num + 1 < (int)(2 * numpresent - 2)) + { + boundaryPM(lists, leaves, numpresent, c - 1, num); + boundaryPM(lists, leaves, numpresent, c - 1, num); } } - return 0; } unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, size_t numcodes, unsigned maxbitlen) { - unsigned i, j; - size_t sum = 0, numpresent = 0; unsigned error = 0; - Coin* coins; /*the coins of the currently calculated row*/ - Coin* prev_row; /*the previous row of coins*/ - unsigned numcoins; - unsigned coinmem; + unsigned i; + size_t numpresent = 0; /*number of symbols with non-zero frequency*/ + BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + if((1u << maxbitlen) < numcodes) return 80; /*error: represent all symbols*/ + + leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); + if(!leaves) return 83; /*alloc fail*/ - for(i = 0; i < numcodes; i++) + for(i = 0; i != numcodes; ++i) { if(frequencies[i] > 0) { - numpresent++; - sum += frequencies[i]; + leaves[numpresent].weight = frequencies[i]; + leaves[numpresent].index = i; + ++numpresent; } } - for(i = 0; i < numcodes; i++) lengths[i] = 0; + for(i = 0; i != numcodes; ++i) lengths[i] = 0; /*ensure at least two present symbols. There should be at least one symbol - according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To + according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To make these work as well ensure there are at least two symbols. The Package-Merge code below also doesn't work correctly if there's only one symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ @@ -749,87 +798,55 @@ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequen } else if(numpresent == 1) { - for(i = 0; i < numcodes; i++) - { - if(frequencies[i]) - { - lengths[i] = 1; - lengths[i == 0 ? 1 : 0] = 1; - break; - } - } + lengths[leaves[0].index] = 1; + lengths[leaves[0].index == 0 ? 1 : 0] = 1; } else { - /*Package-Merge algorithm represented by coin collector's problem - For every symbol, maxbitlen coins will be created*/ + BPMLists lists; + BPMNode* node; - coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/ - coins = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); - prev_row = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); - if(!coins || !prev_row) - { - lodepng_free(coins); - lodepng_free(prev_row); - return 83; /*alloc fail*/ - } - init_coins(coins, coinmem); - init_coins(prev_row, coinmem); + qsort(leaves, numpresent, sizeof(BPMNode), bpmnode_compare); + + lists.listsize = maxbitlen; + lists.memsize = 2 * maxbitlen * (maxbitlen + 1); + lists.nextfree = 0; + lists.numfree = lists.memsize; + lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); + lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); + lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ - /*first row, lowest denominator*/ - error = append_symbol_coins(coins, frequencies, numcodes, sum); - numcoins = numpresent; - qsort(coins, numcoins, sizeof(Coin), coin_compare); if(!error) { - unsigned numprev = 0; - for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/ - { - unsigned tempnum; - Coin* tempcoins; - /*swap prev_row and coins, and their amounts*/ - tempcoins = prev_row; prev_row = coins; coins = tempcoins; - tempnum = numprev; numprev = numcoins; numcoins = tempnum; + for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; - cleanup_coins(coins, numcoins); - init_coins(coins, numcoins); + bpmnode_create(&lists, leaves[0].weight, 1, 0); + bpmnode_create(&lists, leaves[1].weight, 2, 0); - numcoins = 0; - - /*fill in the merged coins of the previous row*/ - for(i = 0; i + 1 < numprev; i += 2) - { - /*merge prev_row[i] and prev_row[i + 1] into new coin*/ - Coin* coin = &coins[numcoins++]; - coin_copy(coin, &prev_row[i]); - add_coins(coin, &prev_row[i + 1]); - } - /*fill in all the original symbols again*/ - if(j < maxbitlen) - { - error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum); - numcoins += numpresent; - } - qsort(coins, numcoins, sizeof(Coin), coin_compare); + for(i = 0; i != lists.listsize; ++i) + { + lists.chains0[i] = &lists.memory[0]; + lists.chains1[i] = &lists.memory[1]; } - } - if(!error) - { - /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/ - for(i = 0; i < numpresent - 1; i++) + /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ + for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, maxbitlen - 1, i); + + for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) { - Coin* coin = &coins[i]; - for(j = 0; j < coin->symbols.size; j++) lengths[coin->symbols.data[j]]++; + for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; } } - cleanup_coins(coins, coinmem); - lodepng_free(coins); - cleanup_coins(prev_row, coinmem); - lodepng_free(prev_row); + lodepng_free(lists.memory); + lodepng_free(lists.freelist); + lodepng_free(lists.chains0); + lodepng_free(lists.chains1); } + lodepng_free(leaves); return error; } @@ -838,7 +855,7 @@ static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigne size_t mincodes, size_t numcodes, unsigned maxbitlen) { unsigned error = 0; - while(!frequencies[numcodes - 1] && numcodes > mincodes) numcodes--; /*trim zeroes*/ + while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ tree->maxbitlen = maxbitlen; tree->numcodes = (unsigned)numcodes; /*number of symbols*/ tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); @@ -870,10 +887,10 @@ static unsigned generateFixedLitLenTree(HuffmanTree* tree) if(!bitlen) return 83; /*alloc fail*/ /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ - for(i = 0; i <= 143; i++) bitlen[i] = 8; - for(i = 144; i <= 255; i++) bitlen[i] = 9; - for(i = 256; i <= 279; i++) bitlen[i] = 7; - for(i = 280; i <= 287; i++) bitlen[i] = 8; + for(i = 0; i <= 143; ++i) bitlen[i] = 8; + for(i = 144; i <= 255; ++i) bitlen[i] = 9; + for(i = 256; i <= 279; ++i) bitlen[i] = 7; + for(i = 280; i <= 287; ++i) bitlen[i] = 8; error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); @@ -889,7 +906,7 @@ static unsigned generateFixedDistanceTree(HuffmanTree* tree) if(!bitlen) return 83; /*alloc fail*/ /*there are 32 distance codes, but 30-31 are unused*/ - for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen[i] = 5; + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); lodepng_free(bitlen); @@ -914,7 +931,7 @@ static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, the expression below because this is the biggest bottleneck while decoding */ ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; - (*bp)++; + ++(*bp); if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ @@ -953,7 +970,7 @@ 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((*bp) >> 3 >= inlength - 2) return 49; /*error: the bit pointer is or will go past the memory*/ + if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/ /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ HLIT = readBitsFromStream(bp, in, 5) + 257; @@ -962,6 +979,8 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ HCLEN = readBitsFromStream(bp, in, 4) + 4; + if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/ + HuffmanTree_init(&tree_cl); while(!error) @@ -971,7 +990,7 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); - for(i = 0; i < NUM_CODE_LENGTH_CODES; i++) + for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i) { if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ @@ -984,8 +1003,8 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); - for(i = 0; i < NUM_DEFLATE_CODE_SYMBOLS; i++) bitlen_ll[i] = 0; - for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen_d[i] = 0; + for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0; + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0; /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ i = 0; @@ -996,61 +1015,59 @@ static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, { if(i < HLIT) bitlen_ll[i] = code; else bitlen_d[i - HLIT] = code; - i++; + ++i; } else if(code == 16) /*repeat previous*/ { unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ unsigned value; /*set value to the previous code*/ - if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ - if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + if((*bp + 2) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 2); if(i < HLIT + 1) value = bitlen_ll[i - 1]; else value = bitlen_d[i - HLIT - 1]; /*repeat this value in the next lengths*/ - for(n = 0; n < replength; n++) + for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = value; else bitlen_d[i - HLIT] = value; - i++; + ++i; } } else if(code == 17) /*repeat "0" 3-10 times*/ { unsigned replength = 3; /*read in the bits that indicate repeat length*/ - if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ - + if((*bp + 3) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 3); /*repeat this value in the next lengths*/ - for(n = 0; n < replength; n++) + for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = 0; else bitlen_d[i - HLIT] = 0; - i++; + ++i; } } else if(code == 18) /*repeat "0" 11-138 times*/ { unsigned replength = 11; /*read in the bits that indicate repeat length*/ - if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ - + if((*bp + 7) > inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ replength += readBitsFromStream(bp, in, 7); /*repeat this value in the next lengths*/ - for(n = 0; n < replength; n++) + for(n = 0; n < replength; ++n) { if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ if(i < HLIT) bitlen_ll[i] = 0; else bitlen_d[i - HLIT] = 0; - i++; + ++i; } } else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ @@ -1106,13 +1123,10 @@ static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); if(code_ll <= 255) /*literal symbol*/ { - if((*pos) >= out->size) - { - /*reserve more room at once*/ - if(!ucvector_resize(out, ((*pos) + 1) * 2)) ERROR_BREAK(83 /*alloc fail*/); - } - out->data[(*pos)] = (unsigned char)(code_ll); - (*pos)++; + /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/ + if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/); + out->data[*pos] = (unsigned char)code_ll; + ++(*pos); } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { @@ -1125,7 +1139,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size /*part 2: get extra bits and add the value of that to length*/ numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; - if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + if((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ length += readBitsFromStream(bp, in, numextrabits_l); /*part 3: get distance code*/ @@ -1145,26 +1159,23 @@ static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size /*part 4: get extra bits from distance*/ numextrabits_d = DISTANCEEXTRA[code_d]; - if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ - + if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ distance += readBitsFromStream(bp, in, numextrabits_d); /*part 5: fill in all the out[n] values based on the length and dist*/ start = (*pos); if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ backward = start - distance; - if((*pos) + length >= out->size) - { - /*reserve more room at once*/ - if(!ucvector_resize(out, ((*pos) + length) * 2)) ERROR_BREAK(83 /*alloc fail*/); - } - for(forward = 0; forward < length; forward++) - { - out->data[(*pos)] = out->data[backward]; - (*pos)++; - backward++; - if(backward >= start) backward = start - distance; + if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/); + if (distance < length) { + for(forward = 0; forward < length; ++forward) + { + out->data[(*pos)++] = out->data[backward++]; + } + } else { + memcpy(out->data + *pos, out->data + backward, length); + *pos += length; } } else if(code_ll == 256) @@ -1175,7 +1186,7 @@ static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size { /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol (10=no endcode, 11=wrong jump outside of tree)*/ - error = (*bp) > inlength * 8 ? 10 : 11; + error = ((*bp) > inlength * 8) ? 10 : 11; break; } } @@ -1188,28 +1199,26 @@ static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) { - /*go to first boundary of byte*/ size_t p; unsigned LEN, NLEN, n, error = 0; - while(((*bp) & 0x7) != 0) (*bp)++; + + /*go to first boundary of byte*/ + while(((*bp) & 0x7) != 0) ++(*bp); p = (*bp) / 8; /*byte position*/ /*read LEN (2 bytes) and NLEN (2 bytes)*/ - if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/ - LEN = in[p] + 256 * in[p + 1]; p += 2; - NLEN = in[p] + 256 * in[p + 1]; p += 2; + if(p + 4 >= inlength) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256u * in[p + 1]; p += 2; + NLEN = in[p] + 256u * in[p + 1]; p += 2; /*check if 16-bit NLEN is really the one's complement of LEN*/ if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ - if((*pos) + LEN >= out->size) - { - if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ - } + if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ /*read the literal data: LEN bytes are now stored in the out buffer*/ if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ - for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++]; + for(n = 0; n < LEN; ++n) out->data[(*pos)++] = in[p++]; (*bp) = p * 8; @@ -1224,7 +1233,6 @@ static unsigned lodepng_inflatev(ucvector* out, size_t bp = 0; unsigned BFINAL = 0; size_t pos = 0; /*byte position in the out buffer*/ - unsigned error = 0; (void)settings; @@ -1234,8 +1242,8 @@ static unsigned lodepng_inflatev(ucvector* out, unsigned BTYPE; if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ BFINAL = readBitFromStream(&bp, in); - BTYPE = 1 * readBitFromStream(&bp, in); - BTYPE += 2 * readBitFromStream(&bp, in); + BTYPE = 1u * readBitFromStream(&bp, in); + BTYPE += 2u * readBitFromStream(&bp, in); if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ @@ -1244,9 +1252,6 @@ static unsigned lodepng_inflatev(ucvector* out, if(error) return error; } - /*Only now we know the true size of out, resize it to that*/ - if(!ucvector_resize(out, pos)) error = 83; /*alloc fail*/ - return error; } @@ -1298,7 +1303,7 @@ given array must be sorted (if no value is smaller, it returns the size of the g static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) { /*linear search implementation*/ - /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1; + /*for(size_t i = 1; i < array_size; ++i) if(array[i] > value) return i - 1; return array_size - 1;*/ /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ @@ -1333,31 +1338,23 @@ static void addLengthDistance(uivector* values, size_t length, size_t distance) uivector_push_back(values, extra_distance); } -static const unsigned HASH_BIT_MASK = 65535; +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ static const unsigned HASH_NUM_VALUES = 65536; -static const unsigned HASH_NUM_CHARACTERS = 3; -static const unsigned HASH_SHIFT = 2; -/* -The HASH_NUM_CHARACTERS value is used to make encoding faster by using longer -sequences to generate a hash value from the stream bytes. Setting it to 3 -gives exactly the same compression as the brute force method, since deflate's -run length encoding starts with lengths of 3. Setting it to higher values, -like 6, can make the encoding faster (not always though!), but will cause the -encoding to miss any length between 3 and this value, so that the compression -may be worse (but this can vary too depending on the image, sometimes it is -even a bit better instead). -The HASH_NUM_VALUES is the amount of unique possible hash values that -combinations of bytes can give, the higher it is the more memory is needed, but -if it's too low the advantage of hashing is gone. -*/ +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ typedef struct Hash { - int* head; /*hash value to head circular pos*/ - int* val; /*circular pos to hash value*/ + int* head; /*hash value to head circular pos - can be outdated if went around window*/ /*circular pos to prev circular pos*/ unsigned short* chain; - unsigned short* zeros; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ } Hash; static unsigned hash_init(Hash* hash, unsigned windowsize) @@ -1366,14 +1363,23 @@ static unsigned hash_init(Hash* hash, unsigned windowsize) hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); - if(!hash->head || !hash->val || !hash->chain || !hash->zeros) return 83; /*alloc fail*/ + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) + { + return 83; /*alloc fail*/ + } /*initialize hash table*/ - for(i = 0; i < HASH_NUM_VALUES; i++) hash->head[i] = -1; - for(i = 0; i < windowsize; i++) hash->val[i] = -1; - for(i = 0; i < windowsize; i++) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; + for(i = 0; i != windowsize; ++i) hash->val[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ return 0; } @@ -1383,22 +1389,31 @@ static void hash_cleanup(Hash* hash) lodepng_free(hash->head); lodepng_free(hash->val); lodepng_free(hash->chain); + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); } + + static unsigned getHash(const unsigned char* data, size_t size, size_t pos) { unsigned result = 0; - if (HASH_NUM_CHARACTERS == 3 && pos + 2 < size) { - result ^= (data[pos + 0] << (0 * HASH_SHIFT)); - result ^= (data[pos + 1] << (1 * HASH_SHIFT)); - result ^= (data[pos + 2] << (2 * HASH_SHIFT)); + if(pos + 2 < size) + { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= (unsigned)(data[pos + 0] << 0u); + result ^= (unsigned)(data[pos + 1] << 4u); + result ^= (unsigned)(data[pos + 2] << 8u); } else { size_t amount, i; if(pos >= size) return 0; - amount = HASH_NUM_CHARACTERS; - if(pos + amount >= size) amount = size - pos; - for(i = 0; i < amount; i++) result ^= (data[pos + i] << (i * HASH_SHIFT)); + amount = size - pos; + for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u)); } return result & HASH_BIT_MASK; } @@ -1409,17 +1424,21 @@ static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; if(end > data + size) end = data + size; data = start; - while (data != end && *data == 0) data++; + while(data != end && *data == 0) ++data; /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ return (unsigned)(data - start); } /*wpos = pos & (windowsize - 1)*/ -static void updateHashChain(Hash* hash, size_t wpos, int hashval) +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) { - hash->val[wpos] = hashval; + hash->val[wpos] = (int)hashval; if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; hash->head[hashval] = wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = wpos; } /* @@ -1435,7 +1454,8 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, unsigned minmatch, unsigned nicematch, unsigned lazymatching) { - unsigned pos, i, error = 0; + size_t pos; + unsigned i, error = 0; /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; @@ -1449,51 +1469,51 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, unsigned lazylength = 0, lazyoffset = 0; unsigned hashval; unsigned current_offset, current_length; + unsigned prev_offset; const unsigned char *lastptr, *foreptr, *backptr; - unsigned hashpos, prevpos; + unsigned hashpos; - if(windowsize <= 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; - for(pos = inpos; pos < insize; pos++) + for(pos = inpos; pos < insize; ++pos) { size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ unsigned chainlength = 0; hashval = getHash(in, insize, pos); - updateHashChain(hash, wpos, hashval); if(usezeros && hashval == 0) { - if (numzeros == 0) numzeros = countZeros(in, insize, pos); - else if (pos + numzeros >= insize || in[pos + numzeros - 1] != 0) numzeros--; - hash->zeros[wpos] = numzeros; + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; } else { numzeros = 0; } + updateHashChain(hash, wpos, hashval, numzeros); + /*the length and offset found for the current position*/ length = 0; offset = 0; - prevpos = hash->head[hashval]; - hashpos = hash->chain[prevpos]; + hashpos = hash->chain[wpos]; lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; /*search for the longest string*/ + prev_offset = 0; for(;;) { - /*stop when went completely around the circular buffer*/ - if(prevpos < wpos && hashpos > prevpos && hashpos <= wpos) break; - if(prevpos > wpos && (hashpos <= wpos || hashpos > prevpos)) break; if(chainlength++ >= maxchainlength) break; - current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; if(current_offset > 0) { /*test the next characters*/ @@ -1501,7 +1521,7 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, backptr = &in[pos - current_offset]; /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ - if(usezeros && hashval == 0 && hash->val[hashpos] == 0 /*hashval[hashpos] may be out of date*/) + if(numzeros >= 3) { unsigned skip = hash->zeros[hashpos]; if(skip > numzeros) skip = numzeros; @@ -1528,8 +1548,17 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, if(hashpos == hash->chain[hashpos]) break; - prevpos = hashpos; - hashpos = hash->chain[hashpos]; + if(numzeros >= 3 && length > numzeros) + { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } + else + { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } } if(lazymatching) @@ -1555,7 +1584,8 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, length = lazylength; offset = lazyoffset; hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ - pos--; + hash->headz[numzeros] = -1; /*idem*/ + --pos; } } } @@ -1575,22 +1605,21 @@ static unsigned encodeLZ77(uivector* out, Hash* hash, else { addLengthDistance(out, length, offset); - for(i = 1; i < length; i++) + for(i = 1; i < length; ++i) { - pos++; + ++pos; wpos = pos & (windowsize - 1); hashval = getHash(in, insize, pos); - updateHashChain(hash, wpos, hashval); if(usezeros && hashval == 0) { - if (numzeros == 0) numzeros = countZeros(in, insize, pos); - else if (pos + numzeros >= insize || in[pos + numzeros - 1] != 0) numzeros--; - hash->zeros[wpos] = numzeros; + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; } else { numzeros = 0; } + updateHashChain(hash, wpos, hashval, numzeros); } } } /*end of the loop through each character of input*/ @@ -1607,7 +1636,7 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; unsigned datapos = 0; - for(i = 0; i < numdeflateblocks; i++) + for(i = 0; i != numdeflateblocks; ++i) { unsigned BFINAL, BTYPE, LEN, NLEN; unsigned char firstbyte; @@ -1628,7 +1657,7 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s ucvector_push_back(out, (unsigned char)(NLEN / 256)); /*Decompressed data*/ - for(j = 0; j < 65535 && datapos < datasize; j++) + for(j = 0; j < 65535 && datapos < datasize; ++j) { ucvector_push_back(out, data[datapos++]); } @@ -1646,7 +1675,7 @@ static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encode const HuffmanTree* tree_ll, const HuffmanTree* tree_d) { size_t i = 0; - for(i = 0; i < lz77_encoded->size; i++) + for(i = 0; i != lz77_encoded->size; ++i) { unsigned val = lz77_encoded->data[i]; addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); @@ -1673,7 +1702,7 @@ static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encode /*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, const unsigned char* data, size_t datapos, size_t dataend, - const LodePNGCompressSettings* settings, int final) + const LodePNGCompressSettings* settings, unsigned final) { unsigned error = 0; @@ -1739,21 +1768,21 @@ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, else { if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); - for(i = datapos; i < dataend; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + for(i = datapos; i < dataend; ++i) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ } if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); /*Count the frequencies of lit, len and dist codes*/ - for(i = 0; i < lz77_encoded.size; i++) + for(i = 0; i != lz77_encoded.size; ++i) { unsigned symbol = lz77_encoded.data[i]; - frequencies_ll.data[symbol]++; + ++frequencies_ll.data[symbol]; if(symbol > 256) { unsigned dist = lz77_encoded.data[i + 2]; - frequencies_d.data[dist]++; + ++frequencies_d.data[dist]; i += 3; } } @@ -1769,19 +1798,19 @@ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; /*store the code lengths of both generated trees in bitlen_lld*/ - for(i = 0; i < numcodes_ll; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); - for(i = 0; i < numcodes_d; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); + for(i = 0; i != numcodes_ll; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); + for(i = 0; i != numcodes_d; ++i) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), 17 (3-10 zeroes), 18 (11-138 zeroes)*/ - for(i = 0; i < (unsigned)bitlen_lld.size; i++) + for(i = 0; i != (unsigned)bitlen_lld.size; ++i) { unsigned j = 0; /*amount of repititions*/ - while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) j++; + while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) ++j; if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ { - j++; /*include the first zero*/ + ++j; /*include the first zero*/ if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ { uivector_push_back(&bitlen_lld_e, 17); @@ -1800,7 +1829,7 @@ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, size_t k; unsigned num = j / 6, rest = j % 6; uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); - for(k = 0; k < num; k++) + for(k = 0; k < num; ++k) { uivector_push_back(&bitlen_lld_e, 16); uivector_push_back(&bitlen_lld_e, 6 - 3); @@ -1822,12 +1851,12 @@ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, /*generate tree_cl, the huffmantree of huffmantrees*/ if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); - for(i = 0; i < bitlen_lld_e.size; i++) + for(i = 0; i != bitlen_lld_e.size; ++i) { - frequencies_cl.data[bitlen_lld_e.data[i]]++; + ++frequencies_cl.data[bitlen_lld_e.data[i]]; /*after a repeat code come the bits that specify the number of repetitions, those don't need to be in the frequencies_cl calculation*/ - if(bitlen_lld_e.data[i] >= 16) i++; + if(bitlen_lld_e.data[i] >= 16) ++i; } error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, @@ -1835,7 +1864,7 @@ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, if(error) break; if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); - for(i = 0; i < tree_cl.numcodes; i++) + for(i = 0; i != tree_cl.numcodes; ++i) { /*lenghts of code length tree is in the order as specified by deflate*/ bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); @@ -1871,16 +1900,16 @@ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, HDIST = (unsigned)(numcodes_d - 1); HCLEN = (unsigned)bitlen_cl.size - 4; /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ - while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) HCLEN--; + while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) --HCLEN; addBitsToStream(bp, out, HLIT, 5); addBitsToStream(bp, out, HDIST, 5); addBitsToStream(bp, out, HCLEN, 4); /*write the code lenghts of the code length alphabet*/ - for(i = 0; i < HCLEN + 4; i++) addBitsToStream(bp, out, bitlen_cl.data[i], 3); + for(i = 0; i != HCLEN + 4; ++i) addBitsToStream(bp, out, bitlen_cl.data[i], 3); /*write the lenghts of the lit/len AND the dist alphabet*/ - for(i = 0; i < bitlen_lld_e.size; i++) + for(i = 0; i != bitlen_lld_e.size; ++i) { addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); @@ -1919,7 +1948,7 @@ static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, const unsigned char* data, size_t datapos, size_t dataend, - const LodePNGCompressSettings* settings, int final) + const LodePNGCompressSettings* settings, unsigned final) { HuffmanTree tree_ll; /*tree for literal values and length codes*/ HuffmanTree tree_d; /*tree for distance codes*/ @@ -1949,7 +1978,7 @@ static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, } else /*no LZ77, but still will be Huffman compressed*/ { - for(i = datapos; i < dataend; i++) + for(i = datapos; i < dataend; ++i) { addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); } @@ -1977,8 +2006,10 @@ static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t else if(settings->btype == 1) blocksize = insize; else /*if(settings->btype == 2)*/ { + /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ blocksize = insize / 8 + 8; - if(blocksize < 65535) blocksize = 65535; + if(blocksize < 65536) blocksize = 65536; + if(blocksize > 262144) blocksize = 262144; } numdeflateblocks = (insize + blocksize - 1) / blocksize; @@ -1987,9 +2018,9 @@ static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t error = hash_init(&hash, settings->windowsize); if(error) return error; - for(i = 0; i < numdeflateblocks && !error; i++) + for(i = 0; i != numdeflateblocks && !error; ++i) { - int final = i == numdeflateblocks - 1; + unsigned final = (i == numdeflateblocks - 1); size_t start = i * blocksize; size_t end = start + blocksize; if(end > insize) end = insize; @@ -2050,7 +2081,7 @@ static unsigned update_adler32(unsigned adler, const unsigned char* data, unsign { s1 += (*data++); s2 += s1; - amount--; + --amount; } s1 %= 65521; s2 %= 65521; @@ -2144,7 +2175,6 @@ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsig unsigned char* deflatedata = 0; size_t deflatesize = 0; - unsigned ADLER32; /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ unsigned FLEVEL = 0; @@ -2163,8 +2193,8 @@ unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsig if(!error) { - ADLER32 = adler32(in, (unsigned)insize); - for(i = 0; i < deflatesize; i++) ucvector_push_back(&outv, deflatedata[i]); + unsigned ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i != deflatesize; ++i) ucvector_push_back(&outv, deflatedata[i]); lodepng_free(deflatedata); lodepng_add32bitInt(&outv, ADLER32); } @@ -2197,7 +2227,7 @@ static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsign static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { - if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_DECODER*/ @@ -2205,7 +2235,7 @@ static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsi static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodePNGCompressSettings* settings) { - if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ return settings->custom_zlib(out, outsize, in, insize, settings); } #endif /*LODEPNG_COMPILE_ENCODER*/ @@ -2267,7 +2297,7 @@ const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, /* ////////////////////////////////////////////////////////////////////////// */ /* CRC polynomial: 0xedb88320 */ -static unsigned const lodepng_crc32_table[256] = { +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, @@ -2308,7 +2338,7 @@ unsigned lodepng_crc32(const unsigned char* buf, size_t len) unsigned c = 0xffffffffL; size_t n; - for(n = 0; n < len; n++) + for(n = 0; n < len; ++n) { c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); } @@ -2322,7 +2352,7 @@ unsigned lodepng_crc32(const unsigned char* buf, size_t len) static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) { unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); - (*bitpointer)++; + ++(*bitpointer); return result; } @@ -2330,7 +2360,7 @@ static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned ch { unsigned result = 0; size_t i; - for(i = nbits - 1; i < nbits; i--) + for(i = nbits - 1; i < nbits; --i) { result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; } @@ -2346,7 +2376,7 @@ static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); } - (*bitpointer)++; + ++(*bitpointer); } #endif /*LODEPNG_COMPILE_DECODER*/ @@ -2355,7 +2385,7 @@ static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, /*the current bit in bitstream may be 0 or 1 for this to work*/ if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); - (*bitpointer)++; + ++(*bitpointer); } /* ////////////////////////////////////////////////////////////////////////// */ @@ -2370,7 +2400,7 @@ unsigned lodepng_chunk_length(const unsigned char* chunk) void lodepng_chunk_type(char type[5], const unsigned char* chunk) { unsigned i; - for(i = 0; i < 4; i++) type[i] = chunk[4 + i]; + for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; type[4] = 0; /*null termination char*/ } @@ -2448,7 +2478,7 @@ unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsi (*outlength) = new_length; chunk_start = &(*out)[new_length - total_chunk_length]; - for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i]; + for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; return 0; } @@ -2470,13 +2500,13 @@ unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned l lodepng_set32bitInt(chunk, (unsigned)length); /*2: chunk name (4 letters)*/ - chunk[4] = type[0]; - chunk[5] = type[1]; - chunk[6] = type[2]; - chunk[7] = type[3]; + chunk[4] = (unsigned char)type[0]; + chunk[5] = (unsigned char)type[1]; + chunk[6] = (unsigned char)type[2]; + chunk[7] = (unsigned char)type[3]; /*3: the data*/ - for(i = 0; i < length; i++) chunk[8 + i] = data[i]; + for(i = 0; i != length; ++i) chunk[8 + i] = data[i]; /*4: CRC (of the chunkname characters and the data)*/ lodepng_chunk_generate_crc(chunk); @@ -2548,7 +2578,7 @@ unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* { dest->palette = (unsigned char*)lodepng_malloc(1024); if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ - for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i]; + for(i = 0; i != source->palettesize * 4; ++i) dest->palette[i] = source->palette[i]; } return 0; } @@ -2566,7 +2596,7 @@ static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColo if(a->key_b != b->key_b) return 0; } if(a->palettesize != b->palettesize) return 0; - for(i = 0; i < a->palettesize * 4; i++) + for(i = 0; i != a->palettesize * 4; ++i) { if(a->palette[i] != b->palette[i]) return 0; } @@ -2597,7 +2627,7 @@ unsigned lodepng_palette_add(LodePNGColorMode* info, info->palette[4 * info->palettesize + 1] = g; info->palette[4 * info->palettesize + 2] = b; info->palette[4 * info->palettesize + 3] = a; - info->palettesize++; + ++info->palettesize; return 0; } @@ -2630,7 +2660,7 @@ unsigned lodepng_is_palette_type(const LodePNGColorMode* info) unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) { size_t i; - for(i = 0; i < info->palettesize; i++) + for(i = 0; i != info->palettesize; ++i) { if(info->palette[i * 4 + 3] < 255) return 1; } @@ -2654,19 +2684,30 @@ size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colorty return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8; } + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_DECODER +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer*/ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return h * ((w * lodepng_get_bpp(color) + 7) / 8); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS static void LodePNGUnknownChunks_init(LodePNGInfo* info) { unsigned i; - for(i = 0; i < 3; i++) info->unknown_chunks_data[i] = 0; - for(i = 0; i < 3; i++) info->unknown_chunks_size[i] = 0; + for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; + for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; } static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) { unsigned i; - for(i = 0; i < 3; i++) lodepng_free(info->unknown_chunks_data[i]); + for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); } static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) @@ -2675,13 +2716,13 @@ static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* LodePNGUnknownChunks_cleanup(dest); - for(i = 0; i < 3; i++) + for(i = 0; i != 3; ++i) { size_t j; dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ - for(j = 0; j < src->unknown_chunks_size[i]; j++) + for(j = 0; j < src->unknown_chunks_size[i]; ++j) { dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; } @@ -2702,7 +2743,7 @@ static void LodePNGText_init(LodePNGInfo* info) static void LodePNGText_cleanup(LodePNGInfo* info) { size_t i; - for(i = 0; i < info->text_num; i++) + for(i = 0; i != info->text_num; ++i) { string_cleanup(&info->text_keys[i]); string_cleanup(&info->text_strings[i]); @@ -2717,7 +2758,7 @@ static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) dest->text_keys = 0; dest->text_strings = 0; dest->text_num = 0; - for(i = 0; i < source->text_num; i++) + for(i = 0; i != source->text_num; ++i) { CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); } @@ -2740,7 +2781,7 @@ unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) return 83; /*alloc fail*/ } - info->text_num++; + ++info->text_num; info->text_keys = new_keys; info->text_strings = new_strings; @@ -2767,7 +2808,7 @@ static void LodePNGIText_init(LodePNGInfo* info) static void LodePNGIText_cleanup(LodePNGInfo* info) { size_t i; - for(i = 0; i < info->itext_num; i++) + for(i = 0; i != info->itext_num; ++i) { string_cleanup(&info->itext_keys[i]); string_cleanup(&info->itext_langtags[i]); @@ -2788,7 +2829,7 @@ static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) dest->itext_transkeys = 0; dest->itext_strings = 0; dest->itext_num = 0; - for(i = 0; i < source->itext_num; i++) + for(i = 0; i != source->itext_num; ++i) { CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], source->itext_transkeys[i], source->itext_strings[i])); @@ -2817,7 +2858,7 @@ unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langt return 83; /*alloc fail*/ } - info->itext_num++; + ++info->itext_num; info->itext_keys = new_keys; info->itext_langtags = new_langtags; info->itext_transkeys = new_transkeys; @@ -2902,7 +2943,7 @@ static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsign unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ unsigned p = index & m; - in &= (1 << bits) - 1; /*filter out any other bits of the input value*/ + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ in = in << (bits * (m - p)); if(p == 0) out[index * bits / 8] = in; else out[index * bits / 8] |= in; @@ -2925,14 +2966,14 @@ struct ColorTree static void color_tree_init(ColorTree* tree) { int i; - for(i = 0; i < 16; i++) tree->children[i] = 0; + for(i = 0; i != 16; ++i) tree->children[i] = 0; tree->index = -1; } static void color_tree_cleanup(ColorTree* tree) { int i; - for(i = 0; i < 16; i++) + for(i = 0; i != 16; ++i) { if(tree->children[i]) { @@ -2946,7 +2987,7 @@ static void color_tree_cleanup(ColorTree* tree) static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { int bit = 0; - for(bit = 0; bit < 8; bit++) + for(bit = 0; bit < 8; ++bit) { int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); if(!tree->children[i]) return -1; @@ -2965,10 +3006,10 @@ static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, uns /*color is not allowed to already exist. Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ static void color_tree_add(ColorTree* tree, - unsigned char r, unsigned char g, unsigned char b, unsigned char a, int index) + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) { int bit; - for(bit = 0; bit < 8; bit++) + for(bit = 0; bit < 8; ++bit) { int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); if(!tree->children[i]) @@ -2978,7 +3019,7 @@ static void color_tree_add(ColorTree* tree, } tree = tree->children[i]; } - tree->index = index; + tree->index = (int)index; } /*put a pixel, given its RGBA color, into image of any color type*/ @@ -3018,7 +3059,7 @@ static unsigned rgba8ToPixel(unsigned char* out, size_t i, int index = color_tree_get(tree, r, g, b, a); if(index < 0) return 82; /*color not in palette*/ if(mode->bitdepth == 8) out[i] = index; - else addColorBits(out, i, mode->bitdepth, index); + else addColorBits(out, i, mode->bitdepth, (unsigned)index); } else if(mode->colortype == LCT_GREY_ALPHA) { @@ -3056,11 +3097,10 @@ static unsigned rgba8ToPixel(unsigned char* out, size_t i, } /*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ -static unsigned rgba16ToPixel(unsigned char* out, size_t i, - const LodePNGColorMode* mode, - unsigned short r, unsigned short g, unsigned short b, unsigned short a) +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) { - if(mode->bitdepth != 16) return 85; /*must be 16 for this function*/ if(mode->colortype == LCT_GREY) { unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; @@ -3095,16 +3135,13 @@ static unsigned rgba16ToPixel(unsigned char* out, size_t i, out[i * 8 + 6] = (a >> 8) & 255; out[i * 8 + 7] = a & 255; } - - return 0; /*no error*/ } /*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ -static unsigned getPixelColorRGBA8(unsigned char* r, unsigned char* g, - unsigned char* b, unsigned char* a, - const unsigned char* in, size_t i, - const LodePNGColorMode* mode, - unsigned fix_png) +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) { if(mode->colortype == LCT_GREY) { @@ -3161,8 +3198,8 @@ static unsigned getPixelColorRGBA8(unsigned char* r, unsigned char* g, if(index >= mode->palettesize) { - /*This is an error according to the PNG spec, but fix_png can ignore it*/ - if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/ + /*This is an error according to the PNG spec, but common PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ *r = *g = *b = 0; *a = 255; } @@ -3204,8 +3241,6 @@ static unsigned getPixelColorRGBA8(unsigned char* r, unsigned char* g, *a = in[i * 8 + 6]; } } - - return 0; /*no error*/ } /*Similar to getPixelColorRGBA8, but with all the for loops inside of the color @@ -3213,10 +3248,9 @@ mode test cases, optimized to convert the colors much faster, when converting to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with enough memory, if has_alpha is true the output is RGBA. mode has the color mode of the input buffer.*/ -static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, - unsigned has_alpha, const unsigned char* in, - const LodePNGColorMode* mode, - unsigned fix_png) +static void getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, + unsigned has_alpha, const unsigned char* in, + const LodePNGColorMode* mode) { unsigned num_channels = has_alpha ? 4 : 3; size_t i; @@ -3224,7 +3258,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, { if(mode->bitdepth == 8) { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i]; if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; @@ -3232,7 +3266,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, } else if(mode->bitdepth == 16) { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2]; if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; @@ -3242,7 +3276,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, { unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ size_t j = 0; - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; @@ -3254,7 +3288,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, { if(mode->bitdepth == 8) { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 3 + 0]; buffer[1] = in[i * 3 + 1]; @@ -3265,7 +3299,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, } else { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 6 + 0]; buffer[1] = in[i * 6 + 2]; @@ -3281,15 +3315,15 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, { unsigned index; size_t j = 0; - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { if(mode->bitdepth == 8) index = in[i]; else index = readBitsFromReversedStream(&j, in, mode->bitdepth); if(index >= mode->palettesize) { - /*This is an error according to the PNG spec, but fix_png can ignore it*/ - if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/ + /*This is an error according to the PNG spec, but most PNG decoders make it black instead. + Done here too, slightly faster due to no error handling needed.*/ buffer[0] = buffer[1] = buffer[2] = 0; if(has_alpha) buffer[3] = 255; } @@ -3306,7 +3340,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, { if(mode->bitdepth == 8) { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; if(has_alpha) buffer[3] = in[i * 2 + 1]; @@ -3314,7 +3348,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, } else { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; if(has_alpha) buffer[3] = in[i * 4 + 2]; @@ -3325,7 +3359,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, { if(mode->bitdepth == 8) { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 4 + 0]; buffer[1] = in[i * 4 + 1]; @@ -3335,7 +3369,7 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, } else { - for(i = 0; i < numpixels; i++, buffer += num_channels) + for(i = 0; i != numpixels; ++i, buffer += num_channels) { buffer[0] = in[i * 8 + 0]; buffer[1] = in[i * 8 + 2]; @@ -3344,17 +3378,13 @@ static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, } } } - - return 0; /*no error*/ } /*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with given color type, but the given color type must be 16-bit itself.*/ -static unsigned getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, - const unsigned char* in, size_t i, const LodePNGColorMode* mode) +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) { - if(mode->bitdepth != 16) return 85; /*error: this function only supports 16-bit input*/ - if(mode->colortype == LCT_GREY) { *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; @@ -3383,21 +3413,12 @@ static unsigned getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsign *b = 256 * in[i * 8 + 4] + in[i * 8 + 5]; *a = 256 * in[i * 8 + 6] + in[i * 8 + 7]; } - else return 85; /*error: this function only supports 16-bit input, not palettes*/ - - return 0; /*no error*/ } -/* -converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code -the out buffer must have (w * h * bpp + 7) / 8 bytes, where bpp is the bits per pixel of the output color type -(lodepng_get_bpp) for < 8 bpp images, there may _not_ be padding bits at the end of scanlines. -*/ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, - unsigned w, unsigned h, unsigned fix_png) + unsigned w, unsigned h) { - unsigned error = 0; size_t i; ColorTree tree; size_t numpixels = w * h; @@ -3405,16 +3426,16 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, if(lodepng_color_mode_equal(mode_out, mode_in)) { size_t numbytes = lodepng_get_raw_size(w, h, mode_in); - for(i = 0; i < numbytes; i++) out[i] = in[i]; - return error; + for(i = 0; i != numbytes; ++i) out[i] = in[i]; + return 0; } if(mode_out->colortype == LCT_PALETTE) { - size_t palsize = 1 << mode_out->bitdepth; + size_t palsize = 1u << mode_out->bitdepth; if(mode_out->palettesize < palsize) palsize = mode_out->palettesize; color_tree_init(&tree); - for(i = 0; i < palsize; i++) + for(i = 0; i != palsize; ++i) { unsigned char* p = &mode_out->palette[i * 4]; color_tree_add(&tree, p[0], p[1], p[2], p[3], i); @@ -3423,32 +3444,28 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) { - for(i = 0; i < numpixels; i++) + for(i = 0; i != numpixels; ++i) { unsigned short r = 0, g = 0, b = 0, a = 0; - error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); - if(error) break; - error = rgba16ToPixel(out, i, mode_out, r, g, b, a); - if(error) break; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); } } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) { - error = getPixelColorsRGBA8(out, numpixels, 1, in, mode_in, fix_png); + getPixelColorsRGBA8(out, numpixels, 1, in, mode_in); } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) { - error = getPixelColorsRGBA8(out, numpixels, 0, in, mode_in, fix_png); + getPixelColorsRGBA8(out, numpixels, 0, in, mode_in); } else { unsigned char r = 0, g = 0, b = 0, a = 0; - for(i = 0; i < numpixels; i++) + for(i = 0; i != numpixels; ++i) { - error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in, fix_png); - if(error) break; - error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); - if(error) break; + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); } } @@ -3457,93 +3474,36 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, color_tree_cleanup(&tree); } - return error; + return 0; /*no error (this function currently never has one, but maybe OOM detection added later.)*/ } #ifdef LODEPNG_COMPILE_ENCODER -typedef struct ColorProfile -{ - unsigned char sixteenbit; /*needs more than 8 bits per channel*/ - unsigned char sixteenbit_done; - - - unsigned char colored; /*not greyscale*/ - unsigned char colored_done; - - unsigned char key; /*a color key is required, or more*/ - unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ - unsigned short key_g; - unsigned short key_b; - unsigned char alpha; /*alpha channel, or alpha palette, required*/ - unsigned char alpha_done; - - unsigned numcolors; - ColorTree tree; /*for listing the counted colors, up to 256*/ - unsigned char* palette; /*size 1024. Remember up to the first 256 RGBA colors*/ - unsigned maxnumcolors; /*if more than that amount counted*/ - unsigned char numcolors_done; - - unsigned greybits; /*amount of bits required for greyscale (1, 2, 4, 8). Does not take 16 bit into account.*/ - unsigned char greybits_done; - -} ColorProfile; - -static void color_profile_init(ColorProfile* profile, const LodePNGColorMode* mode) +void lodepng_color_profile_init(LodePNGColorProfile* profile) { - profile->sixteenbit = 0; - profile->sixteenbit_done = mode->bitdepth == 16 ? 0 : 1; - profile->colored = 0; - profile->colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; - profile->key = 0; profile->alpha = 0; - profile->alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; - + profile->key_r = profile->key_g = profile->key_b = 0; profile->numcolors = 0; - color_tree_init(&profile->tree); - profile->palette = (unsigned char*)lodepng_malloc(1024); - profile->maxnumcolors = 257; - if(lodepng_get_bpp(mode) <= 8) - { - int bpp = lodepng_get_bpp(mode); - profile->maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); - } - profile->numcolors_done = 0; - - profile->greybits = 1; - profile->greybits_done = lodepng_get_bpp(mode) == 1 ? 1 : 0; -} - -static void color_profile_cleanup(ColorProfile* profile) -{ - color_tree_cleanup(&profile->tree); - lodepng_free(profile->palette); + profile->bits = 1; } /*function used for debug purposes with C++*/ -/*void printColorProfile(ColorProfile* p) -{ - std::cout << "sixteenbit: " << (int)p->sixteenbit << std::endl; - std::cout << "sixteenbit_done: " << (int)p->sixteenbit_done << std::endl; - std::cout << "colored: " << (int)p->colored << std::endl; - std::cout << "colored_done: " << (int)p->colored_done << std::endl; - std::cout << "key: " << (int)p->key << std::endl; - std::cout << "key_r: " << (int)p->key_r << std::endl; - std::cout << "key_g: " << (int)p->key_g << std::endl; - std::cout << "key_b: " << (int)p->key_b << std::endl; - std::cout << "alpha: " << (int)p->alpha << std::endl; - std::cout << "alpha_done: " << (int)p->alpha_done << std::endl; - std::cout << "numcolors: " << (int)p->numcolors << std::endl; - std::cout << "maxnumcolors: " << (int)p->maxnumcolors << std::endl; - std::cout << "numcolors_done: " << (int)p->numcolors_done << std::endl; - std::cout << "greybits: " << (int)p->greybits << std::endl; - std::cout << "greybits_done: " << (int)p->greybits_done << std::endl; +/*void printColorProfile(LodePNGColorProfile* p) +{ + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; }*/ /*Returns how many bits needed to represent given value (max 8 bit)*/ -unsigned getValueRequiredBits(unsigned short value) +static unsigned getValueRequiredBits(unsigned char value) { if(value == 0 || value == 255) return 1; /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ @@ -3553,326 +3513,231 @@ unsigned getValueRequiredBits(unsigned short value) /*profile must already have been inited with mode. It's ok to set some parameters of profile to done already.*/ -static unsigned get_color_profile(ColorProfile* profile, - const unsigned char* in, - size_t numpixels /*must be full image size, for certain filesize based choices*/, - const LodePNGColorMode* mode, - unsigned fix_png) +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode) { unsigned error = 0; size_t i; + ColorTree tree; + size_t numpixels = w * h; + + unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode); + unsigned bits_done = bpp == 1 ? 1 : 0; + unsigned maxnumcolors = 257; + unsigned sixteen = 0; + if(bpp <= 8) maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); + color_tree_init(&tree); + + /*Check if the 16-bit input is truly 16-bit*/ if(mode->bitdepth == 16) { - for(i = 0; i < numpixels; i++) + unsigned short r, g, b, a; + for(i = 0; i != numpixels; ++i) { - unsigned short r, g, b, a; - error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); - if(error) break; - - /*a color is considered good for 8-bit if the first byte and the second byte are equal, - (so if it's divisible through 257), NOT necessarily if the second byte is 0*/ - if(!profile->sixteenbit_done - && (((r & 255) != ((r >> 8) & 255)) - || ((g & 255) != ((g >> 8) & 255)) - || ((b & 255) != ((b >> 8) & 255)))) + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || + (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ { - profile->sixteenbit = 1; - profile->sixteenbit_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore at 16-bit*/ - profile->numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + sixteen = 1; + break; } + } + } - if(!profile->colored_done && (r != g || r != b)) + if(sixteen) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + profile->bits = 16; + bits_done = numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + + if(!colored_done && (r != g || r != b)) { profile->colored = 1; - profile->colored_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ + colored_done = 1; } - if(!profile->alpha_done && a != 65535) + if(!alpha_done) { - /*only use color key if numpixels large enough to justify tRNS chunk size*/ - if(a == 0 && numpixels > 16 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b))) + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 65535 && (a != 0 || (profile->key && !matchkey))) { - if(!profile->alpha && !profile->key) - { - profile->key = 1; - profile->key_r = r; - profile->key_g = g; - profile->key_b = b; - } + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } - else + else if(a == 0 && !profile->alpha && !profile->key) { - profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; } - } - - /* Color key cannot be used if an opaque pixel also has that RGB color. */ - if(!profile->alpha_done && a == 65535 && profile->key - && r == profile->key_r && g == profile->key_g && b == profile->key_b) - { - profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - - if(!profile->greybits_done) - { - /*assuming 8-bit r, this test does not care about 16-bit*/ - unsigned bits = getValueRequiredBits(r); - if(bits > profile->greybits) profile->greybits = bits; - if(profile->greybits >= 8) profile->greybits_done = 1; - } - - if(!profile->numcolors_done) - { - /*assuming 8-bit rgba, this test does not care about 16-bit*/ - if(!color_tree_has(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a)) + else if(a == 65535 && profile->key && matchkey) { - color_tree_add(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a, - profile->numcolors); - if(profile->numcolors < 256) - { - unsigned char* p = profile->palette; - unsigned i = profile->numcolors; - p[i * 4 + 0] = (unsigned char)r; - p[i * 4 + 1] = (unsigned char)g; - p[i * 4 + 2] = (unsigned char)b; - p[i * 4 + 3] = (unsigned char)a; - } - profile->numcolors++; - if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1; + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; } } - if(profile->alpha_done && profile->numcolors_done - && profile->colored_done && profile->sixteenbit_done && profile->greybits_done) - { - break; - } - }; + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } } else /* < 16-bit */ { - for(i = 0; i < numpixels; i++) + for(i = 0; i != numpixels; ++i) { unsigned char r = 0, g = 0, b = 0, a = 0; - error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode, fix_png); - if(error) break; + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); - if(!profile->colored_done && (r != g || r != b)) + if(!bits_done && profile->bits < 8) + { + /*only r is checked, < 8 bits is only relevant for greyscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > profile->bits) profile->bits = bits; + } + bits_done = (profile->bits >= bpp); + + if(!colored_done && (r != g || r != b)) { profile->colored = 1; - profile->colored_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ + colored_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ } - if(!profile->alpha_done && a != 255) + if(!alpha_done) { - if(a == 0 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b))) + unsigned matchkey = (r == profile->key_r && g == profile->key_g && b == profile->key_b); + if(a != 255 && (a != 0 || (profile->key && !matchkey))) { - if(!profile->key) - { - profile->key = 1; - profile->key_r = r; - profile->key_g = g; - profile->key_b = b; - } + profile->alpha = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } - else + else if(a == 0 && !profile->alpha && !profile->key) { - profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; } - } - - /* Color key cannot be used if an opaque pixel also has that RGB color. */ - if(!profile->alpha_done && a == 255 && profile->key - && r == profile->key_r && g == profile->key_g && b == profile->key_b) - { + else if(a == 255 && profile->key && matchkey) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ profile->alpha = 1; - profile->alpha_done = 1; - profile->greybits_done = 1; /*greybits is not applicable anymore*/ - } - - if(!profile->greybits_done) - { - unsigned bits = getValueRequiredBits(r); - if(bits > profile->greybits) profile->greybits = bits; - if(profile->greybits >= 8) profile->greybits_done = 1; + alpha_done = 1; + if(profile->bits < 8) profile->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } } - if(!profile->numcolors_done) + if(!numcolors_done) { - if(!color_tree_has(&profile->tree, r, g, b, a)) + if(!color_tree_has(&tree, r, g, b, a)) { - - color_tree_add(&profile->tree, r, g, b, a, profile->numcolors); + color_tree_add(&tree, r, g, b, a, profile->numcolors); if(profile->numcolors < 256) { unsigned char* p = profile->palette; - unsigned i = profile->numcolors; - p[i * 4 + 0] = r; - p[i * 4 + 1] = g; - p[i * 4 + 2] = b; - p[i * 4 + 3] = a; + unsigned n = profile->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; } - profile->numcolors++; - if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1; + ++profile->numcolors; + numcolors_done = profile->numcolors >= maxnumcolors; } } - if(profile->alpha_done && profile->numcolors_done && profile->colored_done && profile->greybits_done) - { - break; - } - }; - } + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } - /*make the profile's key always 16-bit for consistency*/ - if(mode->bitdepth < 16) - { - /*repeat each byte twice*/ - profile->key_r *= 257; - profile->key_g *= 257; - profile->key_b *= 257; + /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ + profile->key_r += (profile->key_r << 8); + profile->key_g += (profile->key_g << 8); + profile->key_b += (profile->key_b << 8); } + color_tree_cleanup(&tree); return error; } -static void setColorKeyFrom16bit(LodePNGColorMode* mode_out, unsigned r, unsigned g, unsigned b, unsigned bitdepth) -{ - unsigned mask = (1 << bitdepth) - 1; - mode_out->key_defined = 1; - mode_out->key_r = r & mask; - mode_out->key_g = g & mask; - mode_out->key_b = b & mask; -} - -/*updates values of mode with a potentially smaller color model. mode_out should +/*Automatically chooses color type that gives smallest amount of bits in the +output image, e.g. grey if there are only greyscale pixels, palette if there +are less than 256 colors, ... +Updates values of mode with a potentially smaller color model. mode_out should contain the user chosen color model, but will be overwritten with the new chosen one.*/ unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, const unsigned char* image, unsigned w, unsigned h, - const LodePNGColorMode* mode_in, - LodePNGAutoConvert auto_convert) + const LodePNGColorMode* mode_in) { - ColorProfile profile; + LodePNGColorProfile prof; unsigned error = 0; - int no_nibbles = auto_convert == LAC_AUTO_NO_NIBBLES || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE; - int no_palette = auto_convert == LAC_AUTO_NO_PALETTE || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE; + unsigned i, n, palettebits, grey_ok, palette_ok; - if(auto_convert == LAC_ALPHA) - { - if(mode_out->colortype != LCT_RGBA && mode_out->colortype != LCT_GREY_ALPHA) return 0; - } + lodepng_color_profile_init(&prof); + error = lodepng_get_color_profile(&prof, image, w, h, mode_in); + if(error) return error; + mode_out->key_defined = 0; - color_profile_init(&profile, mode_in); - if(auto_convert == LAC_ALPHA) + if(prof.key && w * h <= 16) { - profile.colored_done = 1; - profile.greybits_done = 1; - profile.numcolors_done = 1; - profile.sixteenbit_done = 1; + prof.alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + if(prof.bits < 8) prof.bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ } - error = get_color_profile(&profile, image, w * h, mode_in, 0 /*fix_png*/); - if(!error && auto_convert == LAC_ALPHA) + grey_ok = !prof.colored && !prof.alpha; /*grey without alpha, with potentially low bits*/ + n = prof.numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && (n * 2 < w * h) && prof.bits <= 8; + if(w * h < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(grey_ok && prof.bits <= palettebits) palette_ok = 0; /*grey is less overhead*/ + + if(palette_ok) { - if(!profile.alpha) + unsigned char* p = prof.palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i != prof.numcolors; ++i) { - mode_out->colortype = (mode_out->colortype == LCT_RGBA ? LCT_RGB : LCT_GREY); - if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; } - } - else if(!error && auto_convert != LAC_ALPHA) - { - mode_out->key_defined = 0; - if(profile.sixteenbit) - { - mode_out->bitdepth = 16; - if(profile.alpha) - { - mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA; - } - else - { - mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY; - if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); - } - } - else /*less than 16 bits per channel*/ - { - /*don't add palette overhead if image hasn't got a lot of pixels*/ - unsigned n = profile.numcolors; - int palette_ok = !no_palette && n <= 256 && (n * 2 < w * h); - unsigned palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); - int grey_ok = !profile.colored && !profile.alpha; /*grey without alpha, with potentially low bits*/ - if(palette_ok || grey_ok) - { - if(!palette_ok || (grey_ok && profile.greybits <= palettebits)) - { - unsigned grey = profile.key_r; - mode_out->colortype = LCT_GREY; - mode_out->bitdepth = profile.greybits; - if(profile.key) setColorKeyFrom16bit(mode_out, grey, grey, grey, mode_out->bitdepth); - } - else - { - /*fill in the palette*/ - unsigned i; - unsigned char* p = profile.palette; - /*remove potential earlier palette*/ - lodepng_palette_clear(mode_out); - for(i = 0; i < profile.numcolors; i++) - { - error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); - if(error) break; - } + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; - mode_out->colortype = LCT_PALETTE; - mode_out->bitdepth = palettebits; - } - } - else /*8-bit per channel*/ - { - mode_out->bitdepth = 8; - if(profile.alpha) - { - mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA; - } - else - { - mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY /*LCT_GREY normally won't occur, already done earlier*/; - if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); - } - } + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) + { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); + lodepng_color_mode_copy(mode_out, mode_in); } } - - color_profile_cleanup(&profile); - - if(mode_out->colortype == LCT_PALETTE && mode_in->palettesize == mode_out->palettesize) + else /*8-bit or 16-bit per channel*/ { - /*In this case keep the palette order of the input, so that the user can choose an optimal one*/ - size_t i; - for(i = 0; i < mode_in->palettesize * 4; i++) + mode_out->bitdepth = prof.bits; + mode_out->colortype = prof.alpha ? (prof.colored ? LCT_RGBA : LCT_GREY_ALPHA) + : (prof.colored ? LCT_RGB : LCT_GREY); + + if(prof.key && !prof.alpha) { - mode_out->palette[i] = mode_in->palette[i]; + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*profile always uses 16-bit, mask converts it*/ + mode_out->key_r = prof.key_r & mask; + mode_out->key_g = prof.key_g & mask; + mode_out->key_b = prof.key_b & mask; + mode_out->key_defined = 1; } } - if(no_nibbles && mode_out->bitdepth < 8) - { - /*palette can keep its small amount of colors, as long as no indices use it*/ - mode_out->bitdepth = 8; - } - return error; } @@ -3923,7 +3788,7 @@ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t fil unsigned i; /*calculate width and height in pixels of each pass*/ - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; @@ -3932,7 +3797,7 @@ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t fil } filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ filter_passstart[i + 1] = filter_passstart[i] @@ -3959,7 +3824,7 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, { CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ } - if(insize < 29) + if(insize < 33) { CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ } @@ -3987,6 +3852,11 @@ unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, info->filter_method = in[27]; info->interlace_method = in[28]; + if(*w == 0 || *h == 0) + { + CERROR_RETURN_ERROR(state->error, 93); + } + if(!state->decoder.ignore_crc) { unsigned CRC = lodepng_read32bitInt(&in[29]); @@ -4024,53 +3894,53 @@ static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scan switch(filterType) { case 0: - for(i = 0; i < length; i++) recon[i] = scanline[i]; + for(i = 0; i != length; ++i) recon[i] = scanline[i]; break; case 1: - for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; - for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth]; break; case 2: if(precon) { - for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; + for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; } else { - for(i = 0; i < length; i++) recon[i] = scanline[i]; + for(i = 0; i != length; ++i) recon[i] = scanline[i]; } break; case 3: if(precon) { - for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; - for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + precon[i] / 2; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); } else { - for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; - for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth] / 2; } break; case 4: if(precon) { - for(i = 0; i < bytewidth; i++) + for(i = 0; i != bytewidth; ++i) { recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ } - for(i = bytewidth; i < length; i++) + for(i = bytewidth; i < length; ++i) { recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); } } else { - for(i = 0; i < bytewidth; i++) + for(i = 0; i != bytewidth; ++i) { recon[i] = scanline[i]; } - for(i = bytewidth; i < length; i++) + for(i = bytewidth; i < length; ++i) { /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ recon[i] = (scanline[i] + recon[i - bytewidth]); @@ -4099,7 +3969,7 @@ static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w size_t bytewidth = (bpp + 7) / 8; size_t linebytes = (w * bpp + 7) / 8; - for(y = 0; y < h; y++) + for(y = 0; y < h; ++y) { size_t outindex = linebytes * y; size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ @@ -4134,16 +4004,16 @@ static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsig if(bpp >= 8) { - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8; - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; - for(b = 0; b < bytewidth; b++) + for(b = 0; b < bytewidth; ++b) { out[pixeloutstart + b] = in[pixelinstart + b]; } @@ -4152,18 +4022,18 @@ static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsig } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; - for(b = 0; b < bpp; b++) + for(b = 0; b < bpp; ++b) { unsigned char bit = readBitFromReversedStream(&ibp, in); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ @@ -4189,10 +4059,10 @@ static void removePaddingBits(unsigned char* out, const unsigned char* in, unsigned y; size_t diff = ilinebits - olinebits; size_t ibp = 0, obp = 0; /*input and output bit pointers*/ - for(y = 0; y < h; y++) + for(y = 0; y < h; ++y) { size_t x; - for(x = 0; x < olinebits; x++) + for(x = 0; x < olinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); @@ -4234,7 +4104,7 @@ static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, @@ -4267,7 +4137,7 @@ static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* dat } if(color->palettesize > 256) return 38; /*error: palette too big*/ - for(i = 0; i < color->palettesize; i++) + for(i = 0; i != color->palettesize; ++i) { color->palette[4 * i + 0] = data[pos++]; /*R*/ color->palette[4 * i + 1] = data[pos++]; /*G*/ @@ -4286,7 +4156,7 @@ static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* dat /*error: more alpha values given than there are palette entries*/ if(chunkLength > color->palettesize) return 38; - for(i = 0; i < chunkLength; i++) color->palette[4 * i + 3] = data[i]; + for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; } else if(color->colortype == LCT_GREY) { @@ -4294,7 +4164,7 @@ static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* dat if(chunkLength != 2) return 30; color->key_defined = 1; - color->key_r = color->key_g = color->key_b = 256 * data[0] + data[1]; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; } else if(color->colortype == LCT_RGB) { @@ -4302,9 +4172,9 @@ static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* dat if(chunkLength != 6) return 41; color->key_defined = 1; - color->key_r = 256 * data[0] + data[1]; - color->key_g = 256 * data[2] + data[3]; - color->key_b = 256 * data[4] + data[5]; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; } else return 42; /*error: tRNS chunk not allowed for other color models*/ @@ -4330,8 +4200,7 @@ static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, siz if(chunkLength != 2) return 44; info->background_defined = 1; - info->background_r = info->background_g = info->background_b - = 256 * data[0] + data[1]; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { @@ -4339,9 +4208,9 @@ static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, siz if(chunkLength != 6) return 45; info->background_defined = 1; - info->background_r = 256 * data[0] + data[1]; - info->background_g = 256 * data[2] + data[3]; - info->background_b = 256 * data[4] + data[5]; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; } return 0; /* OK */ @@ -4359,7 +4228,7 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz unsigned length, string2_begin; length = 0; - while(length < chunkLength && data[length] != 0) length++; + while(length < chunkLength && data[length] != 0) ++length; /*even though it's not allowed by the standard, no error is thrown if there's no null termination char, if the text is empty*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ @@ -4368,7 +4237,7 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; - for(i = 0; i < length; i++) key[i] = data[i]; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; string2_begin = length + 1; /*skip keyword null terminator*/ @@ -4377,7 +4246,7 @@ static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, siz if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ str[length] = 0; - for(i = 0; i < length; i++) str[i] = data[string2_begin + i]; + for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i]; error = lodepng_add_text(info, key, str); @@ -4405,7 +4274,7 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting while(!error) /*not really a while loop, only used to break on error*/ { - for(length = 0; length < chunkLength && data[length] != 0; length++) ; + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ @@ -4413,7 +4282,7 @@ static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSetting if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; - for(i = 0; i < length; i++) key[i] = data[i]; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ @@ -4458,7 +4327,7 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ /*read the key*/ - for(length = 0; length < chunkLength && data[length] != 0; length++) ; + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ @@ -4466,7 +4335,7 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ key[length] = 0; - for(i = 0; i < length; i++) key[i] = data[i]; + for(i = 0; i != length; ++i) key[i] = (char)data[i]; /*read the compression method*/ compressed = data[length + 1]; @@ -4478,24 +4347,24 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting /*read the langtag*/ begin = length + 3; length = 0; - for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; langtag = (char*)lodepng_malloc(length + 1); if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ langtag[length] = 0; - for(i = 0; i < length; i++) langtag[i] = data[begin + i]; + for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i]; /*read the transkey*/ begin += length + 1; length = 0; - for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; transkey = (char*)lodepng_malloc(length + 1); if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ transkey[length] = 0; - for(i = 0; i < length; i++) transkey[i] = data[begin + i]; + for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i]; /*read the actual text*/ begin += length + 1; @@ -4517,7 +4386,7 @@ static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSetting if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); decoded.data[length] = 0; - for(i = 0; i < length; i++) decoded.data[i] = data[begin + i]; + for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i]; } error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); @@ -4538,7 +4407,7 @@ static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, siz if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ info->time_defined = 1; - info->time.year = 256 * data[0] + data[+ 1]; + info->time.year = 256u * data[0] + data[1]; info->time.month = data[2]; info->time.day = data[3]; info->time.hour = data[4]; @@ -4553,8 +4422,8 @@ static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, siz if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ info->phys_defined = 1; - info->phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3]; - info->phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7]; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; info->phys_unit = data[8]; return 0; /* OK */ @@ -4571,6 +4440,8 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, size_t i; ucvector idat; /*the data from idat chunks*/ ucvector scanlines; + size_t predict; + size_t numpixels; /*for unknown chunk order*/ unsigned unknown = 0; @@ -4584,6 +4455,14 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ if(state->error) return; + numpixels = *w * *h; + + /*multiplication overflow*/ + if(*h != 0 && numpixels / *h != *w) CERROR_RETURN(state->error, 92); + /*multiplication overflow possible further below. Allows up to 2^31-1 pixel + bytes with 16-bit RGBA, the rest is room for filter bytes.*/ + if(numpixels > 268435455) CERROR_RETURN(state->error, 92); + ucvector_init(&idat); chunk = &in[33]; /*first byte of the first chunk after the header*/ @@ -4614,7 +4493,7 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, { size_t oldsize = idat.size; if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); - for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i]; + for(i = 0; i != chunkLength; ++i) idat.data[oldsize + i] = data[i]; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS critical_pos = 3; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ @@ -4709,28 +4588,41 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, } ucvector_init(&scanlines); - if(!state->error) + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + If the decompressed size does not match the prediction, the image must be corrupt.*/ + if(state->info_png.interlace_method == 0) { - /*maximum final image length is already reserved in the vector's length - this is not really necessary*/ - if(!ucvector_resize(&scanlines, lodepng_get_raw_size(*w, *h, &state->info_png.color) + *h)) - { - state->error = 83; /*alloc fail*/ - } + /*The extra *h is added because this are the filter bytes every scanline starts with*/ + predict = lodepng_get_raw_size_idat(*w, *h, &state->info_png.color) + *h; } + else + { + /*Adam-7 interlaced: predicted size is the sum of the 7 sub-images sizes*/ + const LodePNGColorMode* color = &state->info_png.color; + predict = 0; + predict += lodepng_get_raw_size_idat((*w + 7) / 8, (*h + 7) / 8, color) + (*h + 7) / 8; + if(*w > 4) predict += lodepng_get_raw_size_idat((*w + 3) / 8, (*h + 7) / 8, color) + (*h + 7) / 8; + predict += lodepng_get_raw_size_idat((*w + 3) / 4, (*h + 3) / 8, color) + (*h + 3) / 8; + if(*w > 2) predict += lodepng_get_raw_size_idat((*w + 1) / 4, (*h + 3) / 4, color) + (*h + 3) / 4; + predict += lodepng_get_raw_size_idat((*w + 1) / 2, (*h + 1) / 4, color) + (*h + 1) / 4; + if(*w > 1) predict += lodepng_get_raw_size_idat((*w + 0) / 2, (*h + 1) / 2, color) + (*h + 1) / 2; + predict += lodepng_get_raw_size_idat((*w + 0) / 1, (*h + 0) / 2, color) + (*h + 0) / 2; + } + if(!state->error && !ucvector_reserve(&scanlines, predict)) state->error = 83; /*alloc fail*/ if(!state->error) { - /*decompress with the Zlib decompressor*/ state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, idat.size, &state->decoder.zlibsettings); + if(!state->error && scanlines.size != predict) state->error = 91; /*decompressed size doesn't match prediction*/ } ucvector_cleanup(&idat); if(!state->error) { + size_t outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); ucvector outv; ucvector_init(&outv); - if(!ucvector_resizev(&outv, - lodepng_get_raw_size(*w, *h, &state->info_png.color), 0)) state->error = 83; /*alloc fail*/ + if(!ucvector_resizev(&outv, outsize, 0)) state->error = 83; /*alloc fail*/ if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png); *out = outv.data; } @@ -4775,7 +4667,8 @@ unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, { state->error = 83; /*alloc fail*/ } - else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h, state->decoder.fix_png); + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); lodepng_free(data); } return state->error; @@ -4836,7 +4729,6 @@ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) settings->remember_unknown_chunks = 0; #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ settings->ignore_crc = 0; - settings->fix_png = 0; lodepng_decompress_settings_init(&settings->zlibsettings); } @@ -4929,7 +4821,7 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) size_t i; ucvector PLTE; ucvector_init(&PLTE); - for(i = 0; i < info->palettesize * 4; i++) + for(i = 0; i != info->palettesize * 4; ++i) { /*add all channels except alpha channel*/ if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); @@ -4950,13 +4842,13 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { size_t amount = info->palettesize; /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ - for(i = info->palettesize; i > 0; i--) + for(i = info->palettesize; i != 0; --i) { - if(info->palette[4 * (i - 1) + 3] == 255) amount--; + if(info->palette[4 * (i - 1) + 3] == 255) --amount; else break; } /*add only alpha channel*/ - for(i = 0; i < amount; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); + for(i = 0; i != amount; ++i) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); } else if(info->colortype == LCT_GREY) { @@ -5015,10 +4907,10 @@ static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* te size_t i; ucvector text; ucvector_init(&text); - for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&text, 0); /*0 termination char*/ - for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]); + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&text, (unsigned char)textstring[i]); error = addChunk(out, "tEXt", text.data, text.size); ucvector_cleanup(&text); @@ -5034,7 +4926,7 @@ static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* te ucvector_init(&data); ucvector_init(&compressed); - for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&data, 0); /*0 termination char*/ ucvector_push_back(&data, 0); /*compression method: 0*/ @@ -5043,7 +4935,7 @@ static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* te (unsigned char*)textstring, textsize, zlibsettings); if(!error) { - for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]); + for(i = 0; i != compressed.size; ++i) ucvector_push_back(&data, compressed.data[i]); error = addChunk(out, "zTXt", data.data, data.size); } @@ -5061,14 +4953,14 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* ke ucvector_init(&data); - for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + for(i = 0; keyword[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)keyword[i]); if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ ucvector_push_back(&data, 0); /*null termination char*/ ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ ucvector_push_back(&data, 0); /*compression method*/ - for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]); + for(i = 0; langtag[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)langtag[i]); ucvector_push_back(&data, 0); /*null termination char*/ - for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]); + for(i = 0; transkey[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)transkey[i]); ucvector_push_back(&data, 0); /*null termination char*/ if(compressed) @@ -5079,13 +4971,13 @@ static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* ke (unsigned char*)textstring, textsize, zlibsettings); if(!error) { - for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]); + for(i = 0; i != compressed_data.size; ++i) ucvector_push_back(&data, compressed_data.data[i]); } ucvector_cleanup(&compressed_data); } else /*not compressed*/ { - for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]); + for(i = 0; textstring[i] != 0; ++i) ucvector_push_back(&data, (unsigned char)textstring[i]); } if(!error) error = addChunk(out, "iTXt", data.data, data.size); @@ -5130,11 +5022,11 @@ static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) if(!data) return 83; /*alloc fail*/ data[0] = (unsigned char)(time->year / 256); data[1] = (unsigned char)(time->year % 256); - data[2] = time->month; - data[3] = time->day; - data[4] = time->hour; - data[5] = time->minute; - data[6] = time->second; + data[2] = (unsigned char)time->month; + data[3] = (unsigned char)time->day; + data[4] = (unsigned char)time->hour; + data[5] = (unsigned char)time->minute; + data[6] = (unsigned char)time->second; error = addChunk(out, "tIME", data, 7); lodepng_free(data); return error; @@ -5165,57 +5057,49 @@ static void filterScanline(unsigned char* out, const unsigned char* scanline, co switch(filterType) { case 0: /*None*/ - for(i = 0; i < length; i++) out[i] = scanline[i]; + for(i = 0; i != length; ++i) out[i] = scanline[i]; break; case 1: /*Sub*/ - if(prevline) - { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; - } - else - { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; - } + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; break; case 2: /*Up*/ if(prevline) { - for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i]; + for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; } else { - for(i = 0; i < length; i++) out[i] = scanline[i]; + for(i = 0; i != length; ++i) out[i] = scanline[i]; } break; case 3: /*Average*/ if(prevline) { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - prevline[i] / 2; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); } else { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; - for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2; + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth] / 2; } break; case 4: /*Paeth*/ if(prevline) { /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ - for(i = 0; i < bytewidth; i++) out[i] = (scanline[i] - prevline[i]); - for(i = bytewidth; i < length; i++) + for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; ++i) { out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); } } else { - for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ - for(i = bytewidth; i < length; i++) out[i] = (scanline[i] - scanline[i - bytewidth]); + for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); } break; default: return; /*unexisting filter type given*/ @@ -5227,7 +5111,7 @@ static float flog2(float f) { float result = 0; while(f > 32) { result += 4; f /= 16; } - while(f > 2) { result++; f /= 2; } + while(f > 2) { ++result; f /= 2; } return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); } @@ -5270,7 +5154,7 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, if(strategy == LFS_ZERO) { - for(y = 0; y < h; y++) + for(y = 0; y != h; ++y) { size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; @@ -5285,9 +5169,9 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, size_t sum[5]; ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ size_t smallest = 0; - unsigned type, bestType = 0; + unsigned char type, bestType = 0; - for(type = 0; type < 5; type++) + for(type = 0; type != 5; ++type) { ucvector_init(&attempt[type]); if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ @@ -5295,10 +5179,10 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, if(!error) { - for(y = 0; y < h; y++) + for(y = 0; y != h; ++y) { /*try the 5 filter types*/ - for(type = 0; type < 5; type++) + for(type = 0; type != 5; ++type) { filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); @@ -5306,17 +5190,17 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, sum[type] = 0; if(type == 0) { - for(x = 0; x < linebytes; x++) sum[type] += (unsigned char)(attempt[type].data[x]); + for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type].data[x]); } else { - for(x = 0; x < linebytes; x++) + for(x = 0; x != linebytes; ++x) { /*For differences, each byte should be treated as signed, values above 127 are negative (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. This means filtertype 0 is almost never chosen, but that is justified.*/ - signed char s = (signed char)(attempt[type].data[x]); - sum[type] += s < 0 ? -s : s; + unsigned char s = attempt[type].data[x]; + sum[type] += s < 128 ? s : (255U - s); } } @@ -5332,11 +5216,11 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, /*now fill the out values*/ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; } } - for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); } else if(strategy == LFS_ENTROPY) { @@ -5346,23 +5230,23 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned type, bestType = 0; unsigned count[256]; - for(type = 0; type < 5; type++) + for(type = 0; type != 5; ++type) { ucvector_init(&attempt[type]); if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ } - for(y = 0; y < h; y++) + for(y = 0; y != h; ++y) { /*try the 5 filter types*/ - for(type = 0; type < 5; type++) + for(type = 0; type != 5; ++type) { filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); - for(x = 0; x < 256; x++) count[x] = 0; - for(x = 0; x < linebytes; x++) count[attempt[type].data[x]]++; - count[type]++; /*the filter type itself is part of the scanline*/ + for(x = 0; x != 256; ++x) count[x] = 0; + for(x = 0; x != linebytes; ++x) ++count[attempt[type].data[x]]; + ++count[type]; /*the filter type itself is part of the scanline*/ sum[type] = 0; - for(x = 0; x < 256; x++) + for(x = 0; x != 256; ++x) { float p = count[x] / (float)(linebytes + 1); sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; @@ -5379,18 +5263,18 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, /*now fill the out values*/ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; } - for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); } else if(strategy == LFS_PREDEFINED) { - for(y = 0; y < h; y++) + for(y = 0; y != h; ++y) { size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ size_t inindex = linebytes * y; - unsigned type = settings->predefined_filters[y]; + unsigned char type = settings->predefined_filters[y]; out[outindex] = type; /*filter type byte*/ filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); prevline = &in[inindex]; @@ -5416,14 +5300,14 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, images only, so disable it*/ zlibsettings.custom_zlib = 0; zlibsettings.custom_deflate = 0; - for(type = 0; type < 5; type++) + for(type = 0; type != 5; ++type) { ucvector_init(&attempt[type]); ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/ } - for(y = 0; y < h; y++) /*try the 5 filter types*/ + for(y = 0; y != h; ++y) /*try the 5 filter types*/ { - for(type = 0; type < 5; type++) + for(type = 0; type != 5; ++type) { unsigned testsize = attempt[type].size; /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ @@ -5442,9 +5326,9 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, } prevline = &in[y * linebytes]; out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ - for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; } - for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + for(type = 0; type != 5; ++type) ucvector_cleanup(&attempt[type]); } else return 88; /* unknown filter strategy */ @@ -5459,17 +5343,17 @@ static void addPaddingBits(unsigned char* out, const unsigned char* in, unsigned y; size_t diff = olinebits - ilinebits; size_t obp = 0, ibp = 0; /*bit pointers*/ - for(y = 0; y < h; y++) + for(y = 0; y != h; ++y) { size_t x; - for(x = 0; x < ilinebits; x++) + for(x = 0; x < ilinebits; ++x) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); } /*obp += diff; --> no, fill in some value in the padding bits too, to avoid "Use of uninitialised value of size ###" warning from valgrind*/ - for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0); + for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); } } @@ -5494,16 +5378,16 @@ static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigne if(bpp >= 8) { - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { unsigned x, y, b; size_t bytewidth = bpp / 8; - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; - for(b = 0; b < bytewidth; b++) + for(b = 0; b < bytewidth; ++b) { out[pixeloutstart + b] = in[pixelinstart + b]; } @@ -5512,18 +5396,18 @@ static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigne } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { unsigned x, y, b; unsigned ilinebits = bpp * passw[i]; unsigned olinebits = bpp * w; size_t obp, ibp; /*bit pointers (for out and in buffer)*/ - for(y = 0; y < passh[i]; y++) - for(x = 0; x < passw[i]; x++) + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); - for(b = 0; b < bpp; b++) + for(b = 0; b < bpp; ++b) { unsigned char bit = readBitFromReversedStream(&ibp, in); setBitOfReversedStream(&obp, out, bit); @@ -5594,7 +5478,7 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned i; Adam7_interlace(adam7, in, w, h, bpp); - for(i = 0; i < 7; i++) + for(i = 0; i != 7; ++i) { if(bpp < 8) { @@ -5630,9 +5514,10 @@ returns 2 if the palette is semi-translucent. */ static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) { - size_t i, key = 0; + size_t i; + unsigned key = 0; unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ - for(i = 0; i < palettesize; i++) + for(i = 0; i != palettesize; ++i) { if(!key && palette[4 * i + 3] == 0) { @@ -5685,10 +5570,9 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, return state->error; } - if(state->encoder.auto_convert != LAC_NO) + if(state->encoder.auto_convert) { - state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw, - state->encoder.auto_convert); + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw); } if(state->error) return state->error; @@ -5715,7 +5599,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, if(!converted && size) state->error = 83; /*alloc fail*/ if(!state->error) { - state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h, 0 /*fix_png*/); + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); } if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); lodepng_free(converted); @@ -5778,7 +5662,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, /*tIME*/ if(info.time_defined) addChunk_tIME(&outv, &info.time); /*tEXt and/or zTXt*/ - for(i = 0; i < info.text_num; i++) + for(i = 0; i != info.text_num; ++i) { if(strlen(info.text_keys[i]) > 79) { @@ -5803,7 +5687,7 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, if(state->encoder.add_id) { unsigned alread_added_id_text = 0; - for(i = 0; i < info.text_num; i++) + for(i = 0; i != info.text_num; ++i) { if(!strcmp(info.text_keys[i], "LodePNG")) { @@ -5813,11 +5697,11 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize, } if(alread_added_id_text == 0) { - addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ } } /*iTXt*/ - for(i = 0; i < info.itext_num; i++) + for(i = 0; i != info.itext_num; ++i) { if(strlen(info.itext_keys[i]) > 79) { @@ -5909,7 +5793,7 @@ void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) lodepng_compress_settings_init(&settings->zlibsettings); settings->filter_palette_zero = 1; settings->filter_strategy = LFS_MINSUM; - settings->auto_convert = LAC_AUTO; + settings->auto_convert = 1; settings->force_palette = 0; settings->predefined_filters = 0; #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS @@ -5972,10 +5856,6 @@ const char* lodepng_error_text(unsigned code) case 43: return "bKGD chunk has wrong size for palette image"; case 44: return "bKGD chunk has wrong size for greyscale image"; case 45: return "bKGD chunk has wrong size for RGB image"; - /*Is the palette too small?*/ - case 46: return "a value in indexed image is larger than the palette size (bitdepth = 8)"; - /*Is the palette too small?*/ - case 47: return "a value in indexed image is larger than the palette size (bitdepth < 8)"; /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/ case 48: return "empty input or file doesn't exist"; case 49: return "jumped past memory while generating dynamic huffman tree"; @@ -6018,13 +5898,15 @@ const char* lodepng_error_text(unsigned code) case 82: return "color conversion to palette requested while a color isn't in palette"; case 83: return "memory allocation failed"; case 84: return "given image too small to contain all pixels to be encoded"; - case 85: return "internal color conversion bug"; case 86: return "impossible offset in lz77 encoding (internal bug)"; case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; case 89: return "text chunk keyword too short or long: must have size 1-79"; /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ case 90: return "windowsize must be a power of two"; + case 91: return "invalid decompressed idat size"; + case 92: return "too many pixels, not supported"; + case 93: return "zero width or height is invalid"; } return "unknown error code"; } @@ -6061,7 +5943,7 @@ void save_file(const std::vector& buffer, const std::string& file std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary); file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size())); } -#endif //LODEPNG_COMPILE_DISK +#endif /* LODEPNG_COMPILE_DISK */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER @@ -6084,7 +5966,7 @@ unsigned decompress(std::vector& out, const std::vector& out, const unsigned char* in, size_t insize, @@ -6106,8 +5988,8 @@ unsigned compress(std::vector& out, const std::vector& out, unsigned& w, unsigned& h, const load_file(buffer, filename); return decode(out, w, h, buffer, colortype, bitdepth); } -#endif //LODEPNG_COMPILE_DECODER -#endif //LODEPNG_COMPILE_DISK +#endif /* LODEPNG_COMPILE_DECODER */ +#endif /* LODEPNG_COMPILE_DISK */ #ifdef LODEPNG_COMPILE_ENCODER unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, @@ -6256,8 +6138,8 @@ unsigned encode(const std::string& filename, if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); } -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_ENCODER -#endif //LODEPNG_COMPILE_PNG -} //namespace lodepng +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_PNG */ +} /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ diff --git a/components/external/lodepng/lodepng.h b/components/external/lodepng/lodepng.h index b73e35d751..a5aa522e39 100644 --- a/components/external/lodepng/lodepng.h +++ b/components/external/lodepng/lodepng.h @@ -1,7 +1,7 @@ /* -LodePNG version 20131222 +LodePNG version 20150418 -Copyright (c) 2005-2013 Lode Vandevenne +Copyright (c) 2005-2015 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 @@ -36,6 +36,8 @@ freely, subject to the following restrictions: #include #endif /*__cplusplus*/ +extern const char* LODEPNG_VERSION_STRING; + /* 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. @@ -198,7 +200,8 @@ unsigned lodepng_encode24_file(const char* filename, namespace lodepng { #ifdef LODEPNG_COMPILE_DECODER -/*Same as lodepng_decode_memory, but decodes to an std::vector.*/ +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, size_t insize, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); @@ -213,11 +216,12 @@ Same as the other decode functions, but instead takes a filename as input. unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_DECODER +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER -/*Same as lodepng_encode_memory, but encodes to an std::vector.*/ +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); @@ -236,9 +240,9 @@ unsigned encode(const std::string& filename, unsigned encode(const std::string& filename, const std::vector& in, unsigned w, unsigned h, LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_ENCODER -} //namespace lodepng +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +} /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ #endif /*LODEPNG_COMPILE_PNG*/ @@ -283,7 +287,7 @@ struct LodePNGCompressSettings /*deflate = compress*/ /*LZ77 related settings*/ unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ - unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Typical value: 2048.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ @@ -499,13 +503,14 @@ LodePNGColorMode structs to describe the input and output color type. See the reference manual at the end of this header file to see which color conversions are supported. return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel -of the output color type (lodepng_get_bpp) -The fix_png value works as described in struct LodePNGDecoderSettings. -Note: for 16-bit per channel colors, uses big endian format like PNG does. +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code */ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, - unsigned w, unsigned h, unsigned fix_png); + unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DECODER /* @@ -517,16 +522,7 @@ typedef struct LodePNGDecoderSettings LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ unsigned ignore_crc; /*ignore CRC checksums*/ - /* - The fix_png setting, if 1, makes the decoder tolerant towards some PNG images - that do not correctly follow the PNG specification. This only supports errors - that are fixable, were found in images that are actually used on the web, and - are silently tolerated by other decoders as well. Currently only one such fix - is implemented: if a palette index is out of bounds given the palette size, - interpret it as opaque black. - By default this value is 0, which makes it stop with an error on such images. - */ - unsigned fix_png; + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS @@ -559,46 +555,39 @@ typedef enum LodePNGFilterStrategy LFS_PREDEFINED } LodePNGFilterStrategy; -/*automatically use color type with less bits per pixel if losslessly possible. Default: LAC_AUTO*/ -typedef enum LodePNGAutoConvert +/*Gives characteristics about the colors of the image, which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorProfile { - LAC_NO, /*use color type user requested*/ - LAC_ALPHA, /*use color type user requested, but if only opaque pixels and RGBA or grey+alpha, use RGB or grey*/ - LAC_AUTO, /*use PNG color type that can losslessly represent the uncompressed image the smallest possible*/ - /* - like AUTO, but do not choose 1, 2 or 4 bit per pixel types. - sometimes a PNG image compresses worse if less than 8 bits per pixels. - */ - LAC_AUTO_NO_NIBBLES, - /* - like AUTO, but never choose palette color type. For small images, encoding - the palette may take more bytes than what is gained. Note that AUTO also - already prevents encoding the palette for extremely small images, but that may - not be sufficient because due to the compression it cannot predict when to - switch. - */ - LAC_AUTO_NO_PALETTE, - LAC_AUTO_NO_NIBBLES_NO_PALETTE -} LodePNGAutoConvert; - - -/* -Automatically chooses color type that gives smallest amount of bits in the -output image, e.g. grey if there are only greyscale pixels, palette if there -are less than 256 colors, ... -The auto_convert parameter allows limiting it to not use palette, ... -*/ + unsigned colored; /*not greyscale*/ + unsigned key; /*if true, image is not opaque. Only if true and alpha is false, color key is possible.*/ + unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/ +} LodePNGColorProfile; + +void lodepng_color_profile_init(LodePNGColorProfile* profile); + +/*Get a LodePNGColorProfile of the image.*/ +unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); +/*The function LodePNG uses internally to decide the PNG color with auto_convert. +Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/ unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, const unsigned char* image, unsigned w, unsigned h, - const LodePNGColorMode* mode_in, - LodePNGAutoConvert auto_convert); + const LodePNGColorMode* mode_in); /*Settings for the encoder.*/ typedef struct LodePNGEncoderSettings { LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ - LodePNGAutoConvert auto_convert; /*how to automatically choose output PNG color type, if at all*/ + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to @@ -643,7 +632,7 @@ typedef struct LodePNGState LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ unsigned error; #ifdef LODEPNG_COMPILE_CPP - //For the lodepng::State subclass. + /* For the lodepng::State subclass. */ virtual ~LodePNGState(){} #endif } LodePNGState; @@ -693,7 +682,11 @@ Third byte: must be uppercase Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy */ -/*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ +/* +Gets the length of the data of the chunk. Total chunk length has 12 bytes more. +There must be at least 4 bytes to read from. If the result value is too large, +it may be corrupt data. +*/ unsigned lodepng_chunk_length(const unsigned char* chunk); /*puts the 4-byte type in null terminated string*/ @@ -821,7 +814,7 @@ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const #endif /*LODEPNG_COMPILE_DISK*/ #ifdef LODEPNG_COMPILE_CPP -//The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ namespace lodepng { #ifdef LODEPNG_COMPILE_PNG @@ -835,7 +828,7 @@ class State : public LodePNGState }; #ifdef LODEPNG_COMPILE_DECODER -//Same as other lodepng::decode, but using a State for more settings and information. +/* Same as other lodepng::decode, but using a State for more settings and information. */ unsigned decode(std::vector& out, unsigned& w, unsigned& h, State& state, const unsigned char* in, size_t insize); @@ -845,7 +838,7 @@ unsigned decode(std::vector& out, unsigned& w, unsigned& h, #endif /*LODEPNG_COMPILE_DECODER*/ #ifdef LODEPNG_COMPILE_ENCODER -//Same as other lodepng::encode, but using a State for more settings and information. +/* Same as other lodepng::encode, but using a State for more settings and information. */ unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, State& state); @@ -866,31 +859,31 @@ Save the binary data in an std::vector to a file on disk. The file is overwritte without warning. */ void save_file(const std::vector& buffer, const std::string& filename); -#endif //LODEPNG_COMPILE_DISK -#endif //LODEPNG_COMPILE_PNG +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_PNG */ #ifdef LODEPNG_COMPILE_ZLIB #ifdef LODEPNG_COMPILE_DECODER -//Zlib-decompress an unsigned char buffer +/* Zlib-decompress an unsigned char buffer */ unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); -//Zlib-decompress an std::vector +/* Zlib-decompress an std::vector */ unsigned decompress(std::vector& out, const std::vector& in, const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); -#endif //LODEPNG_COMPILE_DECODER +#endif /* LODEPNG_COMPILE_DECODER */ #ifdef LODEPNG_COMPILE_ENCODER -//Zlib-compress an unsigned char buffer +/* Zlib-compress an unsigned char buffer */ unsigned compress(std::vector& out, const unsigned char* in, size_t insize, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); -//Zlib-compress an std::vector +/* Zlib-compress an std::vector */ unsigned compress(std::vector& out, const std::vector& in, const LodePNGCompressSettings& settings = lodepng_default_compress_settings); -#endif //LODEPNG_COMPILE_ENCODER -#endif //LODEPNG_COMPILE_ZLIB -} //namespace lodepng +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ +} /* namespace lodepng */ #endif /*LODEPNG_COMPILE_CPP*/ /* @@ -904,8 +897,8 @@ TODO: [X] let the "isFullyOpaque" function check color keys and transparent palettes too [X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" [ ] don't stop decoding on errors like 69, 57, 58 (make warnings) -[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not [ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... */ #endif /*LODEPNG_H inclusion guard*/ @@ -1243,20 +1236,22 @@ behaviour. If, when decoding, you want the raw image to be something else than the default, you need to set the color type and bit depth you want in the LodePNGColorMode, -or the parameters of the simple function of LodePNG you're using. +or the parameters colortype and bitdepth of the simple decoding function. -If, when encoding, you use another color type than the default in the input +If, when encoding, you use another color type than the default in the raw input image, you need to specify its color type and bit depth in the LodePNGColorMode -of the raw image, or use the parameters of the simplefunction of LodePNG you're -using. +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. If, when encoding, you don't want LodePNG to choose the output PNG color type but control it yourself, you need to set auto_convert in the encoder settings -to LAC_NONE, and specify the color type you want in the LodePNGInfo of the -encoder. +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). -If you do any of the above, LodePNG may need to do a color conversion, which -follows the rules below, and may sometimes not be allowed. +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. To avoid some confusion: -the decoder converts from PNG to raw image @@ -1278,7 +1273,7 @@ To avoid some confusion: Non supported color conversions: -color to greyscale: no error is thrown, but the result will look ugly because only the red channel is taken --anything, to palette when that palette does not have that color in it: in this +-anything to palette when that palette does not have that color in it: in this case an error is thrown Supported color conversions: @@ -1288,10 +1283,10 @@ Supported color conversions: -removing alpha channel -higher to smaller bitdepth, and vice versa -If you want no color conversion to be done: +If you want no color conversion to be done (e.g. for speed or control): -In the encoder, you can make it save a PNG with any color type by giving the raw color mode and LodePNGInfo the same color mode, and setting auto_convert to -LAC_NO. +false. -In the decoder, you can make it store the pixel data in the same color type as the PNG has, by setting the color_convert setting to false. Settings in info_raw are then ignored. @@ -1458,6 +1453,8 @@ LodePNG. For the C++ version, only the standard C++ library is needed on top. Add the files lodepng.c(pp) and lodepng.h to your project, include lodepng.h where needed, and your program can read/write PNG files. +It is compatible with C90 and up, and C++03 and up. + If performance is important, use optimization when compiling! For both the encoder and decoder, this makes a large difference. @@ -1473,49 +1470,40 @@ LodePNG is developed in gcc so this compiler is natively supported. It gives no warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ version 4.7.1 on Linux, 32-bit and 64-bit. -*) Mingw +*) Clang -The Mingw compiler (a port of gcc) for Windows is fully supported by LodePNG. +Fully supported and warning-free. -*) Visual Studio 2005 and up, Visual C++ Express Edition 2005 and up +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. -Visual Studio may give warnings about 'fopen' being deprecated. A multiplatform library -can't support the proposed Visual Studio alternative however, so LodePNG keeps using -fopen. If you don't want to see the deprecated warnings, put this on top of lodepng.h -before the inclusions: -#define _CRT_SECURE_NO_DEPRECATE +*) Visual Studio and Visual C++ Express Edition -Other than the above warnings, LodePNG should be warning-free with warning -level 3 (W3). Warning level 4 (W4) will give warnings about integer conversions. -I'm not planning to resolve these warnings. To get rid of them, let Visual -Studio use warning level W3 for lodepng.cpp only: right click lodepng.cpp, -Properties, C/C++, General, Warning Level: Level 3 (/W3). +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. Visual Studio may want "stdafx.h" files to be included in each source file and give an error "unexpected end of file while looking for precompiled header". -That is not standard C++ and will not be added to the stock LodePNG. You can +This is not standard C++ and will not be added to the stock LodePNG. You can disable it for lodepng.cpp only by right clicking it, Properties, C/C++, Precompiled Headers, and set it to Not Using Precompiled Headers there. -*) Visual Studio 6.0 - -LodePNG support for Visual Studio 6.0 is not guaranteed because VS6 doesn't -follow the C++ standard correctly. - -*) Comeau C/C++ - -Vesion 20070107 compiles without problems on the Comeau C/C++ Online Test Drive -at http://www.comeaucomputing.com/tryitout in both C90 and C++ mode. +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. *) Compilers on Macintosh -LodePNG has been reported to work both with the gcc and LLVM for Macintosh, both -for C and C++. +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. *) Other Compilers -If you encounter problems on other compilers, feel free to let me know and I may -try to fix it if the compiler is modern standards complient. +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards complient. 10. examples @@ -1577,6 +1565,11 @@ yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. +*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. *) 22 dec 2013: Power of two windowsize required for optimization. *) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. *) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). @@ -1715,5 +1708,5 @@ Domain: gmail dot com. Account: lode dot vandevenne. -Copyright (c) 2005-2013 Lode Vandevenne +Copyright (c) 2005-2015 Lode Vandevenne */ -- GitLab