Compress-Zopfli
view release on metacpan or search on metacpan
zopflib/src/zopflipng/lodepng/lodepng_util.cpp view on Meta::CPAN
size_t start = pos, back = start - dist; //backwards
for(size_t i = 0; i < length; i++)
{
out.push_back(out[back++]);
pos++;
if(back >= start) back = start - dist;
}
numlen++;
zlibinfo->back().lz77_dcode.back() = codeD; //output distance code
zlibinfo->back().lz77_lbits.back() = numextrabits; //output length extra bits
zlibinfo->back().lz77_dbits.back() = numextrabitsD; //output dist extra bits
zlibinfo->back().lz77_lvalue.back() = length; //output length
zlibinfo->back().lz77_dvalue.back() = dist; //output dist
}
}
zlibinfo->back().numlit = numlit; //output number of literal symbols
zlibinfo->back().numlen = numlen; //output number of length symbols
}
void inflateNoCompression(std::vector<unsigned char>& out,
const unsigned char* in, size_t& bp, size_t& pos, size_t inlength)
{
while((bp & 0x7) != 0) bp++; //go to first boundary of byte
size_t p = bp / 8;
if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory
unsigned long LEN = in[p] + 256u * in[p + 1], NLEN = in[p + 2] + 256u * in[p + 3]; p += 4;
if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN
if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer
for(unsigned long n = 0; n < LEN; n++)
{
out.push_back(in[p++]); //read LEN bytes of literal data
pos++;
}
bp = p * 8;
}
int decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in) //returns error value
{
if(in.size() < 2) { return 53; } //error, size of zlib data too small
//error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way
if((in[0] * 256 + in[1]) % 31 != 0) { return 24; }
unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1;
//error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec
if(CM != 8 || CINFO > 7) { return 25; }
//error: the PNG spec says about the zlib stream: "The additional flags shall not specify a preset dictionary."
if(FDICT != 0) { return 26; }
inflate(out, in, 2);
return error; //note: adler32 checksum was skipped and ignored
}
};
struct ExtractPNG //PNG decoding and information extraction
{
std::vector<ZlibBlockInfo>* zlibinfo;
ExtractPNG(std::vector<ZlibBlockInfo>* info) : zlibinfo(info) {};
int error;
void decode(const unsigned char* in, size_t size)
{
error = 0;
if(size == 0 || in == 0) { error = 48; return; } //the given data is empty
readPngHeader(&in[0], size); if(error) return;
size_t pos = 33; //first byte of the first chunk after the header
std::vector<unsigned char> idat; //the data from idat chunks
bool IEND = false;
//loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.
//IDAT data is put at the start of the in buffer
while(!IEND)
{
//error: size of the in buffer too small to contain next chunk
if(pos + 8 >= size) { error = 30; return; }
size_t chunkLength = read32bitInt(&in[pos]); pos += 4;
if(chunkLength > 2147483647) { error = 63; return; }
//error: size of the in buffer too small to contain next chunk
if(pos + chunkLength >= size) { error = 35; return; }
//IDAT chunk, containing compressed image data
if(in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T')
{
idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]);
pos += (4 + chunkLength);
}
else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D')
{
pos += 4;
IEND = true;
}
else //it's not an implemented chunk type, so ignore it: skip over the data
{
pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk
}
pos += 4; //step over CRC (which is ignored)
}
std::vector<unsigned char> out; //now the out buffer will be filled
ExtractZlib zlib(zlibinfo); //decompress with the Zlib decompressor
error = zlib.decompress(out, idat);
if(error) return; //stop if the zlib decompressor returned an error
}
//read the information from the header and store it in the Info
void readPngHeader(const unsigned char* in, size_t inlength)
{
if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header
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) { error = 28; return; } //no PNG signature
//error: it doesn't start with a IHDR chunk!
if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; }
}
unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits)
{
unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1;
bitp++;
return result;
}
unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits)
{
unsigned long result = 0;
for(size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i);
return result;
}
void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit)
{
bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); bitp++;
}
unsigned long read32bitInt(const unsigned char* buffer)
{
return (unsigned int)((buffer[0] << 24u) | (buffer[1] << 16u) | (buffer[2] << 8u) | buffer[3]);
}
};
void extractZlibInfo(std::vector<ZlibBlockInfo>& zlibinfo, const std::vector<unsigned char>& in)
{
ExtractPNG decoder(&zlibinfo);
decoder.decode(&in[0], in.size());
if(decoder.error) std::cout << "extract error: " << decoder.error << std::endl;
}
} // namespace lodepng
( run in 0.954 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )