Skip to content

Commit

Permalink
Update zopfli to 66ac641.
Browse files Browse the repository at this point in the history
  • Loading branch information
unknownbrackets committed Sep 10, 2017
2 parents 64d1d58 + 66ac641 commit 4589b42
Show file tree
Hide file tree
Showing 30 changed files with 2,417 additions and 2,052 deletions.
1 change: 1 addition & 0 deletions zopfli/CONTRIBUTORS
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Mark Adler
Jyrki Alakuijala
Frédéric Kayser
Jeffrey Lim
Daniel Reed
Huzaifa Sidhpurwala
Péter Szabó
Expand Down
2 changes: 1 addition & 1 deletion zopfli/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CC = gcc
CXX = g++

CFLAGS = -W -Wall -Wextra -ansi -pedantic -lm -O2
CFLAGS = -W -Wall -Wextra -ansi -pedantic -lm -O2 -Wno-unused-function
CXXFLAGS = -W -Wall -Wextra -ansi -pedantic -O2

ZOPFLILIB_SRC = src/zopfli/blocksplitter.c src/zopfli/cache.c\
Expand Down
11 changes: 9 additions & 2 deletions zopfli/README
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@ zopfli_bin.c is separate from the library and contains an example program to
create very well compressed gzip files. Currently the makefile builds this
program with the library statically linked in.

To build the binary, use "make". To build the library as a shared Linux library,
use "make libzopfli". The source code of Zopfli is under src/zopfli.
The source code of Zopfli is under src/zopfli. Build instructions:

To build zopfli, compile all .c source files under src/zopfli to a single binary
with C, and link to the standard C math library, e.g.:
gcc src/zopfli/*.c -O2 -W -Wall -Wextra -Wno-unused-function -ansi -pedantic -lm -o zopfli

A makefile is provided as well, but only for linux. Use "make" to build the
binary, "make libzopfli" to build it as a shared library. For other platforms,
please use the build instructions above instead.

Zopfli Compression Algorithm was created by Lode Vandevenne and Jyrki
Alakuijala, based on an algorithm by Jyrki Alakuijala.
23 changes: 21 additions & 2 deletions zopfli/README.zopflipng
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,27 @@ ZopfliPNG is a command line program to optimize the Portable Network Graphics
This is an alpha-release for testing while improvements, particularly to add
palette selection, are still being made. Feedback and bug reports are welcome.

To build ZopfliPNG, use "make zopflipng", or compile all the sources except
zopfli_bin.c.
Important:

This PNG optimizer removes ancillary chunks (pieces of metadata) from the
PNG image that normally do not affect rendering. However in special
circumstances you may wish to keep some. For example for a design using
custom gamma correction, keeping it may be desired. Visually check in the
target renderer after using ZopfliPNG. Use --keepchunks to keep chunks, e.g.
--keepchunks=gAMA,pHYs to keep gamma and DPI information. This will increase
file size. The following page contains a list of ancillary PNG chunks:
http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html

Build instructions:

To build ZopfliPNG, compile all .c, .cc and .cpp files from src/zopfli,
src/zopflipng and src/zopflipng/lodepng, except src/zopfli/zopfli_bin.c, to a
single binary with C++, e.g.:
g++ src/zopfli/{blocksplitter,cache,deflate,gzip_container,hash,katajainen,lz77,squeeze,tree,util,zlib_container,zopfli_lib}.c src/zopflipng/*.cc src/zopflipng/lodepng/*.cpp -O2 -W -Wall -Wextra -Wno-unused-function -ansi -pedantic -o zopflipng

A makefile is provided as well, but only for linux: use "make zopflipng" with
the Zopfli makefile. For other platforms, please use the build instructions
above instead.

The main compression algorithm in ZopfliPNG is ported from WebP lossless, but
naturally cannot give as much compression gain for PNGs as it does for a more
Expand Down
78 changes: 34 additions & 44 deletions zopfli/src/zopfli/blocksplitter.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ Author: [email protected] (Jyrki Alakuijala)
#include <stdlib.h>

#include "deflate.h"
#include "lz77.h"
#include "squeeze.h"
#include "tree.h"
#include "util.h"
Expand All @@ -39,9 +38,10 @@ typedef double FindMinimumFun(size_t i, void* context);
/*
Finds minimum of function f(i) where is is of type size_t, f(i) is of type
double, i is in range start-end (excluding end).
Outputs the minimum value in *smallest and returns the index of this value.
*/
static size_t FindMinimum(FindMinimumFun f, void* context,
size_t start, size_t end) {
size_t start, size_t end, double* smallest) {
if (end - start < 1024) {
double best = ZOPFLI_LARGE_FLOAT;
size_t result = start;
Expand All @@ -53,6 +53,7 @@ static size_t FindMinimum(FindMinimumFun f, void* context,
result = i;
}
}
*smallest = best;
return result;
} else {
/* Try to find minimum faster by recursively checking multiple points. */
Expand Down Expand Up @@ -88,6 +89,7 @@ static size_t FindMinimum(FindMinimumFun f, void* context,
pos = p[besti];
lastbest = best;
}
*smallest = lastbest;
return pos;
#undef NUM
}
Expand All @@ -103,16 +105,13 @@ dists: ll77 distances
lstart: start of block
lend: end of block (not inclusive)
*/
static double EstimateCost(const unsigned short* litlens,
const unsigned short* dists,
static double EstimateCost(const ZopfliLZ77Store* lz77,
size_t lstart, size_t lend) {
return ZopfliCalculateBlockSize(litlens, dists, lstart, lend, 2);
return ZopfliCalculateBlockSizeAutoType(lz77, lstart, lend);
}

typedef struct SplitCostContext {
const unsigned short* litlens;
const unsigned short* dists;
size_t llsize;
const ZopfliLZ77Store* lz77;
size_t start;
size_t end;
} SplitCostContext;
Expand All @@ -125,8 +124,7 @@ type: FindMinimumFun
*/
static double SplitCost(size_t i, void* context) {
SplitCostContext* c = (SplitCostContext*)context;
return EstimateCost(c->litlens, c->dists, c->start, i) +
EstimateCost(c->litlens, c->dists, i, c->end);
return EstimateCost(c->lz77, c->start, i) + EstimateCost(c->lz77, i, c->end);
}

static void AddSorted(size_t value, size_t** out, size_t* outsize) {
Expand All @@ -147,9 +145,8 @@ static void AddSorted(size_t value, size_t** out, size_t* outsize) {
/*
Prints the block split points as decimal and hex values in the terminal.
*/
static void PrintBlockSplitPoints(const unsigned short* litlens,
const unsigned short* dists,
size_t llsize, const size_t* lz77splitpoints,
static void PrintBlockSplitPoints(const ZopfliLZ77Store* lz77,
const size_t* lz77splitpoints,
size_t nlz77points) {
size_t* splitpoints = 0;
size_t npoints = 0;
Expand All @@ -158,8 +155,8 @@ static void PrintBlockSplitPoints(const unsigned short* litlens,
index values. */
size_t pos = 0;
if (nlz77points > 0) {
for (i = 0; i < llsize; i++) {
size_t length = dists[i] == 0 ? 1 : litlens[i];
for (i = 0; i < lz77->size; i++) {
size_t length = lz77->dists[i] == 0 ? 1 : lz77->litlens[i];
if (lz77splitpoints[npoints] == i) {
ZOPFLI_APPEND_DATA(pos, &splitpoints, &npoints);
if (npoints == nlz77points) break;
Expand All @@ -186,7 +183,7 @@ static void PrintBlockSplitPoints(const unsigned short* litlens,
Finds next block to try to split, the largest of the available ones.
The largest is chosen to make sure that if only a limited amount of blocks is
requested, their sizes are spread evenly.
llsize: the size of the LL77 data, which is the size of the done array here.
lz77size: the size of the LL77 data, which is the size of the done array here.
done: array indicating which blocks starting at that position are no longer
splittable (splitting them increases rather than decreases cost).
splitpoints: the splitpoints found so far.
Expand All @@ -196,15 +193,15 @@ lend: output variable, giving end of block.
returns 1 if a block was found, 0 if no block found (all are done).
*/
static int FindLargestSplittableBlock(
size_t llsize, const unsigned char* done,
size_t lz77size, const unsigned char* done,
const size_t* splitpoints, size_t npoints,
size_t* lstart, size_t* lend) {
size_t longest = 0;
int found = 0;
size_t i;
for (i = 0; i <= npoints; i++) {
size_t start = i == 0 ? 0 : splitpoints[i - 1];
size_t end = i == npoints ? llsize - 1 : splitpoints[i];
size_t end = i == npoints ? lz77size - 1 : splitpoints[i];
if (!done[start] && end - start > longest) {
*lstart = start;
*lend = end;
Expand All @@ -216,9 +213,7 @@ static int FindLargestSplittableBlock(
}

void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
const unsigned short* litlens,
const unsigned short* dists,
size_t llsize, size_t maxblocks,
const ZopfliLZ77Store* lz77, size_t maxblocks,
size_t** splitpoints, size_t* npoints) {
size_t lstart, lend;
size_t i;
Expand All @@ -227,35 +222,31 @@ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
unsigned char* done;
double splitcost, origcost;

if (llsize < 10) return; /* This code fails on tiny files. */
if (lz77->size < 10) return; /* This code fails on tiny files. */

done = (unsigned char*)malloc(llsize);
done = (unsigned char*)malloc(lz77->size);
if (!done) exit(-1); /* Allocation failed. */
for (i = 0; i < llsize; i++) done[i] = 0;
for (i = 0; i < lz77->size; i++) done[i] = 0;

lstart = 0;
lend = llsize;
lend = lz77->size;
for (;;) {
SplitCostContext c;

if (maxblocks > 0 && numblocks >= maxblocks) {
break;
}

c.litlens = litlens;
c.dists = dists;
c.llsize = llsize;
c.lz77 = lz77;
c.start = lstart;
c.end = lend;
assert(lstart < lend);
llpos = FindMinimum(SplitCost, &c, lstart + 1, lend);
llpos = FindMinimum(SplitCost, &c, lstart + 1, lend, &splitcost);

assert(llpos > lstart);
assert(llpos < lend);

splitcost = EstimateCost(litlens, dists, lstart, llpos) +
EstimateCost(litlens, dists, llpos, lend);
origcost = EstimateCost(litlens, dists, lstart, lend);
origcost = EstimateCost(lz77, lstart, lend);

if (splitcost > origcost || llpos == lstart + 1 || llpos == lend) {
done[lstart] = 1;
Expand All @@ -265,7 +256,7 @@ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
}

if (!FindLargestSplittableBlock(
llsize, done, *splitpoints, *npoints, &lstart, &lend)) {
lz77->size, done, *splitpoints, *npoints, &lstart, &lend)) {
break; /* No further split will probably reduce compression. */
}

Expand All @@ -275,7 +266,7 @@ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
}

if (options->verbose) {
PrintBlockSplitPoints(litlens, dists, llsize, *splitpoints, *npoints);
PrintBlockSplitPoints(lz77, *splitpoints, *npoints);
}

free(done);
Expand All @@ -290,25 +281,22 @@ void ZopfliBlockSplit(const ZopfliOptions* options,
size_t* lz77splitpoints = 0;
size_t nlz77points = 0;
ZopfliLZ77Store store;
ZopfliHash hash;
ZopfliHash* h = &hash;

ZopfliInitLZ77Store(&store);

s.options = options;
s.blockstart = instart;
s.blockend = inend;
#ifdef ZOPFLI_LONGEST_MATCH_CACHE
s.lmc = 0;
#endif
ZopfliInitLZ77Store(in, &store);
ZopfliInitBlockState(options, instart, inend, 0, &s);
ZopfliAllocHash(ZOPFLI_WINDOW_SIZE, h);

*npoints = 0;
*splitpoints = 0;

/* Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal
results in better blocks. */
ZopfliLZ77Greedy(&s, in, instart, inend, &store);
ZopfliLZ77Greedy(&s, in, instart, inend, &store, h);

ZopfliBlockSplitLZ77(options,
store.litlens, store.dists, store.size, maxblocks,
&store, maxblocks,
&lz77splitpoints, &nlz77points);

/* Convert LZ77 positions to positions in the uncompressed input. */
Expand All @@ -326,7 +314,9 @@ void ZopfliBlockSplit(const ZopfliOptions* options,
assert(*npoints == nlz77points);

free(lz77splitpoints);
ZopfliCleanBlockState(&s);
ZopfliCleanLZ77Store(&store);
ZopfliCleanHash(h);
}

void ZopfliBlockSplitSimple(const unsigned char* in,
Expand Down
8 changes: 2 additions & 6 deletions zopfli/src/zopfli/blocksplitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,17 @@ ones that enhance it.

#include <stdlib.h>

#include "lz77.h"
#include "zopfli.h"


/*
Does blocksplitting on LZ77 data.
The output splitpoints are indices in the LZ77 data.
litlens: lz77 lit/lengths
dists: lz77 distances
llsize: size of litlens and dists
maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
*/
void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
const unsigned short* litlens,
const unsigned short* dists,
size_t llsize, size_t maxblocks,
const ZopfliLZ77Store* lz77, size_t maxblocks,
size_t** splitpoints, size_t* npoints);

/*
Expand Down
4 changes: 3 additions & 1 deletion zopfli/src/zopfli/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ void ZopfliInitCache(size_t blocksize, ZopfliLongestMatchCache* lmc) {
/* Rather large amount of memory. */
lmc->sublen = (unsigned char*)malloc(ZOPFLI_CACHE_LENGTH * 3 * blocksize);
if(lmc->sublen == NULL) {
fprintf(stderr,"Error: Out of memory. Tried allocating %lu bytes of memory.\n",(unsigned long)(ZOPFLI_CACHE_LENGTH * 3 * blocksize));
fprintf(stderr,
"Error: Out of memory. Tried allocating %lu bytes of memory.\n",
ZOPFLI_CACHE_LENGTH * 3 * blocksize);
exit (EXIT_FAILURE);
}

Expand Down
Loading

0 comments on commit 4589b42

Please sign in to comment.