zopfli 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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_