Compress-Zopfli
view release on metacpan or search on metacpan
zopflib/src/zopfli/deflate.c view on Meta::CPAN
/*
Deflate a part, to allow ZopfliDeflate() to use multiple master blocks if
needed.
It is possible to call this function multiple times in a row, shifting
instart and inend to next bytes of the data. If instart is larger than 0, then
previous bytes are used as the initial dictionary for LZ77.
This function will usually output multiple deflate blocks. If final is 1, then
the final bit will be set on the last block.
*/
void ZopfliDeflatePart(const ZopfliOptions* options, int btype, int final,
const unsigned char* in, size_t instart, size_t inend,
unsigned char* bp, unsigned char** out,
size_t* outsize) {
size_t i;
/* byte coordinates rather than lz77 index */
size_t* splitpoints_uncompressed = 0;
size_t npoints = 0;
size_t* splitpoints = 0;
double totalcost = 0;
ZopfliLZ77Store lz77;
/* If btype=2 is specified, it tries all block types. If a lesser btype is
given, then however it forces that one. Neither of the lesser types needs
block splitting as they have no dynamic huffman trees. */
if (btype == 0) {
AddNonCompressedBlock(options, final, in, instart, inend, bp, out, outsize);
return;
} else if (btype == 1) {
ZopfliLZ77Store store;
ZopfliBlockState s;
ZopfliInitLZ77Store(in, &store);
ZopfliInitBlockState(options, instart, inend, 1, &s);
ZopfliLZ77OptimalFixed(&s, in, instart, inend, &store);
AddLZ77Block(options, btype, final, &store, 0, store.size, 0,
bp, out, outsize);
ZopfliCleanBlockState(&s);
ZopfliCleanLZ77Store(&store);
return;
}
if (options->blocksplitting) {
ZopfliBlockSplit(options, in, instart, inend,
options->blocksplittingmax,
&splitpoints_uncompressed, &npoints);
splitpoints = (size_t*)malloc(sizeof(*splitpoints) * npoints);
}
ZopfliInitLZ77Store(in, &lz77);
for (i = 0; i <= npoints; i++) {
size_t start = i == 0 ? instart : splitpoints_uncompressed[i - 1];
size_t end = i == npoints ? inend : splitpoints_uncompressed[i];
ZopfliBlockState s;
ZopfliLZ77Store store;
ZopfliInitLZ77Store(in, &store);
ZopfliInitBlockState(options, start, end, 1, &s);
ZopfliLZ77Optimal(&s, in, start, end, options->numiterations, &store);
totalcost += ZopfliCalculateBlockSizeAutoType(&store, 0, store.size);
ZopfliAppendLZ77Store(&store, &lz77);
if (i < npoints) splitpoints[i] = lz77.size;
ZopfliCleanBlockState(&s);
ZopfliCleanLZ77Store(&store);
}
/* Second block splitting attempt */
if (options->blocksplitting && npoints > 1) {
size_t* splitpoints2 = 0;
size_t npoints2 = 0;
double totalcost2 = 0;
ZopfliBlockSplitLZ77(options, &lz77,
options->blocksplittingmax, &splitpoints2, &npoints2);
for (i = 0; i <= npoints2; i++) {
size_t start = i == 0 ? 0 : splitpoints2[i - 1];
size_t end = i == npoints2 ? lz77.size : splitpoints2[i];
totalcost2 += ZopfliCalculateBlockSizeAutoType(&lz77, start, end);
}
if (totalcost2 < totalcost) {
free(splitpoints);
splitpoints = splitpoints2;
npoints = npoints2;
} else {
free(splitpoints2);
}
}
for (i = 0; i <= npoints; i++) {
size_t start = i == 0 ? 0 : splitpoints[i - 1];
size_t end = i == npoints ? lz77.size : splitpoints[i];
AddLZ77BlockAutoType(options, i == npoints && final,
&lz77, start, end, 0,
bp, out, outsize);
}
ZopfliCleanLZ77Store(&lz77);
free(splitpoints);
free(splitpoints_uncompressed);
}
void ZopfliDeflate(const ZopfliOptions* options, int btype, int final,
const unsigned char* in, size_t insize,
unsigned char* bp, unsigned char** out, size_t* outsize) {
size_t offset = *outsize;
#if ZOPFLI_MASTER_BLOCK_SIZE == 0
ZopfliDeflatePart(options, btype, final, in, 0, insize, bp, out, outsize);
#else
size_t i = 0;
do {
int masterfinal = (i + ZOPFLI_MASTER_BLOCK_SIZE >= insize);
int final2 = final && masterfinal;
size_t size = masterfinal ? insize - i : ZOPFLI_MASTER_BLOCK_SIZE;
ZopfliDeflatePart(options, btype, final2,
in, i, i + size, bp, out, outsize);
( run in 0.806 second using v1.01-cache-2.11-cpan-71847e10f99 )