zopfli-bin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitmodules +3 -0
  4. data/.testguardrc +1 -0
  5. data/Gemfile +17 -0
  6. data/Gemfile.lock +111 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.rdoc +19 -0
  9. data/Rakefile +39 -0
  10. data/VERSION +1 -0
  11. data/ext/Makefile +8 -0
  12. data/ext/extconf.rb +4 -0
  13. data/lib/zopfli-bin.rb +5 -0
  14. data/lib/zopfli/bin.rb +34 -0
  15. data/test/helper.rb +19 -0
  16. data/test/test_zopfli-bin.rb +33 -0
  17. data/vendor/zopfli/CONTRIBUTORS +7 -0
  18. data/vendor/zopfli/COPYING +201 -0
  19. data/vendor/zopfli/Makefile +37 -0
  20. data/vendor/zopfli/README +32 -0
  21. data/vendor/zopfli/README.zopflipng +35 -0
  22. data/vendor/zopfli/src/zopfli/blocksplitter.c +342 -0
  23. data/vendor/zopfli/src/zopfli/blocksplitter.h +77 -0
  24. data/vendor/zopfli/src/zopfli/cache.c +119 -0
  25. data/vendor/zopfli/src/zopfli/cache.h +66 -0
  26. data/vendor/zopfli/src/zopfli/deflate.c +866 -0
  27. data/vendor/zopfli/src/zopfli/deflate.h +86 -0
  28. data/vendor/zopfli/src/zopfli/gzip_container.c +117 -0
  29. data/vendor/zopfli/src/zopfli/gzip_container.h +50 -0
  30. data/vendor/zopfli/src/zopfli/hash.c +135 -0
  31. data/vendor/zopfli/src/zopfli/hash.h +70 -0
  32. data/vendor/zopfli/src/zopfli/katajainen.c +251 -0
  33. data/vendor/zopfli/src/zopfli/katajainen.h +42 -0
  34. data/vendor/zopfli/src/zopfli/lz77.c +482 -0
  35. data/vendor/zopfli/src/zopfli/lz77.h +129 -0
  36. data/vendor/zopfli/src/zopfli/squeeze.c +546 -0
  37. data/vendor/zopfli/src/zopfli/squeeze.h +60 -0
  38. data/vendor/zopfli/src/zopfli/tree.c +101 -0
  39. data/vendor/zopfli/src/zopfli/tree.h +51 -0
  40. data/vendor/zopfli/src/zopfli/util.c +213 -0
  41. data/vendor/zopfli/src/zopfli/util.h +175 -0
  42. data/vendor/zopfli/src/zopfli/zlib_container.c +79 -0
  43. data/vendor/zopfli/src/zopfli/zlib_container.h +50 -0
  44. data/vendor/zopfli/src/zopfli/zopfli.h +97 -0
  45. data/vendor/zopfli/src/zopfli/zopfli_bin.c +203 -0
  46. data/vendor/zopfli/src/zopfli/zopfli_lib.c +42 -0
  47. data/vendor/zopfli/src/zopflipng/lodepng/lodepng.cpp +6260 -0
  48. data/vendor/zopfli/src/zopflipng/lodepng/lodepng.h +1716 -0
  49. data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.cpp +656 -0
  50. data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.h +151 -0
  51. data/vendor/zopfli/src/zopflipng/zopflipng_bin.cc +407 -0
  52. data/vendor/zopfli/src/zopflipng/zopflipng_lib.cc +425 -0
  53. data/vendor/zopfli/src/zopflipng/zopflipng_lib.h +79 -0
  54. data/zopfli-bin.gemspec +119 -0
  55. metadata +225 -0
@@ -0,0 +1,37 @@
1
+ CC = gcc
2
+ CXX = g++
3
+
4
+ CFLAGS = -W -Wall -Wextra -ansi -pedantic -lm -O2
5
+ CXXFLAGS = -W -Wall -Wextra -ansi -pedantic -O2
6
+
7
+ ZOPFLILIB_SRC = src/zopfli/blocksplitter.c src/zopfli/cache.c\
8
+ src/zopfli/deflate.c src/zopfli/gzip_container.c\
9
+ src/zopfli/hash.c src/zopfli/katajainen.c\
10
+ src/zopfli/lz77.c src/zopfli/squeeze.c\
11
+ src/zopfli/tree.c src/zopfli/util.c\
12
+ src/zopfli/zlib_container.c src/zopfli/zopfli_lib.c
13
+ ZOPFLILIB_OBJ := $(patsubst src/zopfli/%.c,%.o,$(ZOPFLILIB_SRC))
14
+ ZOPFLIBIN_SRC := src/zopfli/zopfli_bin.c
15
+ LODEPNG_SRC := src/zopflipng/lodepng/lodepng.cpp src/zopflipng/lodepng/lodepng_util.cpp
16
+ ZOPFLIPNGLIB_SRC := src/zopflipng/zopflipng_lib.cc
17
+ ZOPFLIPNGBIN_SRC := src/zopflipng/zopflipng_bin.cc
18
+
19
+ .PHONY: zopfli zopflipng
20
+
21
+ # Zopfli binary
22
+ zopfli:
23
+ $(CC) $(ZOPFLILIB_SRC) $(ZOPFLIBIN_SRC) $(CFLAGS) -o zopfli
24
+
25
+ # Zopfli shared library
26
+ libzopfli:
27
+ $(CC) $(ZOPFLILIB_SRC) $(CFLAGS) -fPIC -c
28
+ $(CC) $(ZOPFLILIB_OBJ) $(CFLAGS) -shared -Wl,-soname,libzopfli.so.1 -o libzopfli.so.1.0.1
29
+
30
+ # ZopfliPNG binary
31
+ zopflipng:
32
+ $(CC) $(ZOPFLILIB_SRC) $(CFLAGS) -c
33
+ $(CXX) $(ZOPFLILIB_OBJ) $(LODEPNG_SRC) $(ZOPFLIPNGLIB_SRC) $(ZOPFLIPNGBIN_SRC) $(CFLAGS) -o zopflipng
34
+
35
+ # Remove all libraries and binaries
36
+ clean:
37
+ rm -f zopflipng zopfli $(ZOPFLILIB_OBJ) libzopfli*
@@ -0,0 +1,32 @@
1
+ Zopfli Compression Algorithm is a compression library programmed in C to perform
2
+ very good, but slow, deflate or zlib compression.
3
+
4
+ The basic function to compress data is ZopfliCompress in zopfli.h. Use the
5
+ ZopfliOptions object to set parameters that affect the speed and compression.
6
+ Use the ZopfliInitOptions function to place the default values in the
7
+ ZopfliOptions first.
8
+
9
+ ZopfliCompress supports deflate, gzip and zlib output format with a parameter.
10
+ To support only one individual format, you can instead use ZopfliDeflate in
11
+ deflate.h, ZopfliZlibCompress in zlib_container.h or ZopfliGzipCompress in
12
+ gzip_container.h.
13
+
14
+ ZopfliDeflate creates a valid deflate stream in memory, see:
15
+ http://www.ietf.org/rfc/rfc1951.txt
16
+ ZopfliZlibCompress creates a valid zlib stream in memory, see:
17
+ http://www.ietf.org/rfc/rfc1950.txt
18
+ ZopfliGzipCompress creates a valid gzip stream in memory, see:
19
+ http://www.ietf.org/rfc/rfc1952.txt
20
+
21
+ This library can only compress, not decompress. Existing zlib or deflate
22
+ libraries can decompress the data.
23
+
24
+ zopfli_bin.c is separate from the library and contains an example program to
25
+ create very well compressed gzip files. Currently the makefile builds this
26
+ program with the library statically linked in.
27
+
28
+ To build the binary, use "make". To build the library as a shared Linux library,
29
+ use "make libzopfli". The source code of Zopfli is under src/zopfli.
30
+
31
+ Zopfli Compression Algorithm was created by Lode Vandevenne and Jyrki
32
+ Alakuijala, based on an algorithm by Jyrki Alakuijala.
@@ -0,0 +1,35 @@
1
+ ZopfliPNG is a command line program to optimize the Portable Network Graphics
2
+ (PNG) images. This version has the following features:
3
+ - uses Zopfli compression for the Deflate compression,
4
+ - compares several strategies for choosing scanline filter codes,
5
+ - chooses a suitable color type to losslessly encode the image,
6
+ - removes all chunks that are unimportant for the typical web use (metadata,
7
+ text, etc...),
8
+ - optionally alters the hidden colors of fully transparent pixels for more
9
+ compression, and,
10
+ - optionally converts 16-bit color channels to 8-bit.
11
+
12
+ This is an alpha-release for testing while improvements, particularly to add
13
+ palette selection, are still being made. Feedback and bug reports are welcome.
14
+
15
+ To build ZopfliPNG, use "make zopflipng", or compile all the sources except
16
+ zopfli_bin.c.
17
+
18
+ The main compression algorithm in ZopfliPNG is ported from WebP lossless, but
19
+ naturally cannot give as much compression gain for PNGs as it does for a more
20
+ modern compression codec like WebP
21
+ https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification.
22
+
23
+ Compared to libpng -- an often used PNG encoder implementation -- ZopfliPNG uses
24
+ 2-3 orders of magnitude more CPU time for compression. Initial testing using a
25
+ corpus of 1000 PNGs with translucency, randomly selected from the internet,
26
+ gives a compression improvement of 12% compared to convert -q 95, but only 0.5%
27
+ compared to pngout (from better of /f0 and /f5 runs).
28
+
29
+ By releasing this software we hope to make images on the web load faster without
30
+ a new image format, but the opportunities for optimization within PNG are
31
+ limited. When targeting Android, Chrome, Opera, and Yandex browsers, or by using
32
+ suitable plugins for other browsers, it is good to note that WebP lossless
33
+ images are still 26 % smaller than images recompressed with ZopfliPNG.
34
+
35
+ 2013-05-07, Lode Vandevenne and Jyrki Alakuijala
@@ -0,0 +1,342 @@
1
+ /*
2
+ Copyright 2011 Google Inc. All Rights Reserved.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+
16
+ Author: lode.vandevenne@gmail.com (Lode Vandevenne)
17
+ Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
18
+ */
19
+
20
+ #include "blocksplitter.h"
21
+
22
+ #include <assert.h>
23
+ #include <stdio.h>
24
+ #include <stdlib.h>
25
+
26
+ #include "deflate.h"
27
+ #include "lz77.h"
28
+ #include "squeeze.h"
29
+ #include "tree.h"
30
+ #include "util.h"
31
+
32
+ /*
33
+ The "f" for the FindMinimum function below.
34
+ i: the current parameter of f(i)
35
+ context: for your implementation
36
+ */
37
+ typedef double FindMinimumFun(size_t i, void* context);
38
+
39
+ /*
40
+ Finds minimum of function f(i) where is is of type size_t, f(i) is of type
41
+ double, i is in range start-end (excluding end).
42
+ */
43
+ static size_t FindMinimum(FindMinimumFun f, void* context,
44
+ size_t start, size_t end) {
45
+ if (end - start < 1024) {
46
+ double best = ZOPFLI_LARGE_FLOAT;
47
+ size_t result = start;
48
+ size_t i;
49
+ for (i = start; i < end; i++) {
50
+ double v = f(i, context);
51
+ if (v < best) {
52
+ best = v;
53
+ result = i;
54
+ }
55
+ }
56
+ return result;
57
+ } else {
58
+ /* Try to find minimum faster by recursively checking multiple points. */
59
+ #define NUM 9 /* Good value: 9. */
60
+ size_t i;
61
+ size_t p[NUM];
62
+ double vp[NUM];
63
+ size_t besti;
64
+ double best;
65
+ double lastbest = ZOPFLI_LARGE_FLOAT;
66
+ size_t pos = start;
67
+
68
+ for (;;) {
69
+ if (end - start <= NUM) break;
70
+
71
+ for (i = 0; i < NUM; i++) {
72
+ p[i] = start + (i + 1) * ((end - start) / (NUM + 1));
73
+ vp[i] = f(p[i], context);
74
+ }
75
+ besti = 0;
76
+ best = vp[0];
77
+ for (i = 1; i < NUM; i++) {
78
+ if (vp[i] < best) {
79
+ best = vp[i];
80
+ besti = i;
81
+ }
82
+ }
83
+ if (best > lastbest) break;
84
+
85
+ start = besti == 0 ? start : p[besti - 1];
86
+ end = besti == NUM - 1 ? end : p[besti + 1];
87
+
88
+ pos = p[besti];
89
+ lastbest = best;
90
+ }
91
+ return pos;
92
+ #undef NUM
93
+ }
94
+ }
95
+
96
+ /*
97
+ Returns estimated cost of a block in bits. It includes the size to encode the
98
+ tree and the size to encode all literal, length and distance symbols and their
99
+ extra bits.
100
+
101
+ litlens: lz77 lit/lengths
102
+ dists: ll77 distances
103
+ lstart: start of block
104
+ lend: end of block (not inclusive)
105
+ */
106
+ static double EstimateCost(const unsigned short* litlens,
107
+ const unsigned short* dists,
108
+ size_t lstart, size_t lend) {
109
+ return ZopfliCalculateBlockSize(litlens, dists, lstart, lend, 2);
110
+ }
111
+
112
+ typedef struct SplitCostContext {
113
+ const unsigned short* litlens;
114
+ const unsigned short* dists;
115
+ size_t llsize;
116
+ size_t start;
117
+ size_t end;
118
+ } SplitCostContext;
119
+
120
+
121
+ /*
122
+ Gets the cost which is the sum of the cost of the left and the right section
123
+ of the data.
124
+ type: FindMinimumFun
125
+ */
126
+ static double SplitCost(size_t i, void* context) {
127
+ SplitCostContext* c = (SplitCostContext*)context;
128
+ return EstimateCost(c->litlens, c->dists, c->start, i) +
129
+ EstimateCost(c->litlens, c->dists, i, c->end);
130
+ }
131
+
132
+ static void AddSorted(size_t value, size_t** out, size_t* outsize) {
133
+ size_t i;
134
+ ZOPFLI_APPEND_DATA(value, out, outsize);
135
+ for (i = 0; i + 1 < *outsize; i++) {
136
+ if ((*out)[i] > value) {
137
+ size_t j;
138
+ for (j = *outsize - 1; j > i; j--) {
139
+ (*out)[j] = (*out)[j - 1];
140
+ }
141
+ (*out)[i] = value;
142
+ break;
143
+ }
144
+ }
145
+ }
146
+
147
+ /*
148
+ Prints the block split points as decimal and hex values in the terminal.
149
+ */
150
+ static void PrintBlockSplitPoints(const unsigned short* litlens,
151
+ const unsigned short* dists,
152
+ size_t llsize, const size_t* lz77splitpoints,
153
+ size_t nlz77points) {
154
+ size_t* splitpoints = 0;
155
+ size_t npoints = 0;
156
+ size_t i;
157
+ /* The input is given as lz77 indices, but we want to see the uncompressed
158
+ index values. */
159
+ size_t pos = 0;
160
+ if (nlz77points > 0) {
161
+ for (i = 0; i < llsize; i++) {
162
+ size_t length = dists[i] == 0 ? 1 : litlens[i];
163
+ if (lz77splitpoints[npoints] == i) {
164
+ ZOPFLI_APPEND_DATA(pos, &splitpoints, &npoints);
165
+ if (npoints == nlz77points) break;
166
+ }
167
+ pos += length;
168
+ }
169
+ }
170
+ assert(npoints == nlz77points);
171
+
172
+ fprintf(stderr, "block split points: ");
173
+ for (i = 0; i < npoints; i++) {
174
+ fprintf(stderr, "%d ", (int)splitpoints[i]);
175
+ }
176
+ fprintf(stderr, "(hex:");
177
+ for (i = 0; i < npoints; i++) {
178
+ fprintf(stderr, " %x", (int)splitpoints[i]);
179
+ }
180
+ fprintf(stderr, ")\n");
181
+
182
+ free(splitpoints);
183
+ }
184
+
185
+ /*
186
+ Finds next block to try to split, the largest of the available ones.
187
+ The largest is chosen to make sure that if only a limited amount of blocks is
188
+ requested, their sizes are spread evenly.
189
+ llsize: the size of the LL77 data, which is the size of the done array here.
190
+ done: array indicating which blocks starting at that position are no longer
191
+ splittable (splitting them increases rather than decreases cost).
192
+ splitpoints: the splitpoints found so far.
193
+ npoints: the amount of splitpoints found so far.
194
+ lstart: output variable, giving start of block.
195
+ lend: output variable, giving end of block.
196
+ returns 1 if a block was found, 0 if no block found (all are done).
197
+ */
198
+ static int FindLargestSplittableBlock(
199
+ size_t llsize, const unsigned char* done,
200
+ const size_t* splitpoints, size_t npoints,
201
+ size_t* lstart, size_t* lend) {
202
+ size_t longest = 0;
203
+ int found = 0;
204
+ size_t i;
205
+ for (i = 0; i <= npoints; i++) {
206
+ size_t start = i == 0 ? 0 : splitpoints[i - 1];
207
+ size_t end = i == npoints ? llsize - 1 : splitpoints[i];
208
+ if (!done[start] && end - start > longest) {
209
+ *lstart = start;
210
+ *lend = end;
211
+ found = 1;
212
+ longest = end - start;
213
+ }
214
+ }
215
+ return found;
216
+ }
217
+
218
+ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
219
+ const unsigned short* litlens,
220
+ const unsigned short* dists,
221
+ size_t llsize, size_t maxblocks,
222
+ size_t** splitpoints, size_t* npoints) {
223
+ size_t lstart, lend;
224
+ size_t i;
225
+ size_t llpos = 0;
226
+ size_t numblocks = 1;
227
+ unsigned char* done;
228
+ double splitcost, origcost;
229
+
230
+ if (llsize < 10) return; /* This code fails on tiny files. */
231
+
232
+ done = (unsigned char*)malloc(llsize);
233
+ if (!done) exit(-1); /* Allocation failed. */
234
+ for (i = 0; i < llsize; i++) done[i] = 0;
235
+
236
+ lstart = 0;
237
+ lend = llsize;
238
+ for (;;) {
239
+ SplitCostContext c;
240
+
241
+ if (maxblocks > 0 && numblocks >= maxblocks) {
242
+ break;
243
+ }
244
+
245
+ c.litlens = litlens;
246
+ c.dists = dists;
247
+ c.llsize = llsize;
248
+ c.start = lstart;
249
+ c.end = lend;
250
+ assert(lstart < lend);
251
+ llpos = FindMinimum(SplitCost, &c, lstart + 1, lend);
252
+
253
+ assert(llpos > lstart);
254
+ assert(llpos < lend);
255
+
256
+ splitcost = EstimateCost(litlens, dists, lstart, llpos) +
257
+ EstimateCost(litlens, dists, llpos, lend);
258
+ origcost = EstimateCost(litlens, dists, lstart, lend);
259
+
260
+ if (splitcost > origcost || llpos == lstart + 1 || llpos == lend) {
261
+ done[lstart] = 1;
262
+ } else {
263
+ AddSorted(llpos, splitpoints, npoints);
264
+ numblocks++;
265
+ }
266
+
267
+ if (!FindLargestSplittableBlock(
268
+ llsize, done, *splitpoints, *npoints, &lstart, &lend)) {
269
+ break; /* No further split will probably reduce compression. */
270
+ }
271
+
272
+ if (lend - lstart < 10) {
273
+ break;
274
+ }
275
+ }
276
+
277
+ if (options->verbose) {
278
+ PrintBlockSplitPoints(litlens, dists, llsize, *splitpoints, *npoints);
279
+ }
280
+
281
+ free(done);
282
+ }
283
+
284
+ void ZopfliBlockSplit(const ZopfliOptions* options,
285
+ const unsigned char* in, size_t instart, size_t inend,
286
+ size_t maxblocks, size_t** splitpoints, size_t* npoints) {
287
+ size_t pos = 0;
288
+ size_t i;
289
+ ZopfliBlockState s;
290
+ size_t* lz77splitpoints = 0;
291
+ size_t nlz77points = 0;
292
+ ZopfliLZ77Store store;
293
+
294
+ ZopfliInitLZ77Store(&store);
295
+
296
+ s.options = options;
297
+ s.blockstart = instart;
298
+ s.blockend = inend;
299
+ #ifdef ZOPFLI_LONGEST_MATCH_CACHE
300
+ s.lmc = 0;
301
+ #endif
302
+
303
+ *npoints = 0;
304
+ *splitpoints = 0;
305
+
306
+ /* Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal
307
+ results in better blocks. */
308
+ ZopfliLZ77Greedy(&s, in, instart, inend, &store);
309
+
310
+ ZopfliBlockSplitLZ77(options,
311
+ store.litlens, store.dists, store.size, maxblocks,
312
+ &lz77splitpoints, &nlz77points);
313
+
314
+ /* Convert LZ77 positions to positions in the uncompressed input. */
315
+ pos = instart;
316
+ if (nlz77points > 0) {
317
+ for (i = 0; i < store.size; i++) {
318
+ size_t length = store.dists[i] == 0 ? 1 : store.litlens[i];
319
+ if (lz77splitpoints[*npoints] == i) {
320
+ ZOPFLI_APPEND_DATA(pos, splitpoints, npoints);
321
+ if (*npoints == nlz77points) break;
322
+ }
323
+ pos += length;
324
+ }
325
+ }
326
+ assert(*npoints == nlz77points);
327
+
328
+ free(lz77splitpoints);
329
+ ZopfliCleanLZ77Store(&store);
330
+ }
331
+
332
+ void ZopfliBlockSplitSimple(const unsigned char* in,
333
+ size_t instart, size_t inend,
334
+ size_t blocksize,
335
+ size_t** splitpoints, size_t* npoints) {
336
+ size_t i = instart;
337
+ while (i < inend) {
338
+ ZOPFLI_APPEND_DATA(i, splitpoints, npoints);
339
+ i += blocksize;
340
+ }
341
+ (void)in;
342
+ }