summaryrefslogtreecommitdiffstats
path: root/src/lodepng.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lodepng.cpp')
-rw-r--r--src/lodepng.cpp1971
1 files changed, 200 insertions, 1771 deletions
diff --git a/src/lodepng.cpp b/src/lodepng.cpp
index 66335aa..bdf292d 100644
--- a/src/lodepng.cpp
+++ b/src/lodepng.cpp
@@ -46,8 +46,64 @@ About these tools (vector, uivector, ucvector and string):
-They're not used in the interface, only internally in this file, so all their functions are made static.
*/
-#ifdef LODEPNG_COMPILE_ZLIB
-#ifdef LODEPNG_COMPILE_ENCODER
+//--------------------------------------------------------------------------------------------
+
+
+/*LodePNG_chunk functions: These functions need as input a large enough amount of allocated memory.*/
+
+static unsigned LodePNG_chunk_length(const unsigned char* chunk); /*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/
+
+static void LodePNG_chunk_type(char type[5], const unsigned char* chunk); /*puts the 4-byte type in null terminated string*/
+static unsigned char LodePNG_chunk_type_equals(const unsigned char* chunk, const char* type); /*check if the type is the given type*/
+
+/*properties of PNG chunks gotten from capitalization of chunk type name, as defined by the standard*/
+static unsigned char LodePNG_chunk_critical(const unsigned char* chunk); /*0: ancillary chunk, 1: it's one of the critical chunk types*/
+static unsigned char LodePNG_chunk_private(const unsigned char* chunk); /*0: public, 1: private*/
+static unsigned char LodePNG_chunk_safetocopy(const unsigned char* chunk); /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy*/
+
+static unsigned char* LodePNG_chunk_data(unsigned char* chunk); /*get pointer to the data of the chunk*/
+static const unsigned char* LodePNG_chunk_data_const(const unsigned char* chunk); /*get pointer to the data of the chunk*/
+
+static unsigned LodePNG_chunk_check_crc(const unsigned char* chunk); /*returns 0 if the crc is correct, 1 if it's incorrect*/
+static void LodePNG_chunk_generate_crc(unsigned char* chunk); /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/
+
+/*iterate to next chunks.*/
+static unsigned char* LodePNG_chunk_next(unsigned char* chunk);
+static const unsigned char* LodePNG_chunk_next_const(const unsigned char* chunk);
+
+/*add chunks to out buffer. It reallocs the buffer to append the data. returns error code*/
+static unsigned LodePNG_append_chunk(unsigned char** out, size_t* outlength, const unsigned char* chunk); /*appends chunk that was already created, to the data. Returns pointer to start of appended chunk, or NULL if error happened*/
+static unsigned LodePNG_create_chunk(unsigned char** out, size_t* outlength, unsigned length, const char* type, const unsigned char* data); /*appends new chunk to out. Returns pointer to start of appended chunk, or NULL if error happened; may change memory address of out buffer*/
+
+static void LodePNG_InfoColor_init(LodePNG_InfoColor* info);
+static void LodePNG_InfoColor_cleanup(LodePNG_InfoColor* info);
+static unsigned LodePNG_InfoColor_copy(LodePNG_InfoColor* dest, const LodePNG_InfoColor* source);
+
+/*Use these functions instead of allocating palette manually*/
+static void LodePNG_InfoColor_clearPalette(LodePNG_InfoColor* info);
+
+/*additional color info*/
+static unsigned LodePNG_InfoColor_getBpp(const LodePNG_InfoColor* info); /*bits per pixel*/
+static unsigned LodePNG_InfoColor_getChannels(const LodePNG_InfoColor* info); /*amount of channels*/
+static unsigned LodePNG_InfoColor_isGreyscaleType(const LodePNG_InfoColor* info); /*is it a greyscale type? (colorType 0 or 4)*/
+static unsigned LodePNG_InfoColor_isAlphaType(const LodePNG_InfoColor* info); /*has it an alpha channel? (colorType 2 or 6)*/
+
+static void LodePNG_InfoPng_init(LodePNG_InfoPng* info);
+static void LodePNG_InfoPng_cleanup(LodePNG_InfoPng* info);
+static unsigned LodePNG_InfoPng_copy(LodePNG_InfoPng* dest, const LodePNG_InfoPng* source);
+
+static void LodePNG_InfoRaw_init(LodePNG_InfoRaw* info);
+static void LodePNG_InfoRaw_cleanup(LodePNG_InfoRaw* info);
+static unsigned LodePNG_InfoRaw_copy(LodePNG_InfoRaw* dest, const LodePNG_InfoRaw* source);
+
+/*
+LodePNG_convert: 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, where bpp is the bits per pixel of the output color type (LodePNG_InfoColor_getBpp)
+*/
+unsigned LodePNG_convert(unsigned char* out, const unsigned char* in, LodePNG_InfoColor* infoOut, LodePNG_InfoColor* infoIn, unsigned w, unsigned h);
+
+
+//--------------------------------------------------------------------------------------------
typedef struct vector /*this one is used only by the deflate compressor*/
{
@@ -115,12 +171,9 @@ static void* vector_get(vector* p, size_t index)
{
return &((char*)p->data)[index * p->typesize];
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
-#endif /*LODEPNG_COMPILE_ZLIB*/
/* /////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_ZLIB
typedef struct uivector
{
unsigned* data;
@@ -167,7 +220,6 @@ static void uivector_init(uivector* p)
p->size = p->allocsize = 0;
}
-#ifdef LODEPNG_COMPILE_ENCODER
static unsigned uivector_push_back(uivector* p, unsigned c) /*returns 1 if success, 0 if failure ==> nothing done*/
{
if(!uivector_resize(p, p->size + 1)) return 0;
@@ -191,8 +243,6 @@ static void uivector_swap(uivector* p, uivector* q)
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*/
/* /////////////////////////////////////////////////////////////////////////// */
@@ -228,17 +278,6 @@ static unsigned ucvector_resize(ucvector* p, size_t size) /*returns 1 if success
return 1;
}
-#ifdef LODEPNG_COMPILE_DECODER
-#ifdef LODEPNG_COMPILE_PNG
-static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) /*resize and give all new elements the value*/
-{
- size_t oldsize = p->size, i;
- if(!ucvector_resize(p, size)) return 0;
- for(i = oldsize; i < size; i++) p->data[i] = value;
- return 1;
-}
-#endif /*LODEPNG_COMPILE_PNG*/
-#endif /*LODEPNG_COMPILE_DECODER*/
static void ucvector_init(ucvector* p)
{
@@ -246,14 +285,12 @@ static void ucvector_init(ucvector* p)
p->size = p->allocsize = 0;
}
-#ifdef LODEPNG_COMPILE_ZLIB
/*you can both convert from vector to buffer&size and vica versa*/
static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size)
{
p->data = buffer;
p->allocsize = p->size = size;
}
-#endif /*LODEPNG_COMPILE_ZLIB*/
static unsigned ucvector_push_back(ucvector* p, unsigned char c) /*returns 1 if success, 0 if failure ==> nothing done*/
{
@@ -264,8 +301,6 @@ static unsigned ucvector_push_back(ucvector* p, unsigned char c) /*returns 1 if
/* /////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_PNG
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
static unsigned string_resize(char** out, size_t size) /*returns 1 if success, 0 if failure ==> nothing done*/
{
char* data = (char*)realloc(*out, size + 1);
@@ -294,16 +329,12 @@ static void string_set(char** out, const char* in)
size_t insize = strlen(in), i = 0;
if(string_resize(out, insize)) for(i = 0; i < insize; i++) (*out)[i] = in[i];
}
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-#endif /*LODEPNG_COMPILE_PNG*/
-#ifdef LODEPNG_COMPILE_ZLIB
/* ////////////////////////////////////////////////////////////////////////// */
/* / Reading and writing single bits and bytes from/to stream for Deflate / */
/* ////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_ENCODER
static void addBitToStream(size_t* bitpointer, ucvector* bitstream, unsigned char bit)
{
if((*bitpointer) % 8 == 0) ucvector_push_back(bitstream, 0); /*add a new byte at the end*/
@@ -322,23 +353,7 @@ static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, uns
size_t i;
for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1));
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
-#ifdef LODEPNG_COMPILE_DECODER
-static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream)
-{
- unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> ((*bitpointer) & 0x7)) & 1);
- (*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++) result += ((unsigned)readBitFromStream(bitpointer, bitstream)) << i;
- return result;
-}
-#endif /*LODEPNG_COMPILE_DECODER*/
/* ////////////////////////////////////////////////////////////////////////// */
/* / Deflate - Huffman / */
@@ -363,7 +378,6 @@ static const unsigned CLCL[NUM_CODE_LENGTH_CODES] /*the order in which "code len
/* /////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_ENCODER
/*terminology used for the package-merge algorithm and the coin collector's problem*/
typedef struct Coin /*a coin can be multiple coins (when they're merged)*/
{
@@ -417,7 +431,6 @@ static void Coin_sort(Coin* data, size_t amount) /*combsort*/
}
}
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
typedef struct HuffmanTree
{
@@ -461,7 +474,7 @@ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree)
unsigned nodefilled = 0; /*up to which node it is filled*/
unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/
unsigned n, i;
-
+
if(!uivector_resize(&tree->tree2d, tree->numcodes * 2)) return 9901; /*if failed return not enough memory error*/
/*convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means 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. 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*/
@@ -489,7 +502,7 @@ static unsigned HuffmanTree_make2DTree(HuffmanTree* tree)
else treepos = tree->tree2d.data[2 * treepos + bit] - tree->numcodes;
}
for(n = 0; n < tree->numcodes * 2; n++) if(tree->tree2d.data[n] == 32767) tree->tree2d.data[n] = 0; /*remove possible remaining 32767's*/
-
+
return 0;
}
@@ -498,14 +511,14 @@ static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) /*given that num
uivector blcount;
uivector nextcode;
unsigned bits, n, error = 0;
-
+
uivector_init(&blcount);
uivector_init(&nextcode);
if(!uivector_resize(&tree->tree1d, tree->numcodes)
|| !uivector_resizev(&blcount, tree->maxbitlen + 1, 0)
|| !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0))
error = 9902;
-
+
if(!error)
{
/*step 1: count number of instances of each code length*/
@@ -515,10 +528,10 @@ static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) /*given that num
/*step 3: generate all the codes*/
for(n = 0; n < tree->numcodes; n++) if(tree->lengths.data[n] != 0) tree->tree1d.data[n] = nextcode.data[tree->lengths.data[n]]++;
}
-
+
uivector_cleanup(&blcount);
uivector_cleanup(&nextcode);
-
+
if(!error) return HuffmanTree_make2DTree(tree);
else return error;
}
@@ -534,7 +547,6 @@ static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* b
return HuffmanTree_makeFromLengths2(tree);
}
-#ifdef LODEPNG_COMPILE_ENCODER
static unsigned HuffmanTree_fillInCoins(vector* coins, const unsigned* frequencies, unsigned numcodes, size_t sum)
{
unsigned i;
@@ -557,12 +569,12 @@ static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigne
unsigned i, j;
size_t sum = 0, numpresent = 0;
unsigned error = 0;
-
+
vector prev_row; /*type Coin, the previous row of coins*/
vector coins; /*type Coin, the coins of the currently calculated row*/
-
+
tree->maxbitlen = maxbitlen;
-
+
for(i = 0; i < numcodes; i++)
{
if(frequencies[i] > 0)
@@ -571,12 +583,12 @@ static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigne
sum += frequencies[i];
}
}
-
+
if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/
tree->numcodes = (unsigned)numcodes; /*number of symbols*/
uivector_resize(&tree->lengths, 0);
if(!uivector_resizev(&tree->lengths, tree->numcodes, 0)) return 9905;
-
+
if(numpresent == 0) /*there are no symbols at all, in that case add one symbol of value 0 to the tree (see RFC 1951 section 3.2.7) */
{
tree->lengths.data[0] = 1;
@@ -587,13 +599,13 @@ static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigne
for(i = 0; i < numcodes; i++) if(frequencies[i]) tree->lengths.data[i] = 1;
return HuffmanTree_makeFromLengths2(tree);
}
-
+
vector_init(&coins, sizeof(Coin));
vector_init(&prev_row, sizeof(Coin));
/*Package-Merge algorithm represented by coin collector's problem
For every symbol, maxbitlen coins will be created*/
-
+
/*first row, lowest denominator*/
error = HuffmanTree_fillInCoins(&coins, frequencies, tree->numcodes, sum);
if(!error)
@@ -616,31 +628,30 @@ static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigne
}
}
}
-
+
if(!error)
{
/*keep the coins with lowest weight, so that they add up to the amount of symbols - 1*/
vector_resized(&coins, numpresent - 1, Coin_cleanup);
-
+
/*calculate the lengths of each symbol, as the amount of times a coin of each symbol is used*/
for(i = 0; i < coins.size; i++)
{
Coin* coin = (Coin*)vector_get(&coins, i);
for(j = 0; j < coin->symbols.size; j++) tree->lengths.data[coin->symbols.data[j]]++;
}
-
+
error = HuffmanTree_makeFromLengths2(tree);
}
vector_cleanupd(&coins, Coin_cleanup);
vector_cleanupd(&prev_row, Coin_cleanup);
-
+
return error;
}
static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) { return tree->tree1d.data[index]; }
static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) { return tree->lengths.data[index]; }
-#endif /*LODEPNG_COMPILE_ENCODER*/
/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/
static unsigned generateFixedTree(HuffmanTree* tree)
@@ -649,7 +660,7 @@ static unsigned generateFixedTree(HuffmanTree* tree)
uivector bitlen;
uivector_init(&bitlen);
if(!uivector_resize(&bitlen, NUM_DEFLATE_CODE_SYMBOLS)) error = 9909;
-
+
if(!error)
{
/*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/
@@ -657,10 +668,10 @@ static unsigned generateFixedTree(HuffmanTree* tree)
for(i = 144; i <= 255; i++) bitlen.data[i] = 9;
for(i = 256; i <= 279; i++) bitlen.data[i] = 7;
for(i = 280; i <= 287; i++) bitlen.data[i] = 8;
-
+
error = HuffmanTree_makeFromLengths(tree, bitlen.data, NUM_DEFLATE_CODE_SYMBOLS, 15);
}
-
+
uivector_cleanup(&bitlen);
return error;
}
@@ -671,7 +682,7 @@ static unsigned generateDistanceTree(HuffmanTree* tree)
uivector bitlen;
uivector_init(&bitlen);
if(!uivector_resize(&bitlen, NUM_DISTANCE_SYMBOLS)) error = 9910;
-
+
/*there are 32 distance codes, but 30-31 are unused*/
if(!error)
{
@@ -682,308 +693,6 @@ static unsigned generateDistanceTree(HuffmanTree* tree)
return error;
}
-#ifdef LODEPNG_COMPILE_DECODER
-/*Decodes a symbol from the tree
-if decoded is true, then result contains the symbol, otherwise it contains something unspecified (because the symbol isn't fully decoded yet)
-bit is the bit that was just read from the stream
-you have to decode a full symbol (let the decode function return true) before you can try to decode another one, otherwise the state isn't reset
-return value is error.*/
-static unsigned HuffmanTree_decode(const HuffmanTree* tree, unsigned* decoded, unsigned* result, unsigned* treepos, unsigned char bit)
-{
- if((*treepos) >= tree->numcodes) return 11; /*error: it appeared outside the codetree*/
-
- (*result) = tree->tree2d.data[2 * (*treepos) + bit];
- (*decoded) = ((*result) < tree->numcodes);
-
- if(*decoded) (*treepos) = 0;
- else (*treepos) = (*result) - tree->numcodes;
-
- return 0;
-}
-
-static unsigned huffmanDecodeSymbol(unsigned int* error, const unsigned char* in, size_t* bp, const HuffmanTree* codetree, size_t inlength)
-{
- unsigned treepos = 0, decoded, ct;
- for(;;)
- {
- unsigned char bit;
- if(((*bp) & 0x07) == 0 && ((*bp) >> 3) > inlength) { *error = 10; return 0; } /*error: end of input memory reached without endcode*/
- bit = readBitFromStream(bp, in);
- *error = HuffmanTree_decode(codetree, &decoded, &ct, &treepos, bit);
- if(*error) return 0; /*stop, an error happened*/
- if(decoded) return ct;
- }
-}
-#endif /*LODEPNG_COMPILE_DECODER*/
-
-#ifdef LODEPNG_COMPILE_DECODER
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / Inflator / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/
-static void getTreeInflateFixed(HuffmanTree* tree, HuffmanTree* treeD)
-{
- /*error checking not done, this is fixed stuff, it works, it doesn't depend on the image*/
- generateFixedTree(tree);
- generateDistanceTree(treeD);
-}
-
-/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/
-static unsigned getTreeInflateDynamic(HuffmanTree* codetree, HuffmanTree* codetreeD, HuffmanTree* codelengthcodetree,
- const unsigned char* in, size_t* bp, size_t inlength)
-{
- /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/
- /*C-code note: use no "return" between ctor and dtor of an uivector!*/
- unsigned error = 0;
- unsigned n, HLIT, HDIST, HCLEN, i;
- uivector bitlen;
- uivector bitlenD;
- uivector codelengthcode;
-
- if((*bp) >> 3 >= inlength - 2) { return 49; } /*the bit pointer is or will go past the memory*/
-
- HLIT = readBitsFromStream(bp, in, 5) + 257; /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
- HDIST = readBitsFromStream(bp, in, 5) + 1; /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/
- HCLEN = readBitsFromStream(bp, in, 4) + 4; /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/
-
- /*read the code length codes out of 3 * (amount of code length codes) bits*/
- uivector_init(&codelengthcode);
- if(!uivector_resize(&codelengthcode, NUM_CODE_LENGTH_CODES)) error = 9911;
-
- if(!error)
- {
- for(i = 0; i < NUM_CODE_LENGTH_CODES; i++)
- {
- if(i < HCLEN) codelengthcode.data[CLCL[i]] = readBitsFromStream(bp, in, 3);
- else codelengthcode.data[CLCL[i]] = 0; /*if not, it must stay 0*/
- }
-
- error = HuffmanTree_makeFromLengths(codelengthcodetree, codelengthcode.data, codelengthcode.size, 7);
- }
-
- uivector_cleanup(&codelengthcode);
- if(error) return error;
-
- /*now we can use this tree to read the lengths for the tree that this function will return*/
- uivector_init(&bitlen);
- uivector_resizev(&bitlen, NUM_DEFLATE_CODE_SYMBOLS, 0);
- uivector_init(&bitlenD);
- uivector_resizev(&bitlenD, NUM_DISTANCE_SYMBOLS, 0);
- i = 0;
- if(!bitlen.data || !bitlenD.data) error = 9912;
- else while(i < HLIT + HDIST) /*i is the current symbol we're reading in the part that contains the code lengths of lit/len codes and dist codes*/
- {
- unsigned code = huffmanDecodeSymbol(&error, in, bp, codelengthcodetree, inlength);
- if(error) break;
-
- if(code <= 15) /*a length code*/
- {
- if(i < HLIT) bitlen.data[i] = code;
- else bitlenD.data[i - HLIT] = code;
- 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) >> 3 >= inlength) { error = 50; break; } /*error, bit pointer jumps past memory*/
-
- replength += readBitsFromStream(bp, in, 2);
-
- if((i - 1) < HLIT) value = bitlen.data[i - 1];
- else value = bitlenD.data[i - HLIT - 1];
- /*repeat this value in the next lengths*/
- for(n = 0; n < replength; n++)
- {
- if(i >= HLIT + HDIST) { error = 13; break; } /*error: i is larger than the amount of codes*/
- if(i < HLIT) bitlen.data[i] = value;
- else bitlenD.data[i - HLIT] = value;
- i++;
- }
- }
- else if(code == 17) /*repeat "0" 3-10 times*/
- {
- unsigned replength = 3; /*read in the bits that indicate repeat length*/
- if((*bp) >> 3 >= inlength) { error = 50; break; } /*error, bit pointer jumps past memory*/
-
- replength += readBitsFromStream(bp, in, 3);
-
- /*repeat this value in the next lengths*/
- for(n = 0; n < replength; n++)
- {
- if(i >= HLIT + HDIST) { error = 14; break; } /*error: i is larger than the amount of codes*/
- if(i < HLIT) bitlen.data[i] = 0;
- else bitlenD.data[i - HLIT] = 0;
- i++;
- }
- }
- else if(code == 18) /*repeat "0" 11-138 times*/
- {
- unsigned replength = 11; /*read in the bits that indicate repeat length*/
- if((*bp) >> 3 >= inlength) { error = 50; break; } /*error, bit pointer jumps past memory*/
- replength += readBitsFromStream(bp, in, 7);
-
- /*repeat this value in the next lengths*/
- for(n = 0; n < replength; n++)
- {
- if(i >= HLIT + HDIST) { error = 15; break; } /*error: i is larger than the amount of codes*/
- if(i < HLIT) bitlen.data[i] = 0;
- else bitlenD.data[i - HLIT] = 0;
- i++;
- }
- }
- else { error = 16; break; } /*error: somehow an unexisting code appeared. This can never happen.*/
- }
-
- if(!error && bitlen.data[256] == 0) { error = 64; } /*the length of the end code 256 must be larger than 0*/
-
- /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/
- if(!error) error = HuffmanTree_makeFromLengths(codetree, &bitlen.data[0], bitlen.size, 15);
- if(!error) error = HuffmanTree_makeFromLengths(codetreeD, &bitlenD.data[0], bitlenD.size, 15);
-
- uivector_cleanup(&bitlen);
- uivector_cleanup(&bitlenD);
-
- return error;
-}
-
-/*inflate a block with dynamic of fixed Huffman tree*/
-static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength, unsigned btype)
-{
- unsigned endreached = 0, error = 0;
- HuffmanTree codetree; /*287, the code tree for Huffman codes*/
- HuffmanTree codetreeD; /*31, the code tree for distance codes*/
-
- HuffmanTree_init(&codetree);
- HuffmanTree_init(&codetreeD);
-
- if(btype == 1) getTreeInflateFixed(&codetree, &codetreeD);
- else if(btype == 2)
- {
- HuffmanTree codelengthcodetree; /*18, the code tree for code length codes*/
- HuffmanTree_init(&codelengthcodetree);
- error = getTreeInflateDynamic(&codetree, &codetreeD, &codelengthcodetree, in, bp, inlength);
- HuffmanTree_cleanup(&codelengthcodetree);
- }
-
- while(!endreached && !error)
- {
- unsigned code = huffmanDecodeSymbol(&error, in, bp, &codetree, inlength);
- if(error) break; /*some error happened in the above function*/
- if(code == 256) endreached = 1; /*end code*/
- else if(code <= 255) /*literal symbol*/
- {
- if((*pos) >= out->size) ucvector_resize(out, ((*pos) + 1) * 2); /*reserve more room at once*/
- if((*pos) >= out->size) { error = 9913; break; } /*not enough memory*/
- out->data[(*pos)] = (unsigned char)(code);
- (*pos)++;
- }
- else if(code >= FIRST_LENGTH_CODE_INDEX && code <= LAST_LENGTH_CODE_INDEX) /*length code*/
- {
- /*part 1: get length base*/
- size_t length = LENGTHBASE[code - FIRST_LENGTH_CODE_INDEX];
- unsigned codeD, distance, numextrabitsD;
- size_t start, forward, backward, numextrabits;
-
- /*part 2: get extra bits and add the value of that to length*/
- numextrabits = LENGTHEXTRA[code - FIRST_LENGTH_CODE_INDEX];
- if(((*bp) >> 3) >= inlength) { error = 51; break; } /*error, bit pointer will jump past memory*/
- length += readBitsFromStream(bp, in, numextrabits);
-
- /*part 3: get distance code*/
- codeD = huffmanDecodeSymbol(&error, in, bp, &codetreeD, inlength);
- if(error) break;
- if(codeD > 29) { error = 18; break; } /*error: invalid distance code (30-31 are never used)*/
- distance = DISTANCEBASE[codeD];
-
- /*part 4: get extra bits from distance*/
- numextrabitsD = DISTANCEEXTRA[codeD];
- if(((*bp) >> 3) >= inlength) { error = 51; break; } /*error, bit pointer will jump past memory*/
- distance += readBitsFromStream(bp, in, numextrabitsD);
-
- /*part 5: fill in all the out[n] values based on the length and dist*/
- start = (*pos);
- backward = start - distance;
- if((*pos) + length >= out->size) ucvector_resize(out, ((*pos) + length) * 2); /*reserve more room at once*/
- if((*pos) + length >= out->size) { error = 9914; break; } /*not enough memory*/
-
- for(forward = 0; forward < length; forward++)
- {
- out->data[(*pos)] = out->data[backward];
- (*pos)++;
- backward++;
- if(backward >= start) backward = start - distance;
- }
- }
- }
-
- HuffmanTree_cleanup(&codetree);
- HuffmanTree_cleanup(&codetreeD);
-
- return error;
-}
-
-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)++;
- 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;
-
- /*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 9915; }
-
- /*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++];
-
- (*bp) = p * 8;
-
- return error;
-}
-
-/*inflate the deflated data (cfr. deflate spec); return value is the error*/
-unsigned LodeFlate_inflate(ucvector* out, const unsigned char* in, size_t insize, size_t inpos)
-{
- size_t bp = 0; /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/
- unsigned BFINAL = 0;
- size_t pos = 0; /*byte position in the out buffer*/
-
- unsigned error = 0;
-
- while(!BFINAL)
- {
- unsigned BTYPE;
- if((bp >> 3) >= insize) return 52; /*error, bit pointer will jump past memory*/
- BFINAL = readBitFromStream(&bp, &in[inpos]);
- BTYPE = 1 * readBitFromStream(&bp, &in[inpos]); BTYPE += 2 * readBitFromStream(&bp, &in[inpos]);
-
- if(BTYPE == 3) return 20; /*error: invalid BTYPE*/
- else if(BTYPE == 0) error = inflateNoCompression(out, &in[inpos], &bp, &pos, insize); /*no compression*/
- else error = inflateHuffmanBlock(out, &in[inpos], &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/
- if(error) return error;
- }
-
- if(!ucvector_resize(out, pos)) error = 9916; /*Only now we know the true size of out, resize it to that*/
-
- return error;
-}
-
-#endif /*LODEPNG_COMPILE_DECODER*/
-
-#ifdef LODEPNG_COMPILE_ENCODER
-
/* ////////////////////////////////////////////////////////////////////////// */
/* / Deflator / */
/* ////////////////////////////////////////////////////////////////////////// */
@@ -1002,7 +711,7 @@ static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t v
/*linear search implementation*/
/*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)*/
size_t left = 1;
size_t right = array_size - 1;
@@ -1028,7 +737,7 @@ static void addLengthDistance(uivector* values, size_t length, size_t distance)
unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]);
unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance);
unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]);
-
+
uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX);
uivector_push_back(values, extra_length);
uivector_push_back(values, dist_code);
@@ -1044,26 +753,26 @@ static unsigned encodeLZ77_brute(uivector* out, const unsigned char* in, size_t
/*using pointer instead of vector for input makes it faster when NOT using optimization when compiling; no influence if optimization is used*/
for(pos = 0; pos < size; pos++)
{
- /*Phase 1: doxygen images often have long runs of the same color, try to find them*/
+ /*Phase 1: doxygen images often have long runs of the same color, try to find them*/
const int minLength = 4; // Minimum length for a run to make sense
-
+
if(pos < size - minLength * 4)
{
size_t p, fp;
size_t current_length;
-
+
/*RGBA pixel run?*/
p = pos;
fp = pos + 4;
current_length = 0;
-
+
while(fp < size && in[p] == in[fp] && current_length < MAX_SUPPORTED_DEFLATE_LENGTH)
{
++p;
++fp;
++current_length;
}
-
+
if (current_length > (minLength - 1 ) * 4) /*worth using?*/
{
uivector_push_back(out, in[pos ]);
@@ -1071,30 +780,30 @@ static unsigned encodeLZ77_brute(uivector* out, const unsigned char* in, size_t
uivector_push_back(out, in[pos + 2]);
uivector_push_back(out, in[pos + 3]);
addLengthDistance(out, current_length, 4);
-
+
pos += current_length + 4 - 1; /*-1 for loop's pos++*/
continue;
}
-
+
/*RGB pixel run?*/
p = pos;
fp = pos + 3;
current_length = 0;
-
+
while(fp < size && in[p] == in[fp] && current_length < MAX_SUPPORTED_DEFLATE_LENGTH)
{
++p;
++fp;
++current_length;
}
-
+
if (current_length > (minLength - 1 ) * 3) /*worth using?*/
{
uivector_push_back(out, in[pos ]);
uivector_push_back(out, in[pos + 1]);
uivector_push_back(out, in[pos + 2]);
addLengthDistance(out, current_length, 3);
-
+
pos += current_length + 3 - 1; /*-1 for loop's pos++*/
continue;
}
@@ -1103,7 +812,7 @@ static unsigned encodeLZ77_brute(uivector* out, const unsigned char* in, size_t
size_t length = 0, offset = 0; /*the length and offset found for the current position*/
size_t max_offset = pos < windowSize ? pos : windowSize; /*how far back to test*/
size_t current_offset;
-
+
/**search for the longest string**/
for(current_offset = 1; current_offset < max_offset; current_offset++) /*search backwards through all possible distances (=offsets)*/
{
@@ -1129,7 +838,7 @@ static unsigned encodeLZ77_brute(uivector* out, const unsigned char* in, size_t
}
}
}
-
+
/**encode it as length/distance pair or literal value**/
if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
{
@@ -1173,7 +882,7 @@ static unsigned encodeLZ77(uivector* out, const unsigned char* in, size_t size,
vector table; /*HASH_NUM_VALUES uivectors; this represents what would be an std::vector<std::vector<unsigned> > in C++*/
uivector tablepos1, tablepos2;
unsigned pos, i, error = 0;
-
+
vector_init(&table, sizeof(uivector));
if(!vector_resize(&table, HASH_NUM_VALUES)) return 9917;
for(i = 0; i < HASH_NUM_VALUES; i++)
@@ -1187,7 +896,7 @@ static unsigned encodeLZ77(uivector* out, const unsigned char* in, size_t size,
uivector_init(&tablepos2);
if(!uivector_resizev(&tablepos1, HASH_NUM_VALUES, 0)) error = 9918;
if(!uivector_resizev(&tablepos2, HASH_NUM_VALUES, 0)) error = 9919;
-
+
if(!error)
{
for(pos = 0; pos < size; pos++)
@@ -1195,12 +904,12 @@ static unsigned encodeLZ77(uivector* out, const unsigned char* in, size_t size,
unsigned length = 0, offset = 0; /*the length and offset found for the current position*/
unsigned max_offset = pos < windowSize ? pos : windowSize; /*how far back to test*/
unsigned tablepos;
-
+
/*/search for the longest string*/
/*first find out where in the table to start (the first value that is in the range from "pos - max_offset" to "pos")*/
unsigned hash = getHash(in, size, pos);
if(!uivector_push_back((uivector*)vector_get(&table, hash), pos)) { error = 9920; break; }
-
+
while(((uivector*)vector_get(&table, hash))->data[tablepos1.data[hash]] < pos - max_offset) tablepos1.data[hash]++; /*it now points to the first value in the table for which the index is larger than or equal to pos - max_offset*/
while(((uivector*)vector_get(&table, hash))->data[tablepos2.data[hash]] < pos) tablepos2.data[hash]++; /*it now points to the first value in the table for which the index is larger than or equal to pos*/
@@ -1227,7 +936,7 @@ static unsigned encodeLZ77(uivector* out, const unsigned char* in, size_t size,
if(current_length == MAX_SUPPORTED_DEFLATE_LENGTH) break; /*you can jump out of this for loop once a length of max length is found (gives significant speed gain)*/
}
}
-
+
/**encode it as length/distance pair or literal value**/
if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
{
@@ -1245,7 +954,7 @@ static unsigned encodeLZ77(uivector* out, const unsigned char* in, size_t size,
}
} /*end of the loop through each character of input*/
} /*end of "if(!error)"*/
-
+
/*cleanup*/
for(i = 0; i < table.size; i++)
{
@@ -1264,24 +973,24 @@ static unsigned encodeLZ77(uivector* out, const unsigned char* in, size_t size,
static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize)
{
/*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/
-
+
size_t i, j, numdeflateblocks = datasize / 65536 + 1;
unsigned datapos = 0;
for(i = 0; i < numdeflateblocks; i++)
{
unsigned BFINAL, BTYPE, LEN, NLEN;
unsigned char firstbyte;
-
+
BFINAL = (i == numdeflateblocks - 1);
BTYPE = 0;
-
+
firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1));
ucvector_push_back(out, firstbyte);
-
+
LEN = 65535;
if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos;
NLEN = 65535 - LEN;
-
+
ucvector_push_back(out, (unsigned char)(LEN % 256));
ucvector_push_back(out, (unsigned char)(LEN / 256));
ucvector_push_back(out, (unsigned char)(NLEN % 256));
@@ -1293,7 +1002,7 @@ static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, s
ucvector_push_back(out, data[datapos++]);
}
}
-
+
return 0;
}
@@ -1310,13 +1019,13 @@ static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encode
unsigned length_index = val - FIRST_LENGTH_CODE_INDEX;
unsigned n_length_extra_bits = LENGTHEXTRA[length_index];
unsigned length_extra_bits = lz77_encoded->data[++i];
-
+
unsigned distance_code = lz77_encoded->data[++i];
-
+
unsigned distance_index = distance_code;
unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index];
unsigned distance_extra_bits = lz77_encoded->data[++i];
-
+
addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits);
addHuffmanSymbol(bp, out, HuffmanTree_getCode(codesD, distance_code), HuffmanTree_getLength(codesD, distance_code));
addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits);
@@ -1335,9 +1044,9 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
- compressed data
- 256 (end code)
*/
-
+
unsigned error = 0;
-
+
uivector lz77_encoded;
HuffmanTree codes; /*tree for literal values and length codes*/
HuffmanTree codesD; /*tree for distance codes*/
@@ -1348,11 +1057,11 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
uivector lldl;
uivector lldll; /*lit/len & dist code lengths*/
uivector clcls;
-
+
unsigned BFINAL = 1; /*make only one block... the first and final one*/
size_t numcodes, numcodesD, i, bp = 0; /*the bit pointer*/
unsigned HLIT, HDIST, HCLEN;
-
+
uivector_init(&lz77_encoded);
HuffmanTree_init(&codes);
HuffmanTree_init(&codesD);
@@ -1363,7 +1072,7 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
uivector_init(&lldl);
uivector_init(&lldll);
uivector_init(&clcls);
-
+
while(!error) /*the goto-avoiding while construct: break out to go to the cleanup phase, a break at the end makes sure the while is never repeated*/
{
if(settings->useLZ77)
@@ -1376,7 +1085,7 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
if(!uivector_resize(&lz77_encoded, datasize)) { error = 9923; break; }
for(i = 0; i < datasize; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/
}
-
+
if(!uivector_resizev(&frequencies, 286, 0)) { error = 9924; break; }
if(!uivector_resizev(&frequenciesD, 30, 0)) { error = 9925; break; }
for(i = 0; i < lz77_encoded.size; i++)
@@ -1391,27 +1100,27 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
}
}
frequencies.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/
-
+
error = HuffmanTree_makeFromFrequencies(&codes, frequencies.data, frequencies.size, 15);
if(error) break;
error = HuffmanTree_makeFromFrequencies(&codesD, frequenciesD.data, frequenciesD.size, 15);
if(error) break;
-
+
addBitToStream(&bp, out, BFINAL);
addBitToStream(&bp, out, 0); /*first bit of BTYPE "dynamic"*/
addBitToStream(&bp, out, 1); /*second bit of BTYPE "dynamic"*/
-
+
numcodes = codes.numcodes; if(numcodes > 286) numcodes = 286;
numcodesD = codesD.numcodes; if(numcodesD > 30) numcodesD = 30;
for(i = 0; i < numcodes; i++) uivector_push_back(&lldll, HuffmanTree_getLength(&codes, (unsigned)i));
for(i = 0; i < numcodesD; i++) uivector_push_back(&lldll, HuffmanTree_getLength(&codesD, (unsigned)i));
-
+
/*make lldl smaller by using repeat codes 16 (copy length 3-6 times), 17 (3-10 zeros), 18 (11-138 zeros)*/
for(i = 0; i < (unsigned)lldll.size; i++)
{
unsigned j = 0;
while(i + j + 1 < (unsigned)lldll.size && lldll.data[i + j + 1] == lldll.data[i]) j++;
-
+
if(lldll.data[i] == 0 && j >= 2)
{
j++; /*include the first zero*/
@@ -1435,7 +1144,7 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
}
else uivector_push_back(&lldl, lldll.data[i]);
}
-
+
/*generate huffmantree for the length codes of lit/len and dist codes*/
if(!uivector_resizev(&amounts, 19, 0)) { error = 9926; break; } /*16 possible lengths (0-15) and 3 repeat codes (16, 17 and 18)*/
for(i = 0; i < lldl.size; i++)
@@ -1443,10 +1152,10 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
amounts.data[lldl.data[i]]++;
if(lldl.data[i] >= 16) i++; /*after a repeat code come the bits that specify the amount, those don't need to be in the amounts calculation*/
}
-
+
error = HuffmanTree_makeFromFrequencies(&codelengthcodes, amounts.data, amounts.size, 7);
if(error) break;
-
+
if(!uivector_resize(&clcls, 19)) { error = 9927; break; }
for(i = 0; i < 19; i++) clcls.data[i] = HuffmanTree_getLength(&codelengthcodes, CLCL[i]); /*lengths of code length tree is in the order as specified by deflate*/
while(clcls.data[clcls.size - 1] == 0 && clcls.size > 4)
@@ -1454,7 +1163,7 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
if(!uivector_resize(&clcls, clcls.size - 1)) { error = 9928; break; } /*remove zeros at the end, but minimum size must be 4*/
}
if(error) break;
-
+
/*write the HLIT, HDIST and HCLEN values*/
HLIT = (unsigned)(numcodes - 257);
HDIST = (unsigned)(numcodesD - 1);
@@ -1462,10 +1171,10 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
addBitsToStream(&bp, out, HLIT, 5);
addBitsToStream(&bp, out, HDIST, 5);
addBitsToStream(&bp, out, HCLEN, 4);
-
+
/*write the code lengths of the code length alphabet*/
for(i = 0; i < HCLEN + 4; i++) addBitsToStream(&bp, out, clcls.data[i], 3);
-
+
/*write the lengths of the lit/len AND the dist alphabet*/
for(i = 0; i < lldl.size; i++)
{
@@ -1475,15 +1184,15 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
else if(lldl.data[i] == 17) addBitsToStream(&bp, out, lldl.data[++i], 3);
else if(lldl.data[i] == 18) addBitsToStream(&bp, out, lldl.data[++i], 7);
}
-
+
/*write the compressed data symbols*/
writeLZ77data(&bp, out, &lz77_encoded, &codes, &codesD);
if(HuffmanTree_getLength(&codes, 256) == 0) { error = 64; break; } /*the length of the end code 256 must be larger than 0*/
addHuffmanSymbol(&bp, out, HuffmanTree_getCode(&codes, 256), HuffmanTree_getLength(&codes, 256)); /*end code*/
-
+
break; /*end of error-while*/
}
-
+
/*cleanup*/
uivector_cleanup(&lz77_encoded);
HuffmanTree_cleanup(&codes);
@@ -1495,7 +1204,7 @@ static unsigned deflateDynamic(ucvector* out, const unsigned char* data, size_t
uivector_cleanup(&lldl);
uivector_cleanup(&lldll);
uivector_cleanup(&clcls);
-
+
return error;
}
@@ -1503,21 +1212,21 @@ static unsigned deflateFixed(ucvector* out, const unsigned char* data, size_t da
{
HuffmanTree codes; /*tree for literal values and length codes*/
HuffmanTree codesD; /*tree for distance codes*/
-
+
unsigned BFINAL = 1; /*make only one block... the first and final one*/
unsigned error = 0;
size_t i, bp = 0; /*the bit pointer*/
-
+
HuffmanTree_init(&codes);
HuffmanTree_init(&codesD);
-
+
generateFixedTree(&codes);
generateDistanceTree(&codesD);
-
+
addBitToStream(&bp, out, BFINAL);
addBitToStream(&bp, out, 1); /*first bit of BTYPE*/
addBitToStream(&bp, out, 0); /*second bit of BTYPE*/
-
+
if(settings->useLZ77) /*LZ77 encoded*/
{
uivector lz77_encoded;
@@ -1531,11 +1240,11 @@ static unsigned deflateFixed(ucvector* out, const unsigned char* data, size_t da
for(i = 0; i < datasize; i++) addHuffmanSymbol(&bp, out, HuffmanTree_getCode(&codes, data[i]), HuffmanTree_getLength(&codes, data[i]));
}
if(!error) addHuffmanSymbol(&bp, out, HuffmanTree_getCode(&codes, 256), HuffmanTree_getLength(&codes, 256)); /*"end" code*/
-
+
/*cleanup*/
HuffmanTree_cleanup(&codes);
HuffmanTree_cleanup(&codesD);
-
+
return error;
}
@@ -1549,7 +1258,6 @@ unsigned LodeFlate_deflate(ucvector* out, const unsigned char* data, size_t data
return error;
}
-#endif /*LODEPNG_COMPILE_DECODER*/
/* ////////////////////////////////////////////////////////////////////////// */
/* / Adler32 */
@@ -1559,7 +1267,7 @@ static unsigned update_adler32(unsigned adler, const unsigned char* data, unsign
{
unsigned s1 = adler & 0xffff;
unsigned s2 = (adler >> 16) & 0xffff;
-
+
while(len > 0)
{
/*at least 5550 sums can be done before the sums overflow, saving us from a lot of module divisions*/
@@ -1574,7 +1282,7 @@ static unsigned update_adler32(unsigned adler, const unsigned char* data, unsign
s1 %= 65521;
s2 %= 65521;
}
-
+
return (s2 << 16) | s1;
}
@@ -1588,7 +1296,6 @@ static unsigned adler32(const unsigned char* data, unsigned len)
/* / Reading and writing single bits and bytes from/to stream for Zlib / */
/* ////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_ENCODER
void LodeZlib_add32bitInt(ucvector* buffer, unsigned value)
{
ucvector_push_back(buffer, (unsigned char)((value >> 24) & 0xff));
@@ -1596,7 +1303,6 @@ void LodeZlib_add32bitInt(ucvector* buffer, unsigned value)
ucvector_push_back(buffer, (unsigned char)((value >> 8) & 0xff));
ucvector_push_back(buffer, (unsigned char)((value ) & 0xff));
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
unsigned LodeZlib_read32bitInt(const unsigned char* buffer)
{
@@ -1607,46 +1313,6 @@ unsigned LodeZlib_read32bitInt(const unsigned char* buffer)
/* / Zlib / */
/* ////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_DECODER
-
-unsigned LodeZlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DecompressSettings* settings)
-{
- unsigned error = 0;
- unsigned CM, CINFO, FDICT;
- ucvector outv;
-
- if(insize < 2) { error = 53; return error; } /*error, size of zlib data too small*/
- /*read information from zlib header*/
- if((in[0] * 256 + in[1]) % 31 != 0) { error = 24; return error; } /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/
-
- CM = in[0] & 15;
- CINFO = (in[0] >> 4) & 15;
- /*FCHECK = in[1] & 31; //FCHECK is already tested above*/
- FDICT = (in[1] >> 5) & 1;
- /*FLEVEL = (in[1] >> 6) & 3; //not really important, all it does it to give a compiler warning about unused variable, we don't care what encoding setting the encoder used*/
-
- if(CM != 8 || CINFO > 7) { error = 25; return error; } /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/
- if(FDICT != 0) { error = 26; return error; } /*error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."*/
-
- ucvector_init_buffer(&outv, *out, *outsize); /*ucvector-controlled version of the output buffer, for dynamic array*/
- error = LodeFlate_inflate(&outv, in, insize, 2);
- *out = outv.data;
- *outsize = outv.size;
- if(error) return error;
-
- if(!settings->ignoreAdler32)
- {
- unsigned ADLER32 = LodeZlib_read32bitInt(&in[insize - 4]);
- unsigned checksum = adler32(outv.data, (unsigned)outv.size);
- if(checksum != ADLER32) { error = 58; return error; }
- }
-
- return error;
-}
-
-#endif /*LODEPNG_COMPILE_DECODER*/
-
-#ifdef LODEPNG_COMPILE_ENCODER
unsigned LodeZlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DeflateSettings* settings)
{
@@ -1654,7 +1320,7 @@ unsigned LodeZlib_compress(unsigned char** out, size_t* outsize, const unsigned
ucvector deflatedata, outv;
size_t i;
unsigned error;
-
+
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.*/
@@ -1663,15 +1329,15 @@ unsigned LodeZlib_compress(unsigned char** out, size_t* outsize, const unsigned
unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64;
unsigned FCHECK = 31 - CMFFLG % 31;
CMFFLG += FCHECK;
-
+
ucvector_init_buffer(&outv, *out, *outsize); /*ucvector-controlled version of the output buffer, for dynamic array*/
-
+
ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256));
ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256));
-
+
ucvector_init(&deflatedata);
error = LodeFlate_deflate(&deflatedata, in, insize, settings);
-
+
if(!error)
{
ADLER32 = adler32(in, (unsigned)insize);
@@ -1679,21 +1345,15 @@ unsigned LodeZlib_compress(unsigned char** out, size_t* outsize, const unsigned
ucvector_cleanup(&deflatedata);
LodeZlib_add32bitInt(&outv, ADLER32);
}
-
+
*out = outv.data;
*outsize = outv.size;
-
+
return error;
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
-
-#endif /*LODEPNG_COMPILE_ZLIB*/
-
/* ////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_ENCODER
-
void LodeZlib_DeflateSettings_init(LodeZlib_DeflateSettings* settings)
{
settings->btype = 2; /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/
@@ -1703,19 +1363,6 @@ void LodeZlib_DeflateSettings_init(LodeZlib_DeflateSettings* settings)
const LodeZlib_DeflateSettings LodeZlib_defaultDeflateSettings = {2, 1, 2048};
-#endif /*LODEPNG_COMPILE_ENCODER*/
-
-#ifdef LODEPNG_COMPILE_DECODER
-
-void LodeZlib_DecompressSettings_init(LodeZlib_DecompressSettings* settings)
-{
- settings->ignoreAdler32 = 0;
-}
-
-const LodeZlib_DecompressSettings LodeZlib_defaultDecompressSettings = {0};
-
-#endif /*LODEPNG_COMPILE_DECODER*/
-
/* ////////////////////////////////////////////////////////////////////////// */
/* ////////////////////////////////////////////////////////////////////////// */
/* ////////////////////////////////////////////////////////////////////////// */
@@ -1728,8 +1375,6 @@ const LodeZlib_DecompressSettings LodeZlib_defaultDecompressSettings = {0};
/* ////////////////////////////////////////////////////////////////////////// */
/* ////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_PNG
-
/*
The two functions below (LodePNG_decompress and LodePNG_compress) directly call the
LodeZlib_decompress and LodeZlib_compress functions. The only purpose of the functions
@@ -1742,18 +1387,10 @@ in the other LodePNG functions.
be the size of the useful data in bytes, not the alloc size.
*/
-#ifdef LODEPNG_COMPILE_DECODER
-static unsigned LodePNG_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DecompressSettings* settings)
-{
- return LodeZlib_decompress(out, outsize, in, insize, settings);
-}
-#endif /*LODEPNG_COMPILE_DECODER*/
-#ifdef LODEPNG_COMPILE_ENCODER
static unsigned LodePNG_compress(unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize, const LodeZlib_DeflateSettings* settings)
{
return LodeZlib_compress(out, outsize, in, insize, settings);
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
/* ////////////////////////////////////////////////////////////////////////// */
/* / CRC32 / */
@@ -1779,7 +1416,7 @@ static void Crc32_make_crc_table(void)
Crc32_crc_table_computed = 1;
}
-/*Update a running CRC with the bytes buf[0..len-1]--the CRC should be
+/*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 int crc, size_t len)
@@ -1820,15 +1457,6 @@ static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned ch
return result;
}
-#ifdef LODEPNG_COMPILE_DECODER
-static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
-{
- /*the current bit in bitstream must be 0 for this to work*/
- if(bit) bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/
- (*bitpointer)++;
-}
-#endif /*LODEPNG_COMPILE_DECODER*/
-
static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
{
/*the current bit in bitstream may be 0 or 1 for this to work*/
@@ -1850,13 +1478,11 @@ static void LodePNG_set32bitInt(unsigned char* buffer, unsigned value) /*buffer
buffer[3] = (unsigned char)((value ) & 0xff);
}
-#ifdef LODEPNG_COMPILE_ENCODER
static void LodePNG_add32bitInt(ucvector* buffer, unsigned value)
{
ucvector_resize(buffer, buffer->size + 4);
LodePNG_set32bitInt(&buffer->data[buffer->size - 4], value);
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
/* ////////////////////////////////////////////////////////////////////////// */
/* / PNG chunks / */
@@ -1941,15 +1567,15 @@ unsigned LodePNG_append_chunk(unsigned char** out, size_t* outlength, const unsi
unsigned char *chunk_start, *new_buffer;
size_t new_length = (*outlength) + total_chunk_length;
if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/
-
+
new_buffer = (unsigned char*)realloc(*out, new_length);
if(!new_buffer) return 9929;
(*out) = new_buffer;
(*outlength) = new_length;
chunk_start = &(*out)[new_length - total_chunk_length];
-
+
for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i];
-
+
return 0;
}
@@ -1964,22 +1590,22 @@ unsigned LodePNG_create_chunk(unsigned char** out, size_t* outlength, unsigned l
(*out) = new_buffer;
(*outlength) = new_length;
chunk = &(*out)[(*outlength) - length - 12];
-
+
/*1: length*/
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];
-
+
/*3: the data*/
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);
-
+
return 0;
}
@@ -2074,190 +1700,6 @@ unsigned LodePNG_InfoColor_equal(const LodePNG_InfoColor* info1, const LodePNG_I
&& info1->bitDepth == info2->bitDepth; /*palette and color key not compared*/
}
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
-
-void LodePNG_UnknownChunks_init(LodePNG_UnknownChunks* chunks)
-{
- unsigned i;
- for(i = 0; i < 3; i++) chunks->data[i] = 0;
- for(i = 0; i < 3; i++) chunks->datasize[i] = 0;
-}
-
-void LodePNG_UnknownChunks_cleanup(LodePNG_UnknownChunks* chunks)
-{
- unsigned i;
- for(i = 0; i < 3; i++) free(chunks->data[i]);
-}
-
-unsigned LodePNG_UnknownChunks_copy(LodePNG_UnknownChunks* dest, const LodePNG_UnknownChunks* src)
-{
- unsigned i;
-
- LodePNG_UnknownChunks_cleanup(dest);
-
- for(i = 0; i < 3; i++)
- {
- size_t j;
- dest->datasize[i] = src->datasize[i];
- dest->data[i] = (unsigned char*)malloc(src->datasize[i]);
- if(!dest->data[i] && dest->datasize[i]) return 9932;
- for(j = 0; j < src->datasize[i]; j++) dest->data[i][j] = src->data[i][j];
- }
-
- return 0;
-}
-
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
-
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
-
-void LodePNG_Text_init(LodePNG_Text* text)
-{
- text->num = 0;
- text->keys = NULL;
- text->strings = NULL;
-}
-
-void LodePNG_Text_cleanup(LodePNG_Text* text)
-{
- LodePNG_Text_clear(text);
-}
-
-unsigned LodePNG_Text_copy(LodePNG_Text* dest, const LodePNG_Text* source)
-{
- size_t i = 0;
- dest->keys = 0;
- dest->strings = 0;
- dest->num = 0;
- for(i = 0; i < source->num; i++)
- {
- unsigned error = LodePNG_Text_add(dest, source->keys[i], source->strings[i]);
- if(error) return error;
- }
- return 0;
-}
-
-void LodePNG_Text_clear(LodePNG_Text* text)
-{
- size_t i;
- for(i = 0; i < text->num; i++)
- {
- string_cleanup(&text->keys[i]);
- string_cleanup(&text->strings[i]);
- }
- free(text->keys);
- free(text->strings);
-}
-
-unsigned LodePNG_Text_add(LodePNG_Text* text, const char* key, const char* str)
-{
- char** new_keys = (char**)(realloc(text->keys, sizeof(char*) * (text->num + 1)));
- char** new_strings = (char**)(realloc(text->strings, sizeof(char*) * (text->num + 1)));
- if(!new_keys || !new_strings)
- {
- free(new_keys);
- free(new_strings);
- return 9933;
- }
-
- text->num++;
- text->keys = new_keys;
- text->strings = new_strings;
-
- string_init(&text->keys[text->num - 1]);
- string_set(&text->keys[text->num - 1], key);
-
- string_init(&text->strings[text->num - 1]);
- string_set(&text->strings[text->num - 1], str);
-
- return 0;
-}
-
-/******************************************************************************/
-
-void LodePNG_IText_init(LodePNG_IText* text)
-{
- text->num = 0;
- text->keys = NULL;
- text->langtags = NULL;
- text->transkeys = NULL;
- text->strings = NULL;
-}
-
-void LodePNG_IText_cleanup(LodePNG_IText* text)
-{
- LodePNG_IText_clear(text);
-}
-
-unsigned LodePNG_IText_copy(LodePNG_IText* dest, const LodePNG_IText* source)
-{
- size_t i = 0;
- dest->keys = 0;
- dest->langtags = 0;
- dest->transkeys = 0;
- dest->strings = 0;
- dest->num = 0;
- for(i = 0; i < source->num; i++)
- {
- unsigned error = LodePNG_IText_add(dest, source->keys[i], source->langtags[i], source->transkeys[i], source->strings[i]);
- if(error) return error;
- }
- return 0;
-}
-
-void LodePNG_IText_clear(LodePNG_IText* text)
-{
- size_t i;
- for(i = 0; i < text->num; i++)
- {
- string_cleanup(&text->keys[i]);
- string_cleanup(&text->langtags[i]);
- string_cleanup(&text->transkeys[i]);
- string_cleanup(&text->strings[i]);
- }
- free(text->keys);
- free(text->langtags);
- free(text->transkeys);
- free(text->strings);
-}
-
-unsigned LodePNG_IText_add(LodePNG_IText* text, const char* key, const char* langtag, const char* transkey, const char* str)
-{
- char** new_keys = (char**)(realloc(text->keys, sizeof(char*) * (text->num + 1)));
- char** new_langtags = (char**)(realloc(text->langtags, sizeof(char*) * (text->num + 1)));
- char** new_transkeys = (char**)(realloc(text->transkeys, sizeof(char*) * (text->num + 1)));
- char** new_strings = (char**)(realloc(text->strings, sizeof(char*) * (text->num + 1)));
- if(!new_keys || !new_langtags || !new_transkeys || !new_strings)
- {
- free(new_keys);
- free(new_langtags);
- free(new_transkeys);
- free(new_strings);
- return 9934;
- }
-
- text->num++;
- text->keys = new_keys;
- text->langtags = new_langtags;
- text->transkeys = new_transkeys;
- text->strings = new_strings;
-
- string_init(&text->keys[text->num - 1]);
- string_set(&text->keys[text->num - 1], key);
-
- string_init(&text->langtags[text->num - 1]);
- string_set(&text->langtags[text->num - 1], langtag);
-
- string_init(&text->transkeys[text->num - 1]);
- string_set(&text->transkeys[text->num - 1], transkey);
-
- string_init(&text->strings[text->num - 1]);
- string_set(&text->strings[text->num - 1], str);
-
- return 0;
-}
-
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
void LodePNG_InfoPng_init(LodePNG_InfoPng* info)
{
@@ -2266,31 +1708,11 @@ void LodePNG_InfoPng_init(LodePNG_InfoPng* info)
info->interlaceMethod = 0;
info->compressionMethod = 0;
info->filterMethod = 0;
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- info->background_defined = 0;
- info->background_r = info->background_g = info->background_b = 0;
-
- LodePNG_Text_init(&info->text);
- LodePNG_IText_init(&info->itext);
-
- info->time_defined = 0;
- info->phys_defined = 0;
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- LodePNG_UnknownChunks_init(&info->unknown_chunks);
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
}
void LodePNG_InfoPng_cleanup(LodePNG_InfoPng* info)
{
LodePNG_InfoColor_cleanup(&info->color);
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- LodePNG_Text_cleanup(&info->text);
- LodePNG_IText_cleanup(&info->itext);
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- LodePNG_UnknownChunks_cleanup(&info->unknown_chunks);
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
}
unsigned LodePNG_InfoPng_copy(LodePNG_InfoPng* dest, const LodePNG_InfoPng* source)
@@ -2300,16 +1722,6 @@ unsigned LodePNG_InfoPng_copy(LodePNG_InfoPng* dest, const LodePNG_InfoPng* sour
*dest = *source;
LodePNG_InfoColor_init(&dest->color);
error = LodePNG_InfoColor_copy(&dest->color, &source->color); if(error) return error;
-
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- error = LodePNG_Text_copy(&dest->text, &source->text); if(error) return error;
- error = LodePNG_IText_copy(&dest->itext, &source->itext); if(error) return error;
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- LodePNG_UnknownChunks_init(&dest->unknown_chunks);
- error = LodePNG_UnknownChunks_copy(&dest->unknown_chunks, &source->unknown_chunks); if(error) return error;
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
return error;
}
@@ -2364,7 +1776,7 @@ unsigned LodePNG_convert(unsigned char* out, const unsigned char* in, LodePNG_In
const unsigned OUT_BYTES = LodePNG_InfoColor_getBpp(infoOut) / 8; /*bytes per pixel in the output image*/
const unsigned OUT_ALPHA = LodePNG_InfoColor_isAlphaType(infoOut); /*use 8-bit alpha channel*/
size_t i, c, bp = 0; /*bitpointer, used by less-than-8-bit color types*/
-
+
/*cases where in and out already have the same format*/
if(LodePNG_InfoColor_equal(infoIn, infoOut))
{
@@ -2543,7 +1955,7 @@ unsigned LodePNG_convert(unsigned char* out, const unsigned char* in, LodePNG_In
}
}
else return 59;
-
+
return 0;
}
@@ -2554,7 +1966,7 @@ static int paethPredictor(int a, int b, int c)
int pa = p > a ? p - a : a - p;
int pb = p > b ? p - b : b - p;
int pc = p > c ? p - c : c - p;
-
+
if(pa <= pb && pa <= pc) return a;
else if(pb <= pc) return b;
else return c;
@@ -2571,7 +1983,7 @@ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t fil
{
/*the passstart values have 8 values: the 8th one actually indicates the byte after the end of the 7th (= last) pass*/
unsigned i;
-
+
/*calculate width and height in pixels of each pass*/
for(i = 0; i < 7; i++)
{
@@ -2580,7 +1992,7 @@ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t fil
if(passw[i] == 0) passh[i] = 0;
if(passh[i] == 0) passw[i] = 0;
}
-
+
filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
for(i = 0; i < 7; i++)
{
@@ -2590,684 +2002,6 @@ static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t fil
}
}
-#ifdef LODEPNG_COMPILE_DECODER
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / PNG Decoder / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-/*read the information from the header and store it in the LodePNG_Info. return value is error*/
-void LodePNG_inspect(LodePNG_Decoder* decoder, const unsigned char* in, size_t inlength)
-{
- if(inlength == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/
- if(inlength < 29) { decoder->error = 27; return; } /*error: the data length is smaller than the length of the header*/
-
- /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/
- LodePNG_InfoPng_cleanup(&decoder->infoPng);
- LodePNG_InfoPng_init(&decoder->infoPng);
- decoder->error = 0;
-
- if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { decoder->error = 28; return; } /*error: the first 8 bytes are not the correct PNG signature*/
- if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { decoder->error = 29; return; } /*error: it doesn't start with a IHDR chunk!*/
-
- /*read the values given in the header*/
- decoder->infoPng.width = LodePNG_read32bitInt(&in[16]);
- decoder->infoPng.height = LodePNG_read32bitInt(&in[20]);
- decoder->infoPng.color.bitDepth = in[24];
- decoder->infoPng.color.colorType = in[25];
- decoder->infoPng.compressionMethod = in[26];
- decoder->infoPng.filterMethod = in[27];
- decoder->infoPng.interlaceMethod = in[28];
-
- if(!decoder->settings.ignoreCrc)
- {
- unsigned CRC = LodePNG_read32bitInt(&in[29]);
- unsigned checksum = Crc32_crc(&in[12], 17);
- if(CRC != checksum) { decoder->error = 57; return; }
- }
-
- if(decoder->infoPng.compressionMethod != 0) { decoder->error = 32; return; } /*error: only compression method 0 is allowed in the specification*/
- if(decoder->infoPng.filterMethod != 0) { decoder->error = 33; return; } /*error: only filter method 0 is allowed in the specification*/
- if(decoder->infoPng.interlaceMethod > 1) { decoder->error = 34; return; } /*error: only interlace methods 0 and 1 exist in the specification*/
-
- decoder->error = checkColorValidity(decoder->infoPng.color.colorType, decoder->infoPng.color.bitDepth);
-}
-
-static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length)
-{
- /*
- For PNG filter method 0
- unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, the filter works byte per byte (bytewidth = 1)
- precon is the previous unfiltered scanline, recon the result, scanline the current one
- the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead
- recon and scanline MAY be the same memory address! precon must be disjoint.
- */
-
- size_t i;
- switch(filterType)
- {
- case 0:
- for(i = 0; i < length; i++) recon[i] = scanline[i];
- break;
- case 1:
- for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
- for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth];
- break;
- case 2:
- if(precon) for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i];
- else for(i = 0; i < length; i++) recon[i] = scanline[i];
- 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);
- }
- 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;
- }
- break;
- case 4:
- if(precon)
- {
- for(i = 0; i < bytewidth; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(0, precon[i], 0));
- for(i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
- }
- else
- {
- for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
- for(i = bytewidth; i < length; i++) recon[i] = (unsigned char)(scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0));
- }
- break;
- default: return 36; /*error: unexisting filter type given*/
- }
- return 0;
-}
-
-static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
-{
- /*
- For PNG filter method 0
- this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 it's called 7 times)
- out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline
- w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel
- in and out are allowed to be the same memory address!
- */
-
- unsigned y;
- unsigned char* prevline = 0;
-
- size_t bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
- size_t linebytes = (w * bpp + 7) / 8;
-
- for(y = 0; y < h; y++)
- {
- size_t outindex = linebytes * y;
- size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
- unsigned char filterType = in[inindex];
-
- unsigned error = unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes);
- if(error) return error;
-
- prevline = &out[outindex];
- }
-
- return 0;
-}
-
-static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
-{
- /*Note: this function works on image buffers WITHOUT padding bits at end of scanlines with non-multiple-of-8 bit amounts, only between reduced images is padding
- out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation (because that's likely a little bit faster)*/
- unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
- unsigned i;
-
- Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
-
- if(bpp >= 8)
- {
- 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++)
- {
- 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++)
- {
- out[pixeloutstart + b] = in[pixelinstart + b];
- }
- }
- }
- }
- else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
- {
- for(i = 0; i < 7; i++)
- {
- unsigned x, y, b;
- unsigned ilinebits = bpp * passw[i];
- unsigned olinebits = bpp * w;
- size_t obp, ibp; /*bit pointers (for out and in buffer)*/
- for(y = 0; y < passh[i]; y++)
- for(x = 0; x < passw[i]; x++)
- {
- ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
- obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
- for(b = 0; b < bpp; b++)
- {
- unsigned char bit = readBitFromReversedStream(&ibp, in);
- setBitOfReversedStream0(&obp, out, bit); /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/
- }
- }
- }
- }
-}
-
-static void removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h)
-{
- /*
- After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers for the Adam7 code, the color convert code and the output to the user.
- in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits
- also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7
- only useful if (ilinebits - olinebits) is a value in the range 1..7
- */
- unsigned y;
- size_t diff = ilinebits - olinebits;
- size_t obp = 0, ibp = 0; /*bit pointers*/
- for(y = 0; y < h; y++)
- {
- size_t x;
- for(x = 0; x < olinebits; x++)
- {
- unsigned char bit = readBitFromReversedStream(&ibp, in);
- setBitOfReversedStream(&obp, out, bit);
- }
- ibp += diff;
- }
-}
-
-/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from the IDAT chunks*/
-static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, const LodePNG_InfoPng* infoPng) /*return value is error*/
-{
- /*
- This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. Steps:
- *) if no Adam7: 1) unfilter 2) remove padding bits (= possible extra bits per scanline if bpp < 8)
- *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace
- NOTE: the in buffer will be overwritten with intermediate data!
- */
- unsigned bpp = LodePNG_InfoColor_getBpp(&infoPng->color);
- unsigned w = infoPng->width;
- unsigned h = infoPng->height;
- unsigned error = 0;
- if(bpp == 0) return 31; /*error: invalid colortype*/
-
- if(infoPng->interlaceMethod == 0)
- {
- if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
- {
- error = unfilter(in, in, w, h, bpp);
- if(error) return error;
- removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
- }
- else error = unfilter(out, in, w, h, bpp); /*we can immediately filter into the out buffer, no other steps needed*/
- }
- else /*interlaceMethod is 1 (Adam7)*/
- {
- unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
- unsigned i;
-
- Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
-
- for(i = 0; i < 7; i++)
- {
- error = unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp);
- if(error) return error;
- if(bpp < 8) /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, move bytes instead of bits or move not at all*/
- {
- /*remove padding bits in scanlines; after this there still may be padding bits between the different reduced images: each reduced image still starts nicely at a byte*/
- removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7) / 8) * 8, passh[i]);
- }
- }
-
- Adam7_deinterlace(out, in, w, h, bpp);
- }
-
- return error;
-}
-
-/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/
-static void decodeGeneric(LodePNG_Decoder* decoder, unsigned char** out, size_t* outsize, const unsigned char* in, size_t size)
-{
- unsigned char IEND = 0;
- const unsigned char* chunk;
- size_t i;
- ucvector idat; /*the data from idat chunks*/
-
- /*for unknown chunk order*/
- unsigned unknown = 0;
- unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
-
- /*provide some proper output values if error will happen*/
- *out = 0;
- *outsize = 0;
-
- if(size == 0 || in == 0) { decoder->error = 48; return; } /*the given data is empty*/
-
- LodePNG_inspect(decoder, in, size); /*reads header and resets other parameters in decoder->infoPng*/
- if(decoder->error) return;
-
- ucvector_init(&idat);
-
- chunk = &in[33]; /*first byte of the first chunk after the header*/
-
- while(!IEND) /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer*/
- {
- unsigned chunkLength;
- const unsigned char* data; /*the data in the chunk*/
-
- if((size_t)((chunk - in) + 12) > size || chunk < in) { decoder->error = 30; break; } /*error: size of the in buffer too small to contain next chunk*/
- chunkLength = LodePNG_chunk_length(chunk); /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
- if(chunkLength > 2147483647) { decoder->error = 63; break; }
- if((size_t)((chunk - in) + chunkLength + 12) > size || (chunk + chunkLength + 12) < in) { decoder->error = 35; break; } /*error: size of the in buffer too small to contain next chunk*/
- data = LodePNG_chunk_data_const(chunk);
-
- /*IDAT chunk, containing compressed image data*/
- if(LodePNG_chunk_type_equals(chunk, "IDAT"))
- {
- size_t oldsize = idat.size;
- if(!ucvector_resize(&idat, oldsize + chunkLength)) { decoder->error = 9936; break; }
- for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i];
- critical_pos = 3;
- }
- /*IEND chunk*/
- else if(LodePNG_chunk_type_equals(chunk, "IEND"))
- {
- IEND = 1;
- }
- /*palette chunk (PLTE)*/
- else if(LodePNG_chunk_type_equals(chunk, "PLTE"))
- {
- unsigned pos = 0;
- if(decoder->infoPng.color.palette) free(decoder->infoPng.color.palette);
- decoder->infoPng.color.palettesize = chunkLength / 3;
- decoder->infoPng.color.palette = (unsigned char*)malloc(4 * decoder->infoPng.color.palettesize);
- if(!decoder->infoPng.color.palette && decoder->infoPng.color.palettesize) { decoder->error = 9937; break; }
- if(!decoder->infoPng.color.palette) decoder->infoPng.color.palettesize = 0; /*malloc failed...*/
- if(decoder->infoPng.color.palettesize > 256) { decoder->error = 38; break; } /*error: palette too big*/
- for(i = 0; i < decoder->infoPng.color.palettesize; i++)
- {
- decoder->infoPng.color.palette[4 * i + 0] = data[pos++]; /*R*/
- decoder->infoPng.color.palette[4 * i + 1] = data[pos++]; /*G*/
- decoder->infoPng.color.palette[4 * i + 2] = data[pos++]; /*B*/
- decoder->infoPng.color.palette[4 * i + 3] = 255; /*alpha*/
- }
- critical_pos = 2;
- }
- /*palette transparency chunk (tRNS)*/
- else if(LodePNG_chunk_type_equals(chunk, "tRNS"))
- {
- if(decoder->infoPng.color.colorType == 3)
- {
- if(chunkLength > decoder->infoPng.color.palettesize) { decoder->error = 39; break; } /*error: more alpha values given than there are palette entries*/
- for(i = 0; i < chunkLength; i++) decoder->infoPng.color.palette[4 * i + 3] = data[i];
- }
- else if(decoder->infoPng.color.colorType == 0)
- {
- if(chunkLength != 2) { decoder->error = 40; break; } /*error: this chunk must be 2 bytes for greyscale image*/
- decoder->infoPng.color.key_defined = 1;
- decoder->infoPng.color.key_r = decoder->infoPng.color.key_g = decoder->infoPng.color.key_b = 256 * data[0] + data[1];
- }
- else if(decoder->infoPng.color.colorType == 2)
- {
- if(chunkLength != 6) { decoder->error = 41; break; } /*error: this chunk must be 6 bytes for RGB image*/
- decoder->infoPng.color.key_defined = 1;
- decoder->infoPng.color.key_r = 256 * data[0] + data[1];
- decoder->infoPng.color.key_g = 256 * data[2] + data[3];
- decoder->infoPng.color.key_b = 256 * data[4] + data[5];
- }
- else { decoder->error = 42; break; } /*error: tRNS chunk not allowed for other color models*/
- }
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- /*background color chunk (bKGD)*/
- else if(LodePNG_chunk_type_equals(chunk, "bKGD"))
- {
- if(decoder->infoPng.color.colorType == 3)
- {
- if(chunkLength != 1) { decoder->error = 43; break; } /*error: this chunk must be 1 byte for indexed color image*/
- decoder->infoPng.background_defined = 1;
- decoder->infoPng.background_r = decoder->infoPng.background_g = decoder->infoPng.background_g = data[0];
- }
- else if(decoder->infoPng.color.colorType == 0 || decoder->infoPng.color.colorType == 4)
- {
- if(chunkLength != 2) { decoder->error = 44; break; } /*error: this chunk must be 2 bytes for greyscale image*/
- decoder->infoPng.background_defined = 1;
- decoder->infoPng.background_r = decoder->infoPng.background_g = decoder->infoPng.background_b = 256 * data[0] + data[1];
- }
- else if(decoder->infoPng.color.colorType == 2 || decoder->infoPng.color.colorType == 6)
- {
- if(chunkLength != 6) { decoder->error = 45; break; } /*error: this chunk must be 6 bytes for greyscale image*/
- decoder->infoPng.background_defined = 1;
- decoder->infoPng.background_r = 256 * data[0] + data[1];
- decoder->infoPng.background_g = 256 * data[2] + data[3];
- decoder->infoPng.background_b = 256 * data[4] + data[5];
- }
- }
- /*text chunk (tEXt)*/
- else if(LodePNG_chunk_type_equals(chunk, "tEXt"))
- {
- if(decoder->settings.readTextChunks)
- {
- char *key = 0, *str = 0;
-
- while(!decoder->error) /*not really a while loop, only used to break on error*/
- {
- unsigned length, string2_begin;
-
- for(length = 0; length < chunkLength && data[length] != 0; length++) ;
- if(length + 1 >= chunkLength) { decoder->error = 75; break; }
- key = (char*)malloc(length + 1);
- if(!key) { decoder->error = 9938; break; }
- key[length] = 0;
- for(i = 0; i < length; i++) key[i] = data[i];
-
- string2_begin = length + 1;
- if(string2_begin > chunkLength) { decoder->error = 75; break; }
- length = chunkLength - string2_begin;
- str = (char*)malloc(length + 1);
- if(!str) { decoder->error = 9939; break; }
- str[length] = 0;
- for(i = 0; i < length; i++) str[i] = data[string2_begin + i];
-
- decoder->error = LodePNG_Text_add(&decoder->infoPng.text, key, str);
-
- break;
- }
-
- free(key);
- free(str);
- }
- }
- /*compressed text chunk (zTXt)*/
- else if(LodePNG_chunk_type_equals(chunk, "zTXt"))
- {
- if(decoder->settings.readTextChunks)
- {
- unsigned length, string2_begin;
- char *key = 0;
- ucvector decoded;
-
- ucvector_init(&decoded);
-
- while(!decoder->error) /*not really a while loop, only used to break on error*/
- {
- for(length = 0; length < chunkLength && data[length] != 0; length++) ;
- if(length + 2 >= chunkLength) { decoder->error = 75; break; }
- key = (char*)malloc(length + 1);
- if(!key) { decoder->error = 9940; break; }
- key[length] = 0;
- for(i = 0; i < length; i++) key[i] = data[i];
-
- if(data[length + 1] != 0) { decoder->error = 72; break; } /*the 0 byte indicating compression must be 0*/
-
- string2_begin = length + 2;
- if(string2_begin > chunkLength) { decoder->error = 75; break; }
- length = chunkLength - string2_begin;
- decoder->error = LodePNG_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[string2_begin]), length, &decoder->settings.zlibsettings);
- if(decoder->error) break;
- ucvector_push_back(&decoded, 0);
-
- decoder->error = LodePNG_Text_add(&decoder->infoPng.text, key, (char*)decoded.data);
-
- break;
- }
-
- free(key);
- ucvector_cleanup(&decoded);
- if(decoder->error) break;
- }
- }
- /*international text chunk (iTXt)*/
- else if(LodePNG_chunk_type_equals(chunk, "iTXt"))
- {
- if(decoder->settings.readTextChunks)
- {
- unsigned length, begin, compressed;
- char *key = 0, *langtag = 0, *transkey = 0;
- ucvector decoded;
- ucvector_init(&decoded);
-
- while(!decoder->error) /*not really a while loop, only used to break on error*/
- {
- if(chunkLength < 5) { decoder->error = 76; break; }
- for(length = 0; length < chunkLength && data[length] != 0; length++) ;
- if(length + 2 >= chunkLength) { decoder->error = 75; break; }
- key = (char*)malloc(length + 1);
- if(!key) { decoder->error = 9941; break; }
- key[length] = 0;
- for(i = 0; i < length; i++) key[i] = data[i];
-
- compressed = data[length + 1];
- if(data[length + 2] != 0) { decoder->error = 72; break; } /*the 0 byte indicating compression must be 0*/
-
- begin = length + 3;
- length = 0;
- for(i = begin; i < chunkLength && data[i] != 0; i++) length++;
- if(begin + length + 1 >= chunkLength) { decoder->error = 75; break; }
- langtag = (char*)malloc(length + 1);
- if(!langtag) { decoder->error = 9942; break; }
- langtag[length] = 0;
- for(i = 0; i < length; i++) langtag[i] = data[begin + i];
-
- begin += length + 1;
- length = 0;
- for(i = begin; i < chunkLength && data[i] != 0; i++) length++;
- if(begin + length + 1 >= chunkLength) { decoder->error = 75; break; }
- transkey = (char*)malloc(length + 1);
- if(!transkey) { decoder->error = 9943; break; }
- transkey[length] = 0;
- for(i = 0; i < length; i++) transkey[i] = data[begin + i];
-
- begin += length + 1;
- if(begin > chunkLength) { decoder->error = 75; break; }
- length = chunkLength - begin;
-
- if(compressed)
- {
- decoder->error = LodePNG_decompress(&decoded.data, &decoded.size, (unsigned char*)(&data[begin]), length, &decoder->settings.zlibsettings);
- if(decoder->error) break;
- ucvector_push_back(&decoded, 0);
- }
- else
- {
- if(!ucvector_resize(&decoded, length + 1)) { decoder->error = 9944; break; }
- decoded.data[length] = 0;
- for(i = 0; i < length; i++) decoded.data[i] = data[begin + i];
- }
-
- decoder->error = LodePNG_IText_add(&decoder->infoPng.itext, key, langtag, transkey, (char*)decoded.data);
-
- break;
- }
-
- free(key);
- free(langtag);
- free(transkey);
- ucvector_cleanup(&decoded);
- if(decoder->error) break;
- }
- }
- else if(LodePNG_chunk_type_equals(chunk, "tIME"))
- {
- if(chunkLength != 7) { decoder->error = 73; break; }
- decoder->infoPng.time_defined = 1;
- decoder->infoPng.time.year = 256 * data[0] + data[+ 1];
- decoder->infoPng.time.month = data[2];
- decoder->infoPng.time.day = data[3];
- decoder->infoPng.time.hour = data[4];
- decoder->infoPng.time.minute = data[5];
- decoder->infoPng.time.second = data[6];
- }
- else if(LodePNG_chunk_type_equals(chunk, "pHYs"))
- {
- if(chunkLength != 9) { decoder->error = 74; break; }
- decoder->infoPng.phys_defined = 1;
- decoder->infoPng.phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3];
- decoder->infoPng.phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7];
- decoder->infoPng.phys_unit = data[8];
- }
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
- else /*it's not an implemented chunk type, so ignore it: skip over the data*/
- {
- if(LodePNG_chunk_critical(chunk)) { decoder->error = 69; break; } /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
- unknown = 1;
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- if(decoder->settings.rememberUnknownChunks)
- {
- LodePNG_UnknownChunks* unknown = &decoder->infoPng.unknown_chunks;
- decoder->error = LodePNG_append_chunk(&unknown->data[critical_pos - 1], &unknown->datasize[critical_pos - 1], chunk);
- if(decoder->error) break;
- }
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
- }
-
- if(!decoder->settings.ignoreCrc && !unknown) /*check CRC if wanted, only on known chunk types*/
- {
- if(LodePNG_chunk_check_crc(chunk)) { decoder->error = 57; break; }
- }
-
- if(!IEND) chunk = LodePNG_chunk_next_const(chunk);
- }
-
- if(!decoder->error)
- {
- ucvector scanlines;
- ucvector_init(&scanlines);
- if(!ucvector_resize(&scanlines, ((decoder->infoPng.width * (decoder->infoPng.height * LodePNG_InfoColor_getBpp(&decoder->infoPng.color) + 7)) / 8) + decoder->infoPng.height)) decoder->error = 9945; /*maximum final image length is already reserved in the vector's length - this is not really necessary*/
- if(!decoder->error) decoder->error = LodePNG_decompress(&scanlines.data, &scanlines.size, idat.data, idat.size, &decoder->settings.zlibsettings); /*decompress with the Zlib decompressor*/
-
- if(!decoder->error)
- {
- ucvector outv;
- ucvector_init(&outv);
- if(!ucvector_resizev(&outv, (decoder->infoPng.height * decoder->infoPng.width * LodePNG_InfoColor_getBpp(&decoder->infoPng.color) + 7) / 8, 0)) decoder->error = 9946;
- if(!decoder->error) decoder->error = postProcessScanlines(outv.data, scanlines.data, &decoder->infoPng);
- *out = outv.data;
- *outsize = outv.size;
- }
- ucvector_cleanup(&scanlines);
- }
-
- ucvector_cleanup(&idat);
-}
-
-void LodePNG_decode(LodePNG_Decoder* decoder, unsigned char** out, size_t* outsize, const unsigned char* in, size_t insize)
-{
- *out = 0;
- *outsize = 0;
- decodeGeneric(decoder, out, outsize, in, insize);
- if(decoder->error) return;
- if(!decoder->settings.color_convert || LodePNG_InfoColor_equal(&decoder->infoRaw.color, &decoder->infoPng.color))
- {
- /*same color type, no copying or converting of data needed*/
- /*store the infoPng color settings on the infoRaw so that the infoRaw still reflects what colorType
- the raw image has to the end user*/
- if(!decoder->settings.color_convert)
- {
- decoder->error = LodePNG_InfoColor_copy(&decoder->infoRaw.color, &decoder->infoPng.color);
- if(decoder->error) return;
- }
- }
- else
- {
- /*color conversion needed; sort of copy of the data*/
- unsigned char* data = *out;
-
- /*TODO: check if this works according to the statement in the documentation: "The converter can convert from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/
- if(!(decoder->infoRaw.color.colorType == 2 || decoder->infoRaw.color.colorType == 6) && !(decoder->infoRaw.color.bitDepth == 8)) { decoder->error = 56; return; }
-
- *outsize = (decoder->infoPng.width * decoder->infoPng.height * LodePNG_InfoColor_getBpp(&decoder->infoRaw.color) + 7) / 8;
- *out = (unsigned char*)malloc(*outsize);
- if(!(*out))
- {
- decoder->error = 9947;
- *outsize = 0;
- }
- else decoder->error = LodePNG_convert(*out, data, &decoder->infoRaw.color, &decoder->infoPng.color, decoder->infoPng.width, decoder->infoPng.height);
- free(data);
- }
-}
-
-unsigned LodePNG_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
-{
- unsigned error;
- size_t dummy_size;
- LodePNG_Decoder decoder;
- LodePNG_Decoder_init(&decoder);
- LodePNG_decode(&decoder, out, &dummy_size, in, insize);
- error = decoder.error;
- *w = decoder.infoPng.width;
- *h = decoder.infoPng.height;
- LodePNG_Decoder_cleanup(&decoder);
- return error;
-}
-
-#ifdef LODEPNG_COMPILE_DISK
-unsigned LodePNG_decode32f(unsigned char** out, unsigned* w, unsigned* h, const char* filename)
-{
- unsigned char* buffer;
- size_t buffersize;
- unsigned error;
- error = LodePNG_loadFile(&buffer, &buffersize, filename);
- if(!error) error = LodePNG_decode32(out, w, h, buffer, buffersize);
- free(buffer);
- return error;
-}
-#endif /*LODEPNG_COMPILE_DISK*/
-
-void LodePNG_DecodeSettings_init(LodePNG_DecodeSettings* settings)
-{
- settings->color_convert = 1;
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- settings->readTextChunks = 1;
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
- settings->ignoreCrc = 0;
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- settings->rememberUnknownChunks = 0;
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
- LodeZlib_DecompressSettings_init(&settings->zlibsettings);
-}
-
-void LodePNG_Decoder_init(LodePNG_Decoder* decoder)
-{
- LodePNG_DecodeSettings_init(&decoder->settings);
- LodePNG_InfoRaw_init(&decoder->infoRaw);
- LodePNG_InfoPng_init(&decoder->infoPng);
- decoder->error = 1;
-}
-
-void LodePNG_Decoder_cleanup(LodePNG_Decoder* decoder)
-{
- LodePNG_InfoRaw_cleanup(&decoder->infoRaw);
- LodePNG_InfoPng_cleanup(&decoder->infoPng);
-}
-
-void LodePNG_Decoder_copy(LodePNG_Decoder* dest, const LodePNG_Decoder* source)
-{
- LodePNG_Decoder_cleanup(dest);
- *dest = *source;
- LodePNG_InfoRaw_init(&dest->infoRaw);
- LodePNG_InfoPng_init(&dest->infoPng);
- dest->error = LodePNG_InfoRaw_copy(&dest->infoRaw, &source->infoRaw); if(dest->error) return;
- dest->error = LodePNG_InfoPng_copy(&dest->infoPng, &source->infoPng); if(dest->error) return;
-}
-
-#endif /*LODEPNG_COMPILE_DECODER*/
-
-#ifdef LODEPNG_COMPILE_ENCODER
/* ////////////////////////////////////////////////////////////////////////// */
/* / PNG Encoder / */
@@ -3300,7 +2034,7 @@ static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, unsigned bi
unsigned error = 0;
ucvector header;
ucvector_init(&header);
-
+
LodePNG_add32bitInt(&header, w); /*width*/
LodePNG_add32bitInt(&header, h); /*height*/
ucvector_push_back(&header, (unsigned char)bitDepth); /*bit depth*/
@@ -3308,10 +2042,10 @@ static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, unsigned bi
ucvector_push_back(&header, 0); /*compression method*/
ucvector_push_back(&header, 0); /*filter method*/
ucvector_push_back(&header, interlaceMethod); /*interlace method*/
-
+
error = addChunk(out, "IHDR", header.data, header.size);
ucvector_cleanup(&header);
-
+
return error;
}
@@ -3324,7 +2058,7 @@ static unsigned addChunk_PLTE(ucvector* out, const LodePNG_InfoColor* info)
for(i = 0; i < info->palettesize * 4; i++) if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); /*add all channels except alpha channel*/
error = addChunk(out, "PLTE", PLTE.data, PLTE.size);
ucvector_cleanup(&PLTE);
-
+
return error;
}
@@ -3358,10 +2092,10 @@ static unsigned addChunk_tRNS(ucvector* out, const LodePNG_InfoColor* info)
ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256));
}
}
-
+
error = addChunk(out, "tRNS", tRNS.data, tRNS.size);
ucvector_cleanup(&tRNS);
-
+
return error;
}
@@ -3369,13 +2103,13 @@ static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t d
{
ucvector zlibdata;
unsigned error = 0;
-
+
/*compress with the Zlib compressor*/
ucvector_init(&zlibdata);
error = LodePNG_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings);
if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size);
ucvector_cleanup(&zlibdata);
-
+
return error;
}
@@ -3386,149 +2120,6 @@ static unsigned addChunk_IEND(ucvector* out)
return error;
}
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
-
-static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) /*add text chunk*/
-{
- unsigned error = 0;
- size_t i;
- ucvector text;
- ucvector_init(&text);
- for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]);
- ucvector_push_back(&text, 0);
- 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);
-
- return error;
-}
-
-static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, LodeZlib_DeflateSettings* zlibsettings)
-{
- unsigned error = 0;
- ucvector data, compressed;
- size_t i, textsize = strlen(textstring);
-
- ucvector_init(&data);
- ucvector_init(&compressed);
- for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]);
- ucvector_push_back(&data, 0); /* 0 termination char*/
- ucvector_push_back(&data, 0); /*compression method: 0*/
-
- error = LodePNG_compress(&compressed.data, &compressed.size, (unsigned char*)textstring, textsize, zlibsettings);
- if(!error)
- {
- for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]);
- error = addChunk(out, "zTXt", data.data, data.size);
- }
-
- ucvector_cleanup(&compressed);
- ucvector_cleanup(&data);
- return error;
-}
-
-static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, const char* transkey, const char* textstring, LodeZlib_DeflateSettings* zlibsettings)
-{
- unsigned error = 0;
- ucvector data, compressed_data;
- size_t i, textsize = strlen(textstring);
-
- ucvector_init(&data);
-
- for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]);
- 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]);
- ucvector_push_back(&data, 0); /*null termination char*/
- 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)
- {
- ucvector_init(&compressed_data);
- error = LodePNG_compress(&compressed_data.data, &compressed_data.size, (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; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]);
- }
- }
- else /*not compressed*/
- {
- 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);
- ucvector_cleanup(&data);
- return error;
-}
-
-static unsigned addChunk_bKGD(ucvector* out, const LodePNG_InfoPng* info)
-{
- unsigned error = 0;
- ucvector bKGD;
- ucvector_init(&bKGD);
- if(info->color.colorType == 0 || info->color.colorType == 4)
- {
- ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
- ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
- }
- else if(info->color.colorType == 2 || info->color.colorType == 6)
- {
- ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
- ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
- ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256));
- ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256));
- ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256));
- ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256));
- }
- else if(info->color.colorType == 3)
- {
- ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/
- }
-
- error = addChunk(out, "bKGD", bKGD.data, bKGD.size);
- ucvector_cleanup(&bKGD);
-
- return error;
-}
-
-static unsigned addChunk_tIME(ucvector* out, const LodePNG_Time* time)
-{
- unsigned error = 0;
- unsigned char* data = (unsigned char*)malloc(7);
- if(!data) return 9948;
- 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;
- error = addChunk(out, "tIME", data, 7);
- free(data);
- return error;
-}
-
-static unsigned addChunk_pHYs(ucvector* out, const LodePNG_InfoPng* info)
-{
- unsigned error = 0;
- ucvector data;
- ucvector_init(&data);
-
- LodePNG_add32bitInt(&data, info->phys_x);
- LodePNG_add32bitInt(&data, info->phys_y);
- ucvector_push_back(&data, info->phys_unit);
-
- error = addChunk(out, "pHYs", data.data, data.size);
- ucvector_cleanup(&data);
-
- return error;
-}
-
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-
static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, size_t length, size_t bytewidth, unsigned char filterType)
{
size_t i;
@@ -3578,14 +2169,14 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
/*
For PNG filter method 0
out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are the scanlines with 1 extra byte per scanline
-
+
There is a nice heuristic described here: http://www.cs.toronto.edu/~cosmin/pngtech/optipng.html. It says:
* If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. use fixed filtering, with the filter None).
* (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply all five filters and select the filter that produces the smallest sum of absolute values per row.
-
+
Here the above method is used mostly. Note though that it appears to be better to use the adaptive filtering on the plasma 8-bit palette example, but that image isn't the best reference for palette images in general.
*/
-
+
unsigned bpp = LodePNG_InfoColor_getBpp(info);
size_t linebytes = (w * bpp + 7) / 8; /*the width of a scanline in bytes, not including the filter type*/
size_t bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
@@ -3593,13 +2184,13 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
unsigned x, y;
unsigned heuristic;
unsigned error = 0;
-
+
if(bpp == 0) return 31; /*invalid color type*/
-
+
/*choose heuristic as described above*/
if(info->colorType == 3 || info->bitDepth < 8) heuristic = 0;
else heuristic = 1;
-
+
if(heuristic == 0) /*None filtertype for everything*/
{
for(y = 0; y < h; y++)
@@ -3618,13 +2209,13 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
size_t smallest = 0;
unsigned type, bestType = 0;
-
+
for(type = 0; type < 5; type++) ucvector_init(&attempt[type]);
for(type = 0; type < 5; type++)
{
if(!ucvector_resize(&attempt[type], linebytes)) { error = 9949; break; }
}
-
+
if(!error)
{
for(y = 0; y < h; y++)
@@ -3633,11 +2224,11 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
for(type = 0; type < 5; type++)
{
filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
-
+
/*calculate the sum of the result*/
sum[type] = 0;
for(x = 0; x < attempt[type].size; x+=3) sum[type] += attempt[type].data[x]; /*note that not all pixels are checked to speed this up while still having probably the best choice*/
-
+
/*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
if(type == 0 || sum[type] < smallest)
{
@@ -3645,47 +2236,18 @@ static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w,
smallest = sum[type];
}
}
-
+
prevline = &in[y * linebytes];
-
+
/*now fill the out values*/
out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
}
}
-
- for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
- }
- #if 0 /*deflate the scanline with a fixed tree after every filter attempt to see which one deflates best. This is slow, and _does not work as expected_: the heuristic gives smaller result!*/
- else if(heuristic == 2) /*adaptive filtering by using deflate*/
- {
- size_t size[5];
- ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
- size_t smallest;
- unsigned type = 0, bestType = 0;
- unsigned char* dummy;
- LodeZlib_DeflateSettings deflatesettings = LodeZlib_defaultDeflateSettings;
- deflatesettings.btype = 1; /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, to simulate the true case where the tree is the same for the whole image*/
- for(type = 0; type < 5; type++) { ucvector_init(&attempt[type]); ucvector_resize(&attempt[type], linebytes); }
- for(y = 0; y < h; y++) /*try the 5 filter types*/
- {
- for(type = 0; type < 5; type++)
- {
- filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
- size[type] = 0; dummy = 0;
- LodePNG_compress(&dummy, &size[type], attempt[type].data, attempt[type].size, &deflatesettings);
- free(dummy);
- /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
- if(type == 0 || size[type] < smallest) { bestType = type; smallest = size[type]; }
- }
- prevline = &in[y * linebytes];
- out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
- for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
- }
+
for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
}
- #endif
-
+
return error;
}
@@ -3716,7 +2278,7 @@ static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigne
unsigned i;
Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
-
+
if(bpp >= 8)
{
for(i = 0; i < 7; i++)
@@ -3770,7 +2332,7 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const
unsigned w = infoPng->width;
unsigned h = infoPng->height;
unsigned error = 0;
-
+
if(infoPng->interlaceMethod == 0)
{
*outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/
@@ -3798,20 +2360,20 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const
{
unsigned char* adam7 = (unsigned char*)malloc((h * w * bpp + 7) / 8);
if(!adam7 && ((h * w * bpp + 7) / 8)) error = 9952; /*malloc failed*/
-
+
while(!error) /*not a real while loop, used to break out to cleanup to avoid a goto*/
{
unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
unsigned i;
-
+
Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
-
+
*outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/
*out = (unsigned char*)malloc(*outsize);
if(!(*out) && (*outsize)) { error = 9953; break; }
-
+
Adam7_interlace(adam7, in, w, h, bpp);
-
+
for(i = 0; i < 7; i++)
{
if(bpp < 8)
@@ -3824,7 +2386,7 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const
addPaddingBits(&padded.data[padded_passstart[i]], &adam7[passstart[i]], ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]);
error = filter(&(*out)[filter_passstart[i]], &padded.data[padded_passstart[i]], passw[i], passh[i], &infoPng->color);
}
-
+
ucvector_cleanup(&padded);
}
else
@@ -3832,13 +2394,13 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const
error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], passw[i], passh[i], &infoPng->color);
}
}
-
+
break;
}
free(adam7);
}
-
+
return error;
}
@@ -3892,55 +2454,40 @@ static unsigned isFullyOpaque(const unsigned char* image, unsigned w, unsigned h
return 0; /*color type that isn't supported by this function yet, so assume there is transparency to be safe*/
}
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
-static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize)
-{
- unsigned char* inchunk = data;
- while((size_t)(inchunk - data) < datasize)
- {
- unsigned error = LodePNG_append_chunk(&out->data, &out->size, inchunk);
- if(error) return error; /*error: not enough memory*/
- out->allocsize = out->size; /*fix the allocsize again*/
- inchunk = LodePNG_chunk_next(inchunk);
- }
- return 0;
-}
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
-
void LodePNG_encode(LodePNG_Encoder* encoder, unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
{
LodePNG_InfoPng info;
ucvector outv;
unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/
size_t datasize = 0;
-
+
/*provide some proper output values if error will happen*/
*out = 0;
*outsize = 0;
encoder->error = 0;
-
+
info = encoder->infoPng; /*UNSAFE copy to avoid having to cleanup! but we will only change primitive parameters, and not invoke the cleanup function nor touch the palette's buffer so we use it safely*/
info.width = w;
info.height = h;
-
+
if(encoder->settings.autoLeaveOutAlphaChannel && isFullyOpaque(image, w, h, &encoder->infoRaw.color))
{
/*go to a color type without alpha channel*/
if(info.color.colorType == 6) info.color.colorType = 2;
else if(info.color.colorType == 4) info.color.colorType = 0;
}
-
+
if(encoder->settings.zlibsettings.windowSize > 32768) { encoder->error = 60; return; } /*error: windowsize larger than allowed*/
if(encoder->settings.zlibsettings.btype > 2) { encoder->error = 61; return; } /*error: unexisting btype*/
if(encoder->infoPng.interlaceMethod > 1) { encoder->error = 71; return; } /*error: unexisting interlace mode*/
if((encoder->error = checkColorValidity(info.color.colorType, info.color.bitDepth))) return; /*error: unexisting color type given*/
if((encoder->error = checkColorValidity(encoder->infoRaw.color.colorType, encoder->infoRaw.color.bitDepth))) return; /*error: unexisting color type given*/
-
+
if(!LodePNG_InfoColor_equal(&encoder->infoRaw.color, &info.color))
{
unsigned char* converted;
size_t size = (w * h * LodePNG_InfoColor_getBpp(&info.color) + 7) / 8;
-
+
if((info.color.colorType != 6 && info.color.colorType != 2) || (info.color.bitDepth != 8)) { encoder->error = 59; return; } /*for the output image, only these types are supported*/
converted = (unsigned char*)malloc(size);
if(!converted && size) encoder->error = 9955; /*error: malloc failed*/
@@ -3949,21 +2496,14 @@ void LodePNG_encode(LodePNG_Encoder* encoder, unsigned char** out, size_t* outsi
free(converted);
}
else preProcessScanlines(&data, &datasize, image, &info);/*filter(data.data, image, w, h, LodePNG_InfoColor_getBpp(&info.color));*/
-
+
ucvector_init(&outv);
while(!encoder->error) /*not really a while loop, this is only used to break out if an error happens to avoid goto's to do the ucvector cleanup*/
{
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- size_t i;
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
/*write signature and chunks*/
writeSignature(&outv);
/*IHDR*/
addChunk_IHDR(&outv, w, h, info.color.bitDepth, info.color.colorType, info.interlaceMethod);
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- /*unknown chunks between IHDR and PLTE*/
- if(info.unknown_chunks.data[0]) { encoder->error = addUnknownChunks(&outv, info.unknown_chunks.data[0], info.unknown_chunks.datasize[0]); if(encoder->error) break; }
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
/*PLTE*/
if(info.color.colorType == 3)
{
@@ -3978,99 +2518,26 @@ void LodePNG_encode(LodePNG_Encoder* encoder, unsigned char** out, size_t* outsi
/*tRNS*/
if(info.color.colorType == 3 && !isPaletteFullyOpaque(info.color.palette, info.color.palettesize)) addChunk_tRNS(&outv, &info.color);
if((info.color.colorType == 0 || info.color.colorType == 2) && info.color.key_defined) addChunk_tRNS(&outv, &info.color);
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- /*bKGD (must come between PLTE and the IDAt chunks*/
- if(info.background_defined) addChunk_bKGD(&outv, &info);
- /*pHYs (must come before the IDAT chunks)*/
- if(info.phys_defined) addChunk_pHYs(&outv, &info);
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- /*unknown chunks between PLTE and IDAT*/
- if(info.unknown_chunks.data[1]) { encoder->error = addUnknownChunks(&outv, info.unknown_chunks.data[1], info.unknown_chunks.datasize[1]); if(encoder->error) break; }
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
/*IDAT (multiple IDAT chunks must be consecutive)*/
encoder->error = addChunk_IDAT(&outv, data, datasize, &encoder->settings.zlibsettings);
if(encoder->error) break;
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- /*tIME*/
- if(info.time_defined) addChunk_tIME(&outv, &info.time);
- /*tEXt and/or zTXt*/
- for(i = 0; i < info.text.num; i++)
- {
- if(strlen(info.text.keys[i]) > 79) { encoder->error = 66; break; }
- if(strlen(info.text.keys[i]) < 1) { encoder->error = 67; break; }
- if(encoder->settings.text_compression)
- addChunk_zTXt(&outv, info.text.keys[i], info.text.strings[i], &encoder->settings.zlibsettings);
- else
- addChunk_tEXt(&outv, info.text.keys[i], info.text.strings[i]);
- }
- /*LodePNG version id in text chunk*/
- if(encoder->settings.add_id)
- {
- unsigned alread_added_id_text = 0;
- for(i = 0; i < info.text.num; i++)
- if(!strcmp(info.text.keys[i], "LodePNG")) { alread_added_id_text = 1; break; }
- if(alread_added_id_text == 0)
- addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/
- }
- /*iTXt*/
- for(i = 0; i < info.itext.num; i++)
- {
- if(strlen(info.itext.keys[i]) > 79) { encoder->error = 66; break; }
- if(strlen(info.itext.keys[i]) < 1) { encoder->error = 67; break; }
- addChunk_iTXt(&outv, encoder->settings.text_compression,
- info.itext.keys[i], info.itext.langtags[i], info.itext.transkeys[i], info.itext.strings[i],
- &encoder->settings.zlibsettings);
- }
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
-#ifdef LODEPNG_COMPILE_UNKNOWN_CHUNKS
- /*unknown chunks between IDAT and IEND*/
- if(info.unknown_chunks.data[2]) { encoder->error = addUnknownChunks(&outv, info.unknown_chunks.data[2], info.unknown_chunks.datasize[2]); if(encoder->error) break; }
-#endif /*LODEPNG_COMPILE_UNKNOWN_CHUNKS*/
/*IEND*/
addChunk_IEND(&outv);
-
+
break; /*this isn't really a while loop; no error happened so break out now!*/
}
-
+
free(data);
/*instead of cleaning the vector up, give it to the output*/
*out = outv.data;
*outsize = outv.size;
}
-unsigned LodePNG_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
-{
- unsigned error;
- LodePNG_Encoder encoder;
- LodePNG_Encoder_init(&encoder);
- LodePNG_encode(&encoder, out, outsize, image, w, h);
- error = encoder.error;
- LodePNG_Encoder_cleanup(&encoder);
- return error;
-}
-
-#ifdef LODEPNG_COMPILE_DISK
-unsigned LodePNG_encode32f(const char* filename, const unsigned char* image, unsigned w, unsigned h)
-{
- unsigned char* buffer;
- size_t buffersize;
- unsigned error = LodePNG_encode32(&buffer, &buffersize, image, w, h);
- LodePNG_saveFile(buffer, buffersize, filename);
- free(buffer);
- return error;
-}
-#endif /*LODEPNG_COMPILE_DISK*/
-
void LodePNG_EncodeSettings_init(LodePNG_EncodeSettings* settings)
{
LodeZlib_DeflateSettings_init(&settings->zlibsettings);
settings->autoLeaveOutAlphaChannel = 1;
settings->force_palette = 0;
-#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
- settings->add_id = 1;
- settings->text_compression = 0;
-#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
}
void LodePNG_Encoder_init(LodePNG_Encoder* encoder)
@@ -4097,46 +2564,10 @@ void LodePNG_Encoder_copy(LodePNG_Encoder* dest, const LodePNG_Encoder* source)
dest->error = LodePNG_InfoRaw_copy(&dest->infoRaw, &source->infoRaw); if(dest->error) return;
}
-#endif /*LODEPNG_COMPILE_ENCODER*/
-
-#endif /*LODEPNG_COMPILE_PNG*/
-
/* ////////////////////////////////////////////////////////////////////////// */
/* / File IO / */
/* ////////////////////////////////////////////////////////////////////////// */
-#ifdef LODEPNG_COMPILE_DISK
-
-unsigned LodePNG_loadFile(unsigned char** out, size_t* outsize, const char* filename) /*designed for loading files from hard disk in a dynamically allocated buffer*/
-{
- FILE* file;
- long size;
-
- /*provide some proper output values if error will happen*/
- *out = 0;
- *outsize = 0;
-
- file = portable_fopen(filename, "rb");
- if(!file) return 78;
-
- /*get filesize:*/
- fseek(file , 0 , SEEK_END);
- size = ftell(file);
- rewind(file);
-
- /*read contents of the file into the vector*/
- if (size>0)
- {
- *outsize = 0;
- *out = (unsigned char*)malloc((size_t)size);
- if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file);
- }
-
- fclose(file);
- if(!(*out) && size) return 80; /*the above malloc failed*/
- return 0;
-}
-
/*write given buffer to the file, overwriting the file, it doesn't append to it.*/
unsigned LodePNG_saveFile(const unsigned char* buffer, size_t buffersize, const char* filename)
{
@@ -4148,5 +2579,3 @@ unsigned LodePNG_saveFile(const unsigned char* buffer, size_t buffersize, const
return 0;
}
-#endif /*LODEPNG_COMPILE_DISK*/
-