Compress-Zopfli
view release on metacpan or search on metacpan
zopflib/src/zopflipng/lodepng/lodepng.cpp view on Meta::CPAN
static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index)
{
return tree->lengths[index];
}
#endif /*LODEPNG_COMPILE_ENCODER*/
/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/
static unsigned generateFixedLitLenTree(HuffmanTree* tree)
{
unsigned i, error = 0;
unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
if(!bitlen) return 83; /*alloc fail*/
/*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/
for(i = 0; i <= 143; ++i) bitlen[i] = 8;
for(i = 144; i <= 255; ++i) bitlen[i] = 9;
for(i = 256; i <= 279; ++i) bitlen[i] = 7;
for(i = 280; i <= 287; ++i) bitlen[i] = 8;
error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15);
lodepng_free(bitlen);
return error;
}
/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/
static unsigned generateFixedDistanceTree(HuffmanTree* tree)
{
unsigned i, error = 0;
unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
if(!bitlen) return 83; /*alloc fail*/
/*there are 32 distance codes, but 30-31 are unused*/
for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5;
error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15);
lodepng_free(bitlen);
return error;
}
#ifdef LODEPNG_COMPILE_DECODER
/*
returns the code, or (unsigned)(-1) if error happened
inbitlength is the length of the complete buffer, in bits (so its byte length times 8)
*/
static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp,
const HuffmanTree* codetree, size_t inbitlength)
{
unsigned treepos = 0, ct;
for(;;)
{
if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/
/*
decode the symbol from the tree. The "readBitFromStream" code is inlined in
the expression below because this is the biggest bottleneck while decoding
*/
ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)];
++(*bp);
if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/
else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/
if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/
}
}
#endif /*LODEPNG_COMPILE_DECODER*/
#ifdef LODEPNG_COMPILE_DECODER
/* ////////////////////////////////////////////////////////////////////////// */
/* / Inflator (Decompressor) / */
/* ////////////////////////////////////////////////////////////////////////// */
/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/
static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d)
{
/*TODO: check for out of memory errors*/
generateFixedLitLenTree(tree_ll);
generateFixedDistanceTree(tree_d);
}
/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/
static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
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*/
unsigned error = 0;
unsigned n, HLIT, HDIST, HCLEN, i;
size_t inbitlength = inlength * 8;
/*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/
unsigned* bitlen_ll = 0; /*lit,len code lengths*/
unsigned* bitlen_d = 0; /*dist code lengths*/
/*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/
unsigned* bitlen_cl = 0;
HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
if((*bp) + 14 > (inlength << 3)) return 49; /*error: the bit pointer is or will go past the memory*/
/*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
HLIT = readBitsFromStream(bp, in, 5) + 257;
/*number of distance codes. Unlike the spec, the value 1 is added to it here already*/
HDIST = readBitsFromStream(bp, in, 5) + 1;
/*number of code length codes. Unlike the spec, the value 4 is added to it here already*/
HCLEN = readBitsFromStream(bp, in, 4) + 4;
if((*bp) + HCLEN * 3 > (inlength << 3)) return 50; /*error: the bit pointer is or will go past the memory*/
HuffmanTree_init(&tree_cl);
while(!error)
{
/*read the code length codes out of 3 * (amount of code length codes) bits*/
bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned));
if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/);
for(i = 0; i != NUM_CODE_LENGTH_CODES; ++i)
{
if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3);
else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/
zopflib/src/zopflipng/lodepng/lodepng.cpp view on Meta::CPAN
info->background_r = 256u * data[0] + data[1];
info->background_g = 256u * data[2] + data[3];
info->background_b = 256u * data[4] + data[5];
}
return 0; /* OK */
}
/*text chunk (tEXt)*/
static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
{
unsigned error = 0;
char *key = 0, *str = 0;
unsigned i;
while(!error) /*not really a while loop, only used to break on error*/
{
unsigned length, string2_begin;
length = 0;
while(length < chunkLength && data[length] != 0) ++length;
/*even though it's not allowed by the standard, no error is thrown if
there's no null termination char, if the text is empty*/
if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
key = (char*)lodepng_malloc(length + 1);
if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
key[length] = 0;
for(i = 0; i != length; ++i) key[i] = (char)data[i];
string2_begin = length + 1; /*skip keyword null terminator*/
length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin;
str = (char*)lodepng_malloc(length + 1);
if(!str) CERROR_BREAK(error, 83); /*alloc fail*/
str[length] = 0;
for(i = 0; i != length; ++i) str[i] = (char)data[string2_begin + i];
error = lodepng_add_text(info, key, str);
break;
}
lodepng_free(key);
lodepng_free(str);
return error;
}
/*compressed text chunk (zTXt)*/
static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
const unsigned char* data, size_t chunkLength)
{
unsigned error = 0;
unsigned i;
unsigned length, string2_begin;
char *key = 0;
ucvector decoded;
ucvector_init(&decoded);
while(!error) /*not really a while loop, only used to break on error*/
{
for(length = 0; length < chunkLength && data[length] != 0; ++length) ;
if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/
if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
key = (char*)lodepng_malloc(length + 1);
if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
key[length] = 0;
for(i = 0; i != length; ++i) key[i] = (char)data[i];
if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/
string2_begin = length + 2;
if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/
length = chunkLength - string2_begin;
/*will fail if zlib error, e.g. if length is too small*/
error = zlib_decompress(&decoded.data, &decoded.size,
(unsigned char*)(&data[string2_begin]),
length, zlibsettings);
if(error) break;
ucvector_push_back(&decoded, 0);
error = lodepng_add_text(info, key, (char*)decoded.data);
break;
}
lodepng_free(key);
ucvector_cleanup(&decoded);
return error;
}
/*international text chunk (iTXt)*/
static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings,
const unsigned char* data, size_t chunkLength)
{
unsigned error = 0;
unsigned i;
unsigned length, begin, compressed;
char *key = 0, *langtag = 0, *transkey = 0;
ucvector decoded;
ucvector_init(&decoded);
while(!error) /*not really a while loop, only used to break on error*/
{
/*Quick check if the chunk length isn't too small. Even without check
it'd still fail with other error checks below if it's too short. This just gives a different error code.*/
if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/
/*read the key*/
for(length = 0; length < chunkLength && data[length] != 0; ++length) ;
if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/
if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/
key = (char*)lodepng_malloc(length + 1);
if(!key) CERROR_BREAK(error, 83); /*alloc fail*/
key[length] = 0;
for(i = 0; i != length; ++i) key[i] = (char)data[i];
/*read the compression method*/
compressed = data[length + 1];
if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/
/*even though it's not allowed by the standard, no error is thrown if
there's no null termination char, if the text is empty for the next 3 texts*/
/*read the langtag*/
begin = length + 3;
length = 0;
for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length;
langtag = (char*)lodepng_malloc(length + 1);
if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/
langtag[length] = 0;
for(i = 0; i != length; ++i) langtag[i] = (char)data[begin + i];
/*read the transkey*/
begin += length + 1;
length = 0;
for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length;
transkey = (char*)lodepng_malloc(length + 1);
if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/
transkey[length] = 0;
for(i = 0; i != length; ++i) transkey[i] = (char)data[begin + i];
/*read the actual text*/
begin += length + 1;
length = chunkLength < begin ? 0 : chunkLength - begin;
if(compressed)
{
/*will fail if zlib error, e.g. if length is too small*/
error = zlib_decompress(&decoded.data, &decoded.size,
(unsigned char*)(&data[begin]),
length, zlibsettings);
if(error) break;
if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size;
ucvector_push_back(&decoded, 0);
}
else
{
if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/);
decoded.data[length] = 0;
for(i = 0; i != length; ++i) decoded.data[i] = data[begin + i];
}
error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data);
break;
}
lodepng_free(key);
lodepng_free(langtag);
lodepng_free(transkey);
ucvector_cleanup(&decoded);
return error;
}
static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
{
if(chunkLength != 7) return 73; /*invalid tIME chunk size*/
info->time_defined = 1;
info->time.year = 256u * data[0] + data[1];
info->time.month = data[2];
info->time.day = data[3];
info->time.hour = data[4];
info->time.minute = data[5];
info->time.second = data[6];
return 0; /* OK */
}
static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength)
{
if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/
info->phys_defined = 1;
info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3];
info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7];
info->phys_unit = data[8];
return 0; /* OK */
}
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/
static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
LodePNGState* state,
const unsigned char* in, size_t insize)
{
unsigned char IEND = 0;
const unsigned char* chunk;
size_t i;
ucvector idat; /*the data from idat chunks*/
ucvector scanlines;
size_t predict;
size_t numpixels;
size_t outsize;
/*for unknown chunk order*/
unsigned unknown = 0;
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
/*provide some proper output values if error will happen*/
*out = 0;
state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/
if(state->error) return;
numpixels = *w * *h;
( run in 1.521 second using v1.01-cache-2.11-cpan-995e09ba956 )