]> code.delx.au - refind/commitdiff
Updated LodePNG to latest version (20151024).
authorsrs5694 <srs5694@users.sourceforge.net>
Sun, 22 Nov 2015 19:12:58 +0000 (14:12 -0500)
committersrs5694 <srs5694@users.sourceforge.net>
Sun, 22 Nov 2015 19:12:58 +0000 (14:12 -0500)
NEWS.txt
debian/copyright
libeg/lodepng.c
libeg/lodepng.h
refind/main.c

index 68893db64687d03bdedd8a118449cd94487076a0..d1a373af62afce4a82b4eb6a5ad73cda81baf8b0 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -1,6 +1,8 @@
 0.10.1 (??/??/201?):
 --------------------
 
+- Updated LodePNG to latest version (20151024).
+
 - Fixed bugs in mkrlconf and in refind-install that could cause some kernel
   options to be excluded from refind_linux.conf. There were two trouble
   conditions:
index 2b9dc2ab8f6a93dab9a1f59e59fe9025606159a2..e187d06318f3c284e38934f3e0dad7dc99395bf6 100644 (file)
@@ -85,8 +85,8 @@ Files: EfiLib/*
 Copyright: 2004-2011 Intel Corp.
 License: BSD 2-clause
 
-Files: libeg/lodepng.c
-Copyright: 2005-2013 Lode Vandevenne
+Files: libeg/lodepng.[ch]
+Copyright: 2005-2015 Lode Vandevenne
 License: zlib
 
 Files: mok/*
index 0410ec105c433f934620d1ccba7a03096d732253..2bbd07e1a3fa3a1c2d617cfe2b12e6b7b059b68a 100644 (file)
@@ -1,7 +1,7 @@
 /*
-LodePNG version 20130415
+LodePNG version 20151024
 
-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
@@ -37,7 +37,12 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for
 #include <fstream>
 #endif /*LODEPNG_COMPILE_CPP*/
 
-#define VERSION_STRING "20130415"
+#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 = "20151024";
 
 /*
 This source file is built up in the following large parts. The code sections
@@ -114,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.
@@ -140,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;
 }
 
@@ -181,24 +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;
-}
-
-static void uivector_swap(uivector* p, uivector* q)
-{
-  size_t tmp;
-  unsigned* tmpp;
-  tmp = p->size; p->size = q->size; q->size = tmp;
-  tmp = p->allocsize; p->allocsize = q->allocsize; q->allocsize = tmp;
-  tmpp = p->data; p->data = q->data; q->data = tmpp;
-}
 #endif /*LODEPNG_COMPILE_ENCODER*/
 #endif /*LODEPNG_COMPILE_ZLIB*/
 
@@ -213,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)
@@ -252,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*/
@@ -311,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];
     }
@@ -327,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)
@@ -404,25 +410,25 @@ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const
 #ifdef LODEPNG_COMPILE_ZLIB
 #ifdef LODEPNG_COMPILE_ENCODER
 /*TODO: this ignores potential out of memory errors*/
-static void addBitToStream(size_t* bitpointer, ucvector* bitstream, unsigned char bit)
-{
-  /*add a new byte at the end*/
-  if((*bitpointer) % 8 == 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)++;
+#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\
+{\
+  /*add a new byte at the end*/\
+  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);\
 }
 
 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*/
 
@@ -433,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;
 }
@@ -506,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;
@@ -543,22 +549,23 @@ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree)
   uninited, a value >= numcodes is an address to another bit, a value < numcodes
   is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as
   many columns as codes - 1.
-  A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
+  A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
   Here, the internal nodes are stored (what their 0 and 1 option point to).
   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*/
@@ -570,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;
@@ -580,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*/
   }
@@ -597,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);
@@ -612,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]]++;
     }
@@ -643,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);
@@ -651,123 +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;
 }
 
-/*
-This uses a simple combsort to sort the data. This function is not critical for
-overall encoding speed and the data amount isn't that large.
-*/
-static void sort_coins(Coin* data, size_t amount)
+/*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)
 {
-  size_t gap = amount;
-  unsigned char swapped = 0;
-  while((gap > 1) || swapped)
+  unsigned lastindex = lists->chains1[c]->index;
+
+  if(c == 0)
   {
-    size_t i;
-    gap = (gap * 10) / 13; /*shrink factor 1.3*/
-    if(gap == 9 || gap == 10) gap = 11; /*combsort11*/
-    if(gap < 1) gap = 1;
-    swapped = 0;
-    for(i = 0; i < amount - gap; i++)
-    {
-      size_t j = i + gap;
-      if(data[j].weight < data[i].weight)
-      {
-        float temp = data[j].weight; data[j].weight = data[i].weight; data[i].weight = temp;
-        uivector_swap(&data[i].symbols, &data[j].symbols);
-        swapped = 1;
-      }
-    }
+    if(lastindex >= numpresent) return;
+    lists->chains0[c] = lists->chains1[c];
+    lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0);
   }
-}
-
-static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum)
-{
-  unsigned i;
-  unsigned j = 0; /*index of present symbols*/
-  for(i = 0; i < numcodes; i++)
+  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)
+    {
+      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))
     {
-      coins[j].weight = frequencies[i] / (float)sum;
-      uivector_push_back(&coins[j].symbols, i);
-      j++;
+      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 = (int)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*/
@@ -777,82 +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;
+
+    qsort(leaves, numpresent, sizeof(BPMNode), bpmnode_compare);
 
-    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) return 83; /*alloc fail*/
-    init_coins(coins, coinmem);
-    init_coins(prev_row, coinmem);
+    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;
-    sort_coins(coins, numcoins);
     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;
-
-        cleanup_coins(coins, numcoins);
-        init_coins(coins, numcoins);
+      for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i];
 
-        numcoins = 0;
+      bpmnode_create(&lists, leaves[0].weight, 1, 0);
+      bpmnode_create(&lists, leaves[1].weight, 2, 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;
-        }
-        sort_coins(coins, numcoins);
+      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, (int)maxbitlen - 1, (int)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;
 }
 
@@ -861,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));
@@ -893,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);
 
@@ -912,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);
@@ -937,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*/
 
@@ -976,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;
@@ -985,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)
@@ -994,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*/
@@ -1007,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;
@@ -1019,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*/
@@ -1129,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*/
     {
@@ -1148,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*/
@@ -1168,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)
@@ -1198,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;
     }
   }
@@ -1211,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;
 
@@ -1247,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;
@@ -1257,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*/
@@ -1267,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;
 }
 
@@ -1321,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)*/
@@ -1356,30 +1338,23 @@ static void addLengthDistance(uivector* values, size_t length, size_t distance)
   uivector_push_back(values, extra_distance);
 }
 
+/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3
+bytes as input because 3 is the minimum match length for deflate*/
 static const unsigned HASH_NUM_VALUES = 65536;
-static const unsigned HASH_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)
@@ -1388,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;
 }
@@ -1405,18 +1389,33 @@ 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;
-  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));
-  return result % HASH_NUM_VALUES;
+  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 = size - pos;
+    for(i = 0; i != amount; ++i) result ^= (unsigned)(data[pos + i] << (i * 8u));
+  }
+  return result & HASH_BIT_MASK;
 }
 
 static unsigned countZeros(const unsigned char* data, size_t size, size_t pos)
@@ -1425,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);
 }
 
-static void updateHashChain(Hash* hash, size_t pos, int hashval, unsigned windowsize)
+/*wpos = pos & (windowsize - 1)*/
+static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros)
 {
-  unsigned wpos = pos % windowsize;
-  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;
 }
 
 /*
@@ -1451,154 +1454,175 @@ 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 short numzeros = 0;
-  int usezeros = windowsize >= 8192; /*for small window size, the 'max chain length' optimization does a better job*/
-  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;
 
-  if(!error)
-  {
-    unsigned offset; /*the offset represents the distance in LZ77 terminology*/
-    unsigned length;
-    unsigned lazy = 0;
-    unsigned lazylength = 0, lazyoffset = 0;
-    unsigned hashval;
-    unsigned current_offset, current_length;
-    const unsigned char *lastptr, *foreptr, *backptr;
-    unsigned short hashpos, prevpos;
+  unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/
+  unsigned numzeros = 0;
 
-    for(pos = inpos; pos < insize; pos++)
-    {
-      size_t wpos = pos % windowsize; /*position for in 'circular' hash buffers*/
+  unsigned offset; /*the offset represents the distance in LZ77 terminology*/
+  unsigned length;
+  unsigned lazy = 0;
+  unsigned lazylength = 0, lazyoffset = 0;
+  unsigned hashval;
+  unsigned current_offset, current_length;
+  unsigned prev_offset;
+  const unsigned char *lastptr, *foreptr, *backptr;
+  unsigned hashpos;
 
-      hashval = getHash(in, insize, pos);
-      updateHashChain(hash, pos, hashval, windowsize);
+  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(usezeros && hashval == 0)
-      {
-        numzeros = countZeros(in, insize, pos);
-        hash->zeros[wpos] = numzeros;
-      }
+  if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH;
 
-      /*the length and offset found for the current position*/
-      length = 0;
-      offset = 0;
+  for(pos = inpos; pos < insize; ++pos)
+  {
+    size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/
+    unsigned chainlength = 0;
 
-      prevpos = hash->head[hashval];
-      hashpos = hash->chain[prevpos];
+    hashval = getHash(in, insize, pos);
 
-      lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH];
+    if(usezeros && hashval == 0)
+    {
+      if(numzeros == 0) numzeros = countZeros(in, insize, pos);
+      else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros;
+    }
+    else
+    {
+      numzeros = 0;
+    }
 
-      /*search for the longest string*/
-      if(hash->val[wpos] == (int)hashval)
-      {
-        unsigned chainlength = 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;
+    updateHashChain(hash, wpos, hashval, numzeros);
 
-          current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize;
-          if(current_offset > 0)
-          {
-            /*test the next characters*/
-            foreptr = &in[pos];
-            backptr = &in[pos - current_offset];
+    /*the length and offset found for the current position*/
+    length = 0;
+    offset = 0;
 
-            /*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*/)
-            {
-              unsigned short skip = hash->zeros[hashpos];
-              if(skip > numzeros) skip = numzeros;
-              backptr += skip;
-              foreptr += skip;
-            }
+    hashpos = hash->chain[wpos];
 
-            /* multiple checks at once per array bounds check */
-            while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/
-            {
-              ++backptr;
-              ++foreptr;
-            }
-            current_length = (unsigned)(foreptr - &in[pos]);
+    lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH];
 
-            if(current_length > length)
-            {
-              length = current_length; /*the longest length*/
-              offset = current_offset; /*the offset that is related to this longest length*/
-              /*jump out once a length of max length is found (speed gain)*/
-              if(current_length >= nicematch || current_length == MAX_SUPPORTED_DEFLATE_LENGTH) break;
-            }
-          }
+    /*search for the longest string*/
+    prev_offset = 0;
+    for(;;)
+    {
+      if(chainlength++ >= maxchainlength) break;
+      current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize;
 
-          if(hashpos == hash->chain[hashpos]) break;
+      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*/
+        foreptr = &in[pos];
+        backptr = &in[pos - current_offset];
 
-          prevpos = hashpos;
-          hashpos = hash->chain[hashpos];
+        /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/
+        if(numzeros >= 3)
+        {
+          unsigned skip = hash->zeros[hashpos];
+          if(skip > numzeros) skip = numzeros;
+          backptr += skip;
+          foreptr += skip;
         }
-      }
 
-      if(lazymatching)
-      {
-        if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH)
+        while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/
         {
-          lazy = 1;
-          lazylength = length;
-          lazyoffset = offset;
-          continue; /*try the next byte*/
+          ++backptr;
+          ++foreptr;
         }
-        if(lazy)
+        current_length = (unsigned)(foreptr - &in[pos]);
+
+        if(current_length > length)
         {
-          lazy = 0;
-          if(pos == 0) ERROR_BREAK(81);
-          if(length > lazylength + 1)
-          {
-            /*push the previous character as literal*/
-            if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/);
-          }
-          else
-          {
-            length = lazylength;
-            offset = lazyoffset;
-            hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/
-            pos--;
-          }
+          length = current_length; /*the longest length*/
+          offset = current_offset; /*the offset that is related to this longest length*/
+          /*jump out once a length of max length is found (speed gain). This also jumps
+          out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/
+          if(current_length >= nicematch) break;
         }
       }
-      if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/);
 
-      /**encode it as length/distance pair or literal value**/
-      if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
+      if(hashpos == hash->chain[hashpos]) break;
+
+      if(numzeros >= 3 && length > numzeros)
       {
-        if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
+        hashpos = hash->chainz[hashpos];
+        if(hash->zeros[hashpos] != numzeros) break;
       }
-      else if(length < minmatch || (length == 3 && offset > 4096))
+      else
       {
-        /*compensate for the fact that longer offsets have more extra bits, a
-        length of only 3 may be not worth it then*/
-        if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
+        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;
       }
-      else
+    }
+
+    if(lazymatching)
+    {
+      if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH)
       {
-        addLengthDistance(out, length, offset);
-        for(i = 1; i < length; i++)
+        lazy = 1;
+        lazylength = length;
+        lazyoffset = offset;
+        continue; /*try the next byte*/
+      }
+      if(lazy)
+      {
+        lazy = 0;
+        if(pos == 0) ERROR_BREAK(81);
+        if(length > lazylength + 1)
         {
-          pos++;
-          hashval = getHash(in, insize, pos);
-          updateHashChain(hash, pos, hashval, windowsize);
-          if(usezeros && hashval == 0)
-          {
-            hash->zeros[pos % windowsize] = countZeros(in, insize, pos);
-          }
+          /*push the previous character as literal*/
+          if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/);
+        }
+        else
+        {
+          length = lazylength;
+          offset = lazyoffset;
+          hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/
+          hash->headz[numzeros] = -1; /*idem*/
+          --pos;
         }
       }
+    }
+    if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/);
 
-    } /*end of the loop through each character of input*/
-  } /*end of "if(!error)"*/
+    /*encode it as length/distance pair or literal value*/
+    if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
+    {
+      if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
+    }
+    else if(length < minmatch || (length == 3 && offset > 4096))
+    {
+      /*compensate for the fact that longer offsets have more extra bits, a
+      length of only 3 may be not worth it then*/
+      if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
+    }
+    else
+    {
+      addLengthDistance(out, length, offset);
+      for(i = 1; i < length; ++i)
+      {
+        ++pos;
+        wpos = pos & (windowsize - 1);
+        hashval = getHash(in, insize, pos);
+        if(usezeros && hashval == 0)
+        {
+          if(numzeros == 0) numzeros = countZeros(in, insize, pos);
+          else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros;
+        }
+        else
+        {
+          numzeros = 0;
+        }
+        updateHashChain(hash, wpos, hashval, numzeros);
+      }
+    }
+  } /*end of the loop through each character of input*/
 
   return error;
 }
@@ -1612,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;
@@ -1633,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++]);
     }
@@ -1651,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));
@@ -1678,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;
 
@@ -1744,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;
       }
     }
@@ -1774,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);
@@ -1805,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);
@@ -1827,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,
@@ -1840,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]);
@@ -1876,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]));
@@ -1924,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*/
@@ -1954,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]));
     }
@@ -1982,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;
@@ -1992,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;
@@ -2055,7 +2081,7 @@ static unsigned update_adler32(unsigned adler, const unsigned char* data, unsign
     {
       s1 += (*data++);
       s2 += s1;
-      amount--;
+      --amount;
     }
     s1 %= 65521;
     s2 %= 65521;
@@ -2125,9 +2151,13 @@ static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsi
                                 size_t insize, const LodePNGDecompressSettings* settings)
 {
   if(settings->custom_zlib)
+  {
     return settings->custom_zlib(out, outsize, in, insize, settings);
+  }
   else
+  {
     return lodepng_zlib_decompress(out, outsize, in, insize, settings);
+  }
 }
 
 #endif /*LODEPNG_COMPILE_DECODER*/
@@ -2145,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;
@@ -2164,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);
   }
@@ -2198,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*/
@@ -2206,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,47 +2296,57 @@ const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0,
 /* / CRC32                                                                  / */
 /* ////////////////////////////////////////////////////////////////////////// */
 
-static unsigned Crc32_crc_table_computed = 0;
-static unsigned Crc32_crc_table[256];
 
-/*Make the table for a fast CRC.*/
-static void Crc32_make_crc_table(void)
-{
-  unsigned c, k, n;
-  for(n = 0; n < 256; n++)
-  {
-    c = n;
-    for(k = 0; k < 8; k++)
-    {
-      if(c & 1) c = 0xedb88320L ^ (c >> 1);
-      else c = c >> 1;
-    }
-    Crc32_crc_table[n] = c;
-  }
-  Crc32_crc_table_computed = 1;
-}
+#ifndef LODEPNG_NO_COMPILE_CRC
+/* CRC polynomial: 0xedb88320 */
+static unsigned lodepng_crc32_table[256] = {
+           0u, 1996959894u, 3993919788u, 2567524794u,  124634137u, 1886057615u, 3915621685u, 2657392035u,
+   249268274u, 2044508324u, 3772115230u, 2547177864u,  162941995u, 2125561021u, 3887607047u, 2428444049u,
+   498536548u, 1789927666u, 4089016648u, 2227061214u,  450548861u, 1843258603u, 4107580753u, 2211677639u,
+   325883990u, 1684777152u, 4251122042u, 2321926636u,  335633487u, 1661365465u, 4195302755u, 2366115317u,
+   997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u,
+   901097722u, 1119000684u, 3686517206u, 2898065728u,  853044451u, 1172266101u, 3705015759u, 2882616665u,
+   651767980u, 1373503546u, 3369554304u, 3218104598u,  565507253u, 1454621731u, 3485111705u, 3099436303u,
+   671266974u, 1594198024u, 3322730930u, 2970347812u,  795835527u, 1483230225u, 3244367275u, 3060149565u,
+  1994146192u,   31158534u, 2563907772u, 4023717930u, 1907459465u,  112637215u, 2680153253u, 3904427059u,
+  2013776290u,  251722036u, 2517215374u, 3775830040u, 2137656763u,  141376813u, 2439277719u, 3865271297u,
+  1802195444u,  476864866u, 2238001368u, 4066508878u, 1812370925u,  453092731u, 2181625025u, 4111451223u,
+  1706088902u,  314042704u, 2344532202u, 4240017532u, 1658658271u,  366619977u, 2362670323u, 4224994405u,
+  1303535960u,  984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u,
+  1131014506u,  879679996u, 2909243462u, 3663771856u, 1141124467u,  855842277u, 2852801631u, 3708648649u,
+  1342533948u,  654459306u, 3188396048u, 3373015174u, 1466479909u,  544179635u, 3110523913u, 3462522015u,
+  1591671054u,  702138776u, 2966460450u, 3352799412u, 1504918807u,  783551873u, 3082640443u, 3233442989u,
+  3988292384u, 2596254646u,   62317068u, 1957810842u, 3939845945u, 2647816111u,   81470997u, 1943803523u,
+  3814918930u, 2489596804u,  225274430u, 2053790376u, 3826175755u, 2466906013u,  167816743u, 2097651377u,
+  4027552580u, 2265490386u,  503444072u, 1762050814u, 4150417245u, 2154129355u,  426522225u, 1852507879u,
+  4275313526u, 2312317920u,  282753626u, 1742555852u, 4189708143u, 2394877945u,  397917763u, 1622183637u,
+  3604390888u, 2714866558u,  953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u,
+  3624741850u, 2936675148u,  906185462u, 1090812512u, 3747672003u, 2825379669u,  829329135u, 1181335161u,
+  3412177804u, 3160834842u,  628085408u, 1382605366u, 3423369109u, 3138078467u,  570562233u, 1426400815u,
+  3317316542u, 2998733608u,  733239954u, 1555261956u, 3268935591u, 3050360625u,  752459403u, 1541320221u,
+  2607071920u, 3965973030u, 1969922972u,   40735498u, 2617837225u, 3943577151u, 1913087877u,   83908371u,
+  2512341634u, 3803740692u, 2075208622u,  213261112u, 2463272603u, 3855990285u, 2094854071u,  198958881u,
+  2262029012u, 4057260610u, 1759359992u,  534414190u, 2176718541u, 4139329115u, 1873836001u,  414664567u,
+  2282248934u, 4279200368u, 1711684554u,  285281116u, 2405801727u, 4167216745u, 1634467795u,  376229701u,
+  2685067896u, 3608007406u, 1308918612u,  956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u,
+  2932959818u, 3654703836u, 1088359270u,  936918000u, 2847714899u, 3736837829u, 1202900863u,  817233897u,
+  3183342108u, 3401237130u, 1404277552u,  615818150u, 3134207493u, 3453421203u, 1423857449u,  601450431u,
+  3009837614u, 3294710456u, 1567103746u,  711928724u, 3020668471u, 3272380065u, 1510334235u,  755167117u
+};
 
-/*Update a running CRC with the bytes buf[0..len-1]--the CRC should be
-initialized to all 1's, and the transmitted value is the 1's complement of the
-final running CRC (see the crc() routine below).*/
-static unsigned Crc32_update_crc(const unsigned char* buf, unsigned crc, size_t len)
+/*Return the CRC of the bytes buf[0..len-1].*/
+unsigned lodepng_crc32(const unsigned char* buf, size_t len)
 {
-  unsigned c = crc;
+  unsigned c = 0xffffffffL;
   size_t n;
 
-  if(!Crc32_crc_table_computed) Crc32_make_crc_table();
-  for(n = 0; n < len; n++)
+  for(n = 0; n < len; ++n)
   {
-    c = Crc32_crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+    c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
   }
-  return c;
-}
-
-/*Return the CRC of the bytes buf[0..len-1].*/
-unsigned lodepng_crc32(const unsigned char* buf, size_t len)
-{
-  return Crc32_update_crc(buf, 0xffffffffL, len) ^ 0xffffffffL;
+  return c ^ 0xffffffffL;
 }
+#endif /* !LODEPNG_NO_COMPILE_CRC */
 
 /* ////////////////////////////////////////////////////////////////////////// */
 /* / Reading and writing single bits and bytes from/to stream for LodePNG   / */
@@ -2316,7 +2355,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;
 }
 
@@ -2324,7 +2363,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;
   }
@@ -2340,7 +2379,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*/
 
@@ -2349,7 +2388,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);
 }
 
 /* ////////////////////////////////////////////////////////////////////////// */
@@ -2364,7 +2403,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*/
 }
 
@@ -2442,7 +2481,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;
 }
@@ -2464,13 +2503,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);
@@ -2542,7 +2581,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;
 }
@@ -2559,10 +2598,15 @@ static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColo
     if(a->key_g != b->key_g) return 0;
     if(a->key_b != b->key_b) return 0;
   }
-  if(a->palettesize != b->palettesize) return 0;
-  for(i = 0; i < a->palettesize * 4; i++)
-  {
-    if(a->palette[i] != b->palette[i]) return 0;
+  /*if one of the palette sizes is 0, then we consider it to be the same as the
+  other: it means that e.g. the palette was not given by the user and should be
+  considered the same as the palette inside the PNG.*/
+  if(1/*a->palettesize != 0 && b->palettesize != 0*/) {
+    if(a->palettesize != b->palettesize) return 0;
+    for(i = 0; i != a->palettesize * 4; ++i)
+    {
+      if(a->palette[i] != b->palette[i]) return 0;
+    }
   }
   return 1;
 }
@@ -2591,7 +2635,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;
 }
 
@@ -2624,7 +2668,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;
   }
@@ -2648,19 +2692,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)
@@ -2669,13 +2724,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];
     }
@@ -2696,7 +2751,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]);
@@ -2711,7 +2766,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]));
   }
@@ -2734,7 +2789,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;
 
@@ -2761,7 +2816,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]);
@@ -2782,7 +2837,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]));
@@ -2811,7 +2866,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;
@@ -2890,13 +2945,14 @@ void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b)
 
 /* ////////////////////////////////////////////////////////////////////////// */
 
-/*index: bitgroup index, bits: bitgroup size(1, 2 or 4, in: bitgroup value, out: octet array to add bits to*/
+/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/
 static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in)
 {
+  unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/
   /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/
-  unsigned p = index % (8 / bits);
-  in &= (1 << bits) - 1; /*filter out any other bits of the input value*/
-  in = in << (bits * (8 / bits - p - 1));
+  unsigned p = index & m;
+  in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/
+  in = in << (bits * (m - p));
   if(p == 0) out[index * bits / 8] = in;
   else out[index * bits / 8] |= in;
 }
@@ -2918,14 +2974,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])
     {
@@ -2939,7 +2995,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;
@@ -2958,10 +3014,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])
@@ -2971,7 +3027,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*/
@@ -3011,7 +3067,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)
   {
@@ -3049,11 +3105,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*/;
@@ -3088,16 +3143,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)
   {
@@ -3154,8 +3206,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;
     }
@@ -3197,8 +3249,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
@@ -3206,10 +3256,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;
@@ -3217,7 +3266,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;
@@ -3225,7 +3274,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;
@@ -3235,7 +3284,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;
@@ -3247,7 +3296,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];
@@ -3258,7 +3307,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];
@@ -3274,15 +3323,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;
       }
@@ -3299,7 +3348,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];
@@ -3307,7 +3356,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];
@@ -3318,7 +3367,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];
@@ -3328,7 +3377,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];
@@ -3337,17 +3386,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];
@@ -3376,21 +3421,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, LodePNGColorMode* mode_in,
-                         unsigned w, unsigned h, unsigned fix_png)
+                         const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,
+                         unsigned w, unsigned h)
 {
-  unsigned error = 0;
   size_t i;
   ColorTree tree;
   size_t numpixels = w * h;
@@ -3398,50 +3434,55 @@ 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;
-    if(mode_out->palettesize < palsize) palsize = mode_out->palettesize;
+    size_t palettesize = mode_out->palettesize;
+    const unsigned char* palette = mode_out->palette;
+    size_t palsize = 1u << mode_out->bitdepth;
+    /*if the user specified output palette but did not give the values, assume
+    they want the values of the input color type (assuming that one is palette).
+    Note that we never create a new palette ourselves.*/
+    if(palettesize == 0) {
+      palettesize = mode_in->palettesize;
+      palette = mode_in->palette;
+    }
+    if(palettesize < palsize) palsize = 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];
+      const unsigned char* p = &palette[i * 4];
       color_tree_add(&tree, p[0], p[1], p[2], p[3], i);
     }
   }
 
   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);
+      CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a));
     }
   }
 
@@ -3450,93 +3491,36 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
     color_tree_cleanup(&tree);
   }
 
-  return error;
+  return 0; /*no error*/
 }
 
 #ifdef LODEPNG_COMPILE_ENCODER
 
-typedef struct ColorProfile
+void lodepng_color_profile_init(LodePNGColorProfile* profile)
 {
-  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, LodePNGColorMode* mode)
-{
-  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*/
@@ -3546,323 +3530,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,
-                                  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)
       {
-        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 != 65535 && (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 == 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(!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(!profile->colored_done && (r != g || r != b))
+      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.*/
-static unsigned doAutoChooseColor(LodePNGColorMode* mode_out,
-                                  const unsigned char* image, unsigned w, unsigned h, LodePNGColorMode* mode_in,
-                                  LodePNGAutoConvert auto_convert)
+unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out,
+                                   const unsigned char* image, unsigned w, unsigned h,
+                                   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;
 }
 
@@ -3913,7 +3805,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];
@@ -3922,7 +3814,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]
@@ -3949,7 +3841,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*/
   }
@@ -3977,6 +3869,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]);
@@ -4014,53 +3911,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]);
@@ -4089,7 +3986,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*/
@@ -4124,16 +4021,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];
         }
@@ -4142,18 +4039,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*/
@@ -4179,10 +4076,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);
@@ -4214,7 +4111,7 @@ static unsigned postProcessScanlines(unsigned char* out, unsigned char* in,
       CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp));
       removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
     }
-    /*we can immediatly filter into the out buffer, no other steps needed*/
+    /*we can immediately filter into the out buffer, no other steps needed*/
     else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp));
   }
   else /*interlace_method is 1 (Adam7)*/
@@ -4224,7 +4121,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,
@@ -4257,7 +4154,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*/
@@ -4276,7 +4173,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)
   {
@@ -4284,7 +4181,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)
   {
@@ -4292,9 +4189,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*/
 
@@ -4320,8 +4217,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)
   {
@@ -4329,9 +4225,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 */
@@ -4349,7 +4245,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*/
@@ -4358,7 +4254,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*/
 
@@ -4367,7 +4263,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);
 
@@ -4395,7 +4291,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*/
 
@@ -4403,7 +4299,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*/
 
@@ -4448,7 +4344,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*/
 
@@ -4456,7 +4352,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];
@@ -4468,24 +4364,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;
@@ -4507,7 +4403,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);
@@ -4528,7 +4424,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];
@@ -4543,8 +4439,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 */
@@ -4560,6 +4456,9 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
   const unsigned char* chunk;
   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;
@@ -4573,6 +4472,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*/
 
@@ -4603,7 +4510,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*/
@@ -4697,36 +4604,46 @@ static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
     if(!IEND) chunk = lodepng_chunk_next_const(chunk);
   }
 
+  ucvector_init(&scanlines);
+  /*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)
+  {
+    /*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)
   {
-    ucvector scanlines;
-    ucvector_init(&scanlines);
-
-    /*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*/
-    }
-    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)
-    {
-      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(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png);
-      *out = outv.data;
-    }
-    ucvector_cleanup(&scanlines);
+    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, 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;
+  }
+  ucvector_cleanup(&scanlines);
 }
 
 unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,
@@ -4767,7 +4684,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;
@@ -4828,7 +4746,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);
 }
 
@@ -4921,7 +4838,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]);
@@ -4942,13 +4859,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)
   {
@@ -5007,10 +4924,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);
 
@@ -5026,7 +4943,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*/
@@ -5035,7 +4952,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);
   }
 
@@ -5053,14 +4970,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)
@@ -5071,13 +4988,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);
@@ -5122,11 +5039,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;
@@ -5157,57 +5074,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*/
@@ -5219,7 +5128,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);
 }
 
@@ -5262,7 +5171,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;
@@ -5277,9 +5186,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*/
@@ -5287,10 +5196,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);
 
@@ -5298,17 +5207,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);
             }
           }
 
@@ -5324,11 +5233,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)
   {
@@ -5338,23 +5247,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;
@@ -5371,18 +5280,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];
@@ -5408,14 +5317,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*/
@@ -5434,9 +5343,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 */
 
@@ -5451,17 +5360,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);
   }
 }
 
@@ -5486,16 +5395,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];
         }
@@ -5504,18 +5413,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);
@@ -5561,7 +5470,7 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const
       }
       else
       {
-        /*we can immediatly filter into the out buffer, no other steps needed*/
+        /*we can immediately filter into the out buffer, no other steps needed*/
         error = filter(*out, in, w, h, &info_png->color, settings);
       }
     }
@@ -5586,7 +5495,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)
         {
@@ -5622,9 +5531,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)
     {
@@ -5677,17 +5587,12 @@ 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 = doAutoChooseColor(&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;
 
-  if(state->encoder.zlibsettings.windowsize > 32768)
-  {
-    CERROR_RETURN_ERROR(state->error, 60); /*error: windowsize larger than allowed*/
-  }
   if(state->encoder.zlibsettings.btype > 2)
   {
     CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/
@@ -5711,7 +5616,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);
@@ -5774,7 +5679,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)
       {
@@ -5787,15 +5692,19 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
         break;
       }
       if(state->encoder.text_compression)
+      {
         addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings);
+      }
       else
+      {
         addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]);
+      }
     }
     /*LodePNG version id in text chunk*/
     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"))
         {
@@ -5804,10 +5713,12 @@ 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)
       {
@@ -5831,7 +5742,6 @@ unsigned lodepng_encode(unsigned char** out, size_t* outsize,
       if(state->error) break;
     }
 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-    /*IEND*/
     addChunk_IEND(&outv);
 
     break; /*this isn't really a while loop; no error happened so break out now!*/
@@ -5900,7 +5810,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
@@ -5963,10 +5873,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";
@@ -6009,11 +5915,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";
 }
@@ -6025,7 +5935,6 @@ const char* lodepng_error_text(unsigned code)
 /* ////////////////////////////////////////////////////////////////////////// */
 /* ////////////////////////////////////////////////////////////////////////// */
 
-
 #ifdef LODEPNG_COMPILE_CPP
 namespace lodepng
 {
@@ -6046,12 +5955,14 @@ void load_file(std::vector<unsigned char>& buffer, const std::string& filename)
 }
 
 /*write given buffer to the file, overwriting the file, it doesn't append to it.*/
-void save_file(const std::vector<unsigned char>& buffer, const std::string& filename)
+unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename)
 {
   std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary);
+  if(!file) return 79;
   file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size()));
+  return 0;
 }
-#endif //LODEPNG_COMPILE_DISK
+#endif /* LODEPNG_COMPILE_DISK */
 
 #ifdef LODEPNG_COMPILE_ZLIB
 #ifdef LODEPNG_COMPILE_DECODER
@@ -6074,7 +5985,7 @@ unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned
 {
   return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings);
 }
-#endif //LODEPNG_COMPILE_DECODER
+#endif /* LODEPNG_COMPILE_DECODER */
 
 #ifdef LODEPNG_COMPILE_ENCODER
 unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
@@ -6096,8 +6007,8 @@ unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned ch
 {
   return compress(out, in.empty() ? 0 : &in[0], in.size(), settings);
 }
-#endif //LODEPNG_COMPILE_ENCODER
-#endif //LODEPNG_COMPILE_ZLIB
+#endif /* LODEPNG_COMPILE_ENCODER */
+#endif /* LODEPNG_COMPILE_ZLIB */
 
 
 #ifdef LODEPNG_COMPILE_PNG
@@ -6153,14 +6064,14 @@ unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
                 State& state,
                 const unsigned char* in, size_t insize)
 {
-  unsigned char* buffer;
+  unsigned char* buffer = NULL;
   unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
   if(buffer && !error)
   {
     size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
     out.insert(out.end(), &buffer[0], &buffer[buffersize]);
-    lodepng_free(buffer);
   }
+  lodepng_free(buffer);
   return error;
 }
 
@@ -6179,8 +6090,8 @@ unsigned decode(std::vector<unsigned char>& 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<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h,
@@ -6235,7 +6146,7 @@ unsigned encode(const std::string& filename,
 {
   std::vector<unsigned char> buffer;
   unsigned error = encode(buffer, in, w, h, colortype, bitdepth);
-  if(!error) save_file(buffer, filename);
+  if(!error) error = save_file(buffer, filename);
   return error;
 }
 
@@ -6246,8 +6157,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*/
index 42bd04b9ee53d0b452aaccc0f005d0a7c5bbbfc3..bd3b7149a93038e677e8cef3d8db8e6980a0ed46 100644 (file)
@@ -1,7 +1,7 @@
 /*
-LodePNG version 20130415
+LodePNG version 20151024
 
-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
@@ -22,6 +22,12 @@ freely, subject to the following restrictions:
     3. This notice may not be removed or altered from any source
     distribution.
 */
+/*
+ * This version of lodepng.h is modified for use with rEFInd. Some options
+ * are commented out and two definitions (commented on shortly) are added
+ * for GNU-EFI compatibility. The associated lodepng.c file is unmodified
+ * from the original.
+ */
 
 #ifndef LODEPNG_H
 #define LODEPNG_H
@@ -32,18 +38,27 @@ freely, subject to the following restrictions:
 // and associated function in lodepng_xtra.c)
 int MyStrlen(const char *InString);
 #define strlen(c) MyStrlen(c)
+#ifdef __MAKEWITH_GNUEFI
+#include <efi.h>
+#include <efilib.h>
+#define memcpy(a, b, c) CopyMem(a, b, c)
+#endif
 
 #ifdef __cplusplus
 #include <vector>
 #include <string>
 #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.
 The "NO_COMPILE" defines are designed to be used to pass as defines to the
 compiler command to disable them without modifying this header, e.g.
 -DLODEPNG_NO_COMPILE_ZLIB for gcc.
+In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to
+allow implementing a custom lodepng_crc32.
 */
 /*deflate & zlib. If disabled, you must specify alternative zlib functions in
 the custom_zlib field of the compress and decompress settings*/
@@ -200,7 +215,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<unsigned char>& out, unsigned& w, unsigned& h,
                 const unsigned char* in, size_t insize,
                 LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
@@ -215,11 +231,12 @@ Same as the other decode functions, but instead takes a filename as input.
 unsigned decode(std::vector<unsigned char>& 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<unsigned char>& out,
                 const unsigned char* in, unsigned w, unsigned h,
                 LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
@@ -238,9 +255,9 @@ unsigned encode(const std::string& filename,
 unsigned encode(const std::string& filename,
                 const std::vector<unsigned char>& 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*/
 
@@ -267,7 +284,7 @@ struct LodePNGDecompressSettings
                              const unsigned char*, size_t,
                              const LodePNGDecompressSettings*);
 
-  void* custom_context; /*optional custom settings for custom functions*/
+  const void* custom_context; /*optional custom settings for custom functions*/
 };
 
 extern const LodePNGDecompressSettings lodepng_default_decompress_settings;
@@ -285,7 +302,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; /*the maximum is 32768, higher gives more compression 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*/
@@ -301,7 +318,7 @@ struct LodePNGCompressSettings /*deflate = compress*/
                              const unsigned char*, size_t,
                              const LodePNGCompressSettings*);
 
-  void* custom_context; /*optional custom settings for custom functions*/
+  const void* custom_context; /*optional custom settings for custom functions*/
 };
 
 extern const LodePNGCompressSettings lodepng_default_compress_settings;
@@ -501,14 +518,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 makes it ignore out of bound palette indices.
-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, LodePNGColorMode* mode_in,
-                         unsigned w, unsigned h, unsigned fix_png);
-
+                         const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,
+                         unsigned w, unsigned h);
 
 #ifdef LODEPNG_COMPILE_DECODER
 /*
@@ -520,7 +537,7 @@ typedef struct LodePNGDecoderSettings
   LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/
 
   unsigned ignore_crc; /*ignore CRC checksums*/
-  unsigned fix_png; /*if 1, try to parse some broken PNG images, e.g. with out of bound palette.*/
+
   unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
 
 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
@@ -539,7 +556,7 @@ typedef enum LodePNGFilterStrategy
 {
   /*every filter at zero*/
   LFS_ZERO,
-  /*Use filter that gives minumum sum, as described in the official PNG filter heuristic.*/
+  /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/
   LFS_MINSUM,
   /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending
   on the image, this is better or worse than minsum.*/
@@ -553,35 +570,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;
-
+  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);
 
 /*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
@@ -595,7 +616,7 @@ typedef struct LodePNGEncoderSettings
   the same length as the amount of scanlines in the image, and each value must <= 5. You
   have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero
   must be set to 0 to ensure this is also used on palette or low bitdepth images.*/
-  unsigned char* predefined_filters;
+  const unsigned char* predefined_filters;
 
   /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette).
   If colortype is 3, PLTE is _always_ created.*/
@@ -626,7 +647,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;
@@ -676,7 +697,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*/
@@ -804,7 +829,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
@@ -818,7 +843,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<unsigned char>& out, unsigned& w, unsigned& h,
                 State& state,
                 const unsigned char* in, size_t insize);
@@ -828,7 +853,7 @@ unsigned decode(std::vector<unsigned char>& 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<unsigned char>& out,
                 const unsigned char* in, unsigned w, unsigned h,
                 State& state);
@@ -848,38 +873,38 @@ void load_file(std::vector<unsigned char>& buffer, const std::string& filename);
 Save the binary data in an std::vector to a file on disk. The file is overwritten
 without warning.
 */
-void save_file(const std::vector<unsigned char>& buffer, const std::string& filename);
-#endif //LODEPNG_COMPILE_DISK
-#endif //LODEPNG_COMPILE_PNG
+unsigned save_file(const std::vector<unsigned char>& buffer, const std::string& filename);
+#endif /* LODEPNG_COMPILE_DISK */
+#endif /* LODEPNG_COMPILE_PNG */
 
 #ifdef LODEPNG_COMPILE_ZLIB
 #ifdef LODEPNG_COMPILE_DECODER
-//Zlib-decompress an unsigned char buffer
+/* Zlib-decompress an unsigned char buffer */
 unsigned decompress(std::vector<unsigned char>& 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<unsigned char>& out, const std::vector<unsigned char>& 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<unsigned char>& 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<unsigned char>& out, const std::vector<unsigned char>& 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*/
 
 /*
 TODO:
 [.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often
-[.] check compatibility with vareous compilers  - done but needs to be redone for every newer version
+[.] check compatibility with various compilers  - done but needs to be redone for every newer version
 [X] converting color to 16-bit per channel types
 [ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values)
 [ ] make sure encoder generates no chunks with size > (2^31)-1
@@ -887,8 +912,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*/
@@ -1226,20 +1251,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
@@ -1261,7 +1288,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:
@@ -1271,10 +1298,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.
@@ -1441,6 +1468,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.
 
@@ -1456,49 +1485,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
 
-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
+The Mingw compiler (a port of gcc for Windows) should be fully supported by
+LodePNG.
 
-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).
+*) Visual Studio and Visual C++ Express Edition
+
+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
@@ -1560,6 +1580,13 @@ yyyymmdd.
 Some changes aren't backwards compatible. Those are indicated with a (!)
 symbol.
 
+*) 24 okt 2015: Bugfix with decoding to palette output.
+*) 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).
 *) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_"
@@ -1579,7 +1606,7 @@ symbol.
 *) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed
     redundant C++ codec classes. Reduced amount of structs. Everything changed,
     but it is cleaner now imho and functionality remains the same. Also fixed
-    several bugs and shrinked the implementation code. Made new samples.
+    several bugs and shrunk the implementation code. Made new samples.
 *) 6 nov 2011 (!): By default, the encoder now automatically chooses the best
     PNG color model and bit depth, based on the amount and type of colors of the
     raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color.
@@ -1614,7 +1641,7 @@ symbol.
 *) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor.
 *) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder.
 *) 17 jan 2008: ability to encode and decode compressed zTXt chunks added
-    Also vareous fixes, such as in the deflate and the padding bits code.
+    Also various fixes, such as in the deflate and the padding bits code.
 *) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved
     filtering code of encoder.
 *) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A
@@ -1697,5 +1724,5 @@ Domain: gmail dot com.
 Account: lode dot vandevenne.
 
 
-Copyright (c) 2005-2013 Lode Vandevenne
+Copyright (c) 2005-2015 Lode Vandevenne
 */
index 55ce8d4b50d9c5e8a5617b2dcd99e650d1d6ec90..ba3368b646efac958da47642e8488a4ebdc01c79 100644 (file)
@@ -193,7 +193,7 @@ static VOID AboutrEFInd(VOID)
 
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.10.0.2");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.10.0.3");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith");