zopfli 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +35 -0
  3. data/.github/workflows/publish.yml +34 -0
  4. data/.gitmodules +1 -1
  5. data/Gemfile +4 -0
  6. data/README.md +6 -1
  7. data/Rakefile +14 -10
  8. data/ext/extconf.rb +36 -32
  9. data/ext/zopfli.c +52 -20
  10. data/lib/zopfli/version.rb +1 -1
  11. data/smoke.sh +9 -0
  12. data/test/test_helper.rb +7 -0
  13. data/test/zopfli_test.rb +63 -0
  14. data/vendor/zopfli/src/zopfli/blocksplitter.c +41 -53
  15. data/vendor/zopfli/src/zopfli/blocksplitter.h +2 -6
  16. data/vendor/zopfli/src/zopfli/cache.c +6 -0
  17. data/vendor/zopfli/src/zopfli/deflate.c +613 -381
  18. data/vendor/zopfli/src/zopfli/deflate.h +8 -2
  19. data/vendor/zopfli/src/zopfli/gzip_container.c +54 -47
  20. data/vendor/zopfli/src/zopfli/hash.c +18 -10
  21. data/vendor/zopfli/src/zopfli/hash.h +10 -7
  22. data/vendor/zopfli/src/zopfli/katajainen.c +73 -62
  23. data/vendor/zopfli/src/zopfli/katajainen.h +1 -1
  24. data/vendor/zopfli/src/zopfli/lz77.c +190 -42
  25. data/vendor/zopfli/src/zopfli/lz77.h +39 -23
  26. data/vendor/zopfli/src/zopfli/squeeze.c +75 -61
  27. data/vendor/zopfli/src/zopfli/squeeze.h +1 -0
  28. data/vendor/zopfli/src/zopfli/symbols.h +239 -0
  29. data/vendor/zopfli/src/zopfli/util.c +0 -178
  30. data/vendor/zopfli/src/zopfli/util.h +6 -23
  31. data/vendor/zopfli/src/zopfli/zlib_container.c +1 -1
  32. data/vendor/zopfli/src/zopfli/zopfli.h +1 -4
  33. data/vendor/zopfli/src/zopfli/zopfli_bin.c +31 -15
  34. data/zopfli.gemspec +12 -32
  35. metadata +20 -68
  36. data/test/fixtures/alice29.txt +0 -3609
  37. data/test/test_zopfli_deflate.rb +0 -47
  38. data/vendor/zopfli/CONTRIBUTORS +0 -7
  39. data/vendor/zopfli/README +0 -32
  40. data/vendor/zopfli/README.zopflipng +0 -35
  41. data/vendor/zopfli/makefile +0 -37
  42. data/vendor/zopfli/src/zopflipng/lodepng/lodepng.cpp +0 -6253
  43. data/vendor/zopfli/src/zopflipng/lodepng/lodepng.h +0 -1705
  44. data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.cpp +0 -656
  45. data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.h +0 -151
  46. data/vendor/zopfli/src/zopflipng/zopflipng_bin.cc +0 -407
  47. data/vendor/zopfli/src/zopflipng/zopflipng_lib.cc +0 -376
  48. data/vendor/zopfli/src/zopflipng/zopflipng_lib.h +0 -79
@@ -1,376 +0,0 @@
1
- // Copyright 2013 Google Inc. All Rights Reserved.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
- //
15
- // Author: lode.vandevenne@gmail.com (Lode Vandevenne)
16
- // Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
17
-
18
- // See zopflipng_lib.h
19
-
20
- #include "zopflipng_lib.h"
21
-
22
- #include <stdio.h>
23
- #include <vector>
24
-
25
- #include "lodepng/lodepng.h"
26
- #include "lodepng/lodepng_util.h"
27
- #include "../zopfli/deflate.h"
28
-
29
- ZopfliPNGOptions::ZopfliPNGOptions()
30
- : lossy_transparent(false)
31
- , lossy_8bit(false)
32
- , auto_filter_strategy(true)
33
- , use_zopfli(true)
34
- , num_iterations(15)
35
- , num_iterations_large(5)
36
- , block_split_strategy(1) {
37
- }
38
-
39
- // Deflate compressor passed as fuction pointer to LodePNG to have it use Zopfli
40
- // as its compression backend.
41
- unsigned CustomPNGDeflate(unsigned char** out, size_t* outsize,
42
- const unsigned char* in, size_t insize,
43
- const LodePNGCompressSettings* settings) {
44
- const ZopfliPNGOptions* png_options =
45
- static_cast<const ZopfliPNGOptions*>(settings->custom_context);
46
- unsigned char bp = 0;
47
- ZopfliOptions options;
48
- ZopfliInitOptions(&options);
49
-
50
- options.numiterations = insize < 200000
51
- ? png_options->num_iterations : png_options->num_iterations_large;
52
-
53
- if (png_options->block_split_strategy == 3) {
54
- // Try both block splitting first and last.
55
- unsigned char* out2 = 0;
56
- size_t outsize2 = 0;
57
- options.blocksplittinglast = 0;
58
- ZopfliDeflate(&options, 2 /* Dynamic */, 1, in, insize, &bp, out, outsize);
59
- bp = 0;
60
- options.blocksplittinglast = 1;
61
- ZopfliDeflate(&options, 2 /* Dynamic */, 1,
62
- in, insize, &bp, &out2, &outsize2);
63
-
64
- if (outsize2 < *outsize) {
65
- free(*out);
66
- *out = out2;
67
- *outsize = outsize2;
68
- printf("Block splitting last was better\n");
69
- } else {
70
- free(out2);
71
- }
72
- } else {
73
- if (png_options->block_split_strategy == 0) options.blocksplitting = 0;
74
- options.blocksplittinglast = png_options->block_split_strategy == 2;
75
- ZopfliDeflate(&options, 2 /* Dynamic */, 1, in, insize, &bp, out, outsize);
76
- }
77
-
78
- return 0; // OK
79
- }
80
-
81
- // Remove RGB information from pixels with alpha=0
82
- void LossyOptimizeTransparent(unsigned char* image, unsigned w, unsigned h) {
83
- // First check if we want to preserve potential color-key background color,
84
- // or instead use the last encountered RGB value all the time to save bytes.
85
- bool key = true;
86
- for (size_t i = 0; i < w * h; i++) {
87
- if (image[i * 4 + 3] > 0 && image[i * 4 + 3] < 255) {
88
- key = false;
89
- break;
90
- }
91
- }
92
-
93
- // Choose the color key if color keying is used.
94
- int r = 0, g = 0, b = 0;
95
- if (key) {
96
- for (size_t i = 0; i < w * h; i++) {
97
- if (image[i * 4 + 3] == 0) {
98
- // Use first encountered transparent pixel as the color key
99
- r = image[i * 4 + 0];
100
- g = image[i * 4 + 1];
101
- b = image[i * 4 + 2];
102
- }
103
- }
104
- }
105
-
106
- for (size_t i = 0; i < w * h; i++) {
107
- // if alpha is 0
108
- if (image[i * 4 + 3] == 0) {
109
- image[i * 4 + 0] = r;
110
- image[i * 4 + 1] = g;
111
- image[i * 4 + 2] = b;
112
- } else {
113
- if (!key) {
114
- // Use the last encountered RGB value if no color keying is used.
115
- r = image[i * 4 + 0];
116
- g = image[i * 4 + 1];
117
- b = image[i * 4 + 2];
118
- }
119
- }
120
- }
121
- }
122
-
123
- // Tries to optimize given a single PNG filter strategy.
124
- // Returns 0 if ok, other value for error
125
- unsigned TryOptimize(
126
- const std::vector<unsigned char>& image, unsigned w, unsigned h,
127
- const lodepng::State& inputstate, bool bit16,
128
- const std::vector<unsigned char>& origfile,
129
- ZopfliPNGFilterStrategy filterstrategy,
130
- bool use_zopfli, int windowsize, const ZopfliPNGOptions* png_options,
131
- std::vector<unsigned char>* out) {
132
- unsigned error = 0;
133
-
134
- lodepng::State state;
135
- state.encoder.zlibsettings.windowsize = windowsize;
136
- if (use_zopfli && png_options->use_zopfli) {
137
- ZopfliPNGOptions custom_context = *png_options;
138
- state.encoder.zlibsettings.custom_deflate = CustomPNGDeflate;
139
- state.encoder.zlibsettings.custom_context = &custom_context;
140
- }
141
-
142
- if (inputstate.info_png.color.colortype == LCT_PALETTE) {
143
- // Make it preserve the original palette order
144
- lodepng_color_mode_copy(&state.info_raw, &inputstate.info_png.color);
145
- state.info_raw.colortype = LCT_RGBA;
146
- state.info_raw.bitdepth = 8;
147
- }
148
- if (bit16) {
149
- state.info_raw.bitdepth = 16;
150
- }
151
-
152
- state.encoder.filter_palette_zero = 0;
153
-
154
- std::vector<unsigned char> filters;
155
- switch (filterstrategy) {
156
- case kStrategyZero:
157
- state.encoder.filter_strategy = LFS_ZERO;
158
- break;
159
- case kStrategyMinSum:
160
- state.encoder.filter_strategy = LFS_MINSUM;
161
- break;
162
- case kStrategyEntropy:
163
- state.encoder.filter_strategy = LFS_ENTROPY;
164
- break;
165
- case kStrategyBruteForce:
166
- state.encoder.filter_strategy = LFS_BRUTE_FORCE;
167
- break;
168
- case kStrategyOne:
169
- case kStrategyTwo:
170
- case kStrategyThree:
171
- case kStrategyFour:
172
- // Set the filters of all scanlines to that number.
173
- filters.resize(h, filterstrategy);
174
- state.encoder.filter_strategy = LFS_PREDEFINED;
175
- state.encoder.predefined_filters = &filters[0];
176
- break;
177
- case kStrategyPredefined:
178
- lodepng::getFilterTypes(filters, origfile);
179
- state.encoder.filter_strategy = LFS_PREDEFINED;
180
- state.encoder.predefined_filters = &filters[0];
181
- break;
182
- default:
183
- break;
184
- }
185
-
186
- state.encoder.add_id = false;
187
- state.encoder.text_compression = 1;
188
-
189
- error = lodepng::encode(*out, image, w, h, state);
190
-
191
- // For very small output, also try without palette, it may be smaller thanks
192
- // to no palette storage overhead.
193
- if (!error && out->size() < 4096) {
194
- lodepng::State teststate;
195
- std::vector<unsigned char> temp;
196
- lodepng::decode(temp, w, h, teststate, *out);
197
- LodePNGColorMode& color = teststate.info_png.color;
198
- if (color.colortype == LCT_PALETTE) {
199
- std::vector<unsigned char> out2;
200
- state.encoder.auto_convert = LAC_ALPHA;
201
- bool grey = true;
202
- for (size_t i = 0; i < color.palettesize; i++) {
203
- if (color.palette[i * 4 + 0] != color.palette[i * 4 + 2]
204
- || color.palette[i * 4 + 1] != color.palette[i * 4 + 2]) {
205
- grey = false;
206
- break;
207
- }
208
- }
209
- if (grey) state.info_png.color.colortype = LCT_GREY_ALPHA;
210
-
211
- error = lodepng::encode(out2, image, w, h, state);
212
- if (out2.size() < out->size()) out->swap(out2);
213
- }
214
- }
215
-
216
- if (error) {
217
- printf("Encoding error %i: %s\n", error, lodepng_error_text(error));
218
- return error;
219
- }
220
-
221
- return 0;
222
- }
223
-
224
- // Use fast compression to check which PNG filter strategy gives the smallest
225
- // output. This allows to then do the slow and good compression only on that
226
- // filter type.
227
- unsigned AutoChooseFilterStrategy(const std::vector<unsigned char>& image,
228
- unsigned w, unsigned h,
229
- const lodepng::State& inputstate, bool bit16,
230
- const std::vector<unsigned char>& origfile,
231
- int numstrategies,
232
- ZopfliPNGFilterStrategy* strategies,
233
- bool* enable) {
234
- std::vector<unsigned char> out;
235
- size_t bestsize = 0;
236
- int bestfilter = 0;
237
-
238
- // A large window size should still be used to do the quick compression to
239
- // try out filter strategies: which filter strategy is the best depends
240
- // largely on the window size, the closer to the actual used window size the
241
- // better.
242
- int windowsize = 8192;
243
-
244
- for (int i = 0; i < numstrategies; i++) {
245
- out.clear();
246
- unsigned error = TryOptimize(image, w, h, inputstate, bit16, origfile,
247
- strategies[i], false, windowsize, 0, &out);
248
- if (error) return error;
249
- if (bestsize == 0 || out.size() < bestsize) {
250
- bestsize = out.size();
251
- bestfilter = i;
252
- }
253
- }
254
-
255
- for (int i = 0; i < numstrategies; i++) {
256
- enable[i] = (i == bestfilter);
257
- }
258
-
259
- return 0; /* OK */
260
- }
261
-
262
- // Keeps chunks with given names from the original png by literally copying them
263
- // into the new png
264
- void KeepChunks(const std::vector<unsigned char>& origpng,
265
- const std::vector<std::string>& keepnames,
266
- std::vector<unsigned char>* png) {
267
- std::vector<std::string> names[3];
268
- std::vector<std::vector<unsigned char> > chunks[3];
269
-
270
- lodepng::getChunks(names, chunks, origpng);
271
- std::vector<std::vector<unsigned char> > keepchunks[3];
272
-
273
- // There are 3 distinct locations in a PNG file for chunks: between IHDR and
274
- // PLTE, between PLTE and IDAT, and between IDAT and IEND. Keep each chunk at
275
- // its corresponding location in the new PNG.
276
- for (size_t i = 0; i < 3; i++) {
277
- for (size_t j = 0; j < names[i].size(); j++) {
278
- for (size_t k = 0; k < keepnames.size(); k++) {
279
- if (keepnames[k] == names[i][j]) {
280
- keepchunks[i].push_back(chunks[i][j]);
281
- }
282
- }
283
- }
284
- }
285
-
286
- lodepng::insertChunks(*png, keepchunks);
287
- }
288
-
289
- int ZopfliPNGOptimize(const std::vector<unsigned char>& origpng,
290
- const ZopfliPNGOptions& png_options,
291
- bool verbose,
292
- std::vector<unsigned char>* resultpng) {
293
- // Use the largest possible deflate window size
294
- int windowsize = 32768;
295
-
296
- ZopfliPNGFilterStrategy filterstrategies[kNumFilterStrategies] = {
297
- kStrategyZero, kStrategyOne, kStrategyTwo, kStrategyThree, kStrategyFour,
298
- kStrategyMinSum, kStrategyEntropy, kStrategyPredefined, kStrategyBruteForce
299
- };
300
- bool strategy_enable[kNumFilterStrategies] = {
301
- false, false, false, false, false, false, false, false, false
302
- };
303
- std::string strategy_name[kNumFilterStrategies] = {
304
- "zero", "one", "two", "three", "four",
305
- "minimum sum", "entropy", "predefined", "brute force"
306
- };
307
- for (size_t i = 0; i < png_options.filter_strategies.size(); i++) {
308
- strategy_enable[png_options.filter_strategies[i]] = true;
309
- }
310
-
311
-
312
- std::vector<unsigned char> image;
313
- unsigned w, h;
314
- unsigned error;
315
- lodepng::State inputstate;
316
- error = lodepng::decode(image, w, h, inputstate, origpng);
317
-
318
- if (error) {
319
- if (verbose) {
320
- printf("Decoding error %i: %s\n", error, lodepng_error_text(error));
321
- }
322
- return error;
323
- }
324
-
325
- bool bit16 = false; // Using 16-bit per channel raw image
326
- if (inputstate.info_png.color.bitdepth == 16 && !png_options.lossy_8bit) {
327
- // Decode as 16-bit
328
- image.clear();
329
- error = lodepng::decode(image, w, h, origpng, LCT_RGBA, 16);
330
- bit16 = true;
331
- }
332
-
333
- if (!error) {
334
- // If lossy_transparent, remove RGB information from pixels with alpha=0
335
- if (png_options.lossy_transparent && !bit16) {
336
- LossyOptimizeTransparent(&image[0], w, h);
337
- }
338
-
339
- if (png_options.auto_filter_strategy) {
340
- error = AutoChooseFilterStrategy(image, w, h, inputstate, bit16,
341
- origpng,
342
- /* Don't try brute force */
343
- kNumFilterStrategies - 1,
344
- filterstrategies, strategy_enable);
345
- }
346
- }
347
-
348
- if (!error) {
349
- size_t bestsize = 0;
350
-
351
- for (int i = 0; i < kNumFilterStrategies; i++) {
352
- if (!strategy_enable[i]) continue;
353
-
354
- std::vector<unsigned char> temp;
355
- error = TryOptimize(image, w, h, inputstate, bit16, origpng,
356
- filterstrategies[i], true /* use_zopfli */,
357
- windowsize, &png_options, &temp);
358
- if (!error) {
359
- if (verbose) {
360
- printf("Filter strategy %s: %d bytes\n",
361
- strategy_name[i].c_str(), (int) temp.size());
362
- }
363
- if (bestsize == 0 || temp.size() < bestsize) {
364
- bestsize = temp.size();
365
- (*resultpng).swap(temp); // Store best result so far in the output.
366
- }
367
- }
368
- }
369
-
370
- if (!png_options.keepchunks.empty()) {
371
- KeepChunks(origpng, png_options.keepchunks, resultpng);
372
- }
373
- }
374
-
375
- return error;
376
- }
@@ -1,79 +0,0 @@
1
- // Copyright 2013 Google Inc. All Rights Reserved.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
- //
15
- // Author: lode.vandevenne@gmail.com (Lode Vandevenne)
16
- // Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
17
-
18
- // Library to recompress and optimize PNG images. Uses Zopfli as the compression
19
- // backend, chooses optimal PNG color model, and tries out several PNG filter
20
- // strategies.
21
-
22
- #ifndef UTIL_COMPRESSION_ZOPFLI_PNG_ZOPFLIPNG_LIB_H_
23
- #define UTIL_COMPRESSION_ZOPFLI_PNG_ZOPFLIPNG_LIB_H_
24
-
25
- #include <string>
26
- #include <vector>
27
-
28
- enum ZopfliPNGFilterStrategy {
29
- kStrategyZero = 0,
30
- kStrategyOne = 1,
31
- kStrategyTwo = 2,
32
- kStrategyThree = 3,
33
- kStrategyFour = 4,
34
- kStrategyMinSum,
35
- kStrategyEntropy,
36
- kStrategyPredefined,
37
- kStrategyBruteForce,
38
- kNumFilterStrategies /* Not a strategy but used for the size of this enum */
39
- };
40
-
41
- struct ZopfliPNGOptions {
42
- ZopfliPNGOptions();
43
-
44
- // Allow altering hidden colors of fully transparent pixels
45
- bool lossy_transparent;
46
- // Convert 16-bit per channel images to 8-bit per channel
47
- bool lossy_8bit;
48
-
49
- // Filter strategies to try
50
- std::vector<ZopfliPNGFilterStrategy> filter_strategies;
51
-
52
- // Automatically choose filter strategy using less good compression
53
- bool auto_filter_strategy;
54
-
55
- // PNG chunks to keep
56
- // chunks to literally copy over from the original PNG to the resulting one
57
- std::vector<std::string> keepchunks;
58
-
59
- // Use Zopfli deflate compression
60
- bool use_zopfli;
61
-
62
- // Zopfli number of iterations
63
- int num_iterations;
64
-
65
- // Zopfli number of iterations on large images
66
- int num_iterations_large;
67
-
68
- // 0=none, 1=first, 2=last, 3=both
69
- int block_split_strategy;
70
- };
71
-
72
- // Returns 0 on success, error code otherwise.
73
- // If verbose is true, it will print some info while working.
74
- int ZopfliPNGOptimize(const std::vector<unsigned char>& origpng,
75
- const ZopfliPNGOptions& png_options,
76
- bool verbose,
77
- std::vector<unsigned char>* resultpng);
78
-
79
- #endif // UTIL_COMPRESSION_ZOPFLI_PNG_ZOPFLIPNG_LIB_H_