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,425 @@
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 <set>
24
+ #include <vector>
25
+
26
+ #include "lodepng/lodepng.h"
27
+ #include "lodepng/lodepng_util.h"
28
+ #include "../zopfli/deflate.h"
29
+
30
+ ZopfliPNGOptions::ZopfliPNGOptions()
31
+ : lossy_transparent(false)
32
+ , lossy_8bit(false)
33
+ , auto_filter_strategy(true)
34
+ , use_zopfli(true)
35
+ , num_iterations(15)
36
+ , num_iterations_large(5)
37
+ , block_split_strategy(1) {
38
+ }
39
+
40
+ // Deflate compressor passed as fuction pointer to LodePNG to have it use Zopfli
41
+ // as its compression backend.
42
+ unsigned CustomPNGDeflate(unsigned char** out, size_t* outsize,
43
+ const unsigned char* in, size_t insize,
44
+ const LodePNGCompressSettings* settings) {
45
+ const ZopfliPNGOptions* png_options =
46
+ static_cast<const ZopfliPNGOptions*>(settings->custom_context);
47
+ unsigned char bp = 0;
48
+ ZopfliOptions options;
49
+ ZopfliInitOptions(&options);
50
+
51
+ options.numiterations = insize < 200000
52
+ ? png_options->num_iterations : png_options->num_iterations_large;
53
+
54
+ if (png_options->block_split_strategy == 3) {
55
+ // Try both block splitting first and last.
56
+ unsigned char* out2 = 0;
57
+ size_t outsize2 = 0;
58
+ options.blocksplittinglast = 0;
59
+ ZopfliDeflate(&options, 2 /* Dynamic */, 1, in, insize, &bp, out, outsize);
60
+ bp = 0;
61
+ options.blocksplittinglast = 1;
62
+ ZopfliDeflate(&options, 2 /* Dynamic */, 1,
63
+ in, insize, &bp, &out2, &outsize2);
64
+
65
+ if (outsize2 < *outsize) {
66
+ free(*out);
67
+ *out = out2;
68
+ *outsize = outsize2;
69
+ printf("Block splitting last was better\n");
70
+ } else {
71
+ free(out2);
72
+ }
73
+ } else {
74
+ if (png_options->block_split_strategy == 0) options.blocksplitting = 0;
75
+ options.blocksplittinglast = png_options->block_split_strategy == 2;
76
+ ZopfliDeflate(&options, 2 /* Dynamic */, 1, in, insize, &bp, out, outsize);
77
+ }
78
+
79
+ return 0; // OK
80
+ }
81
+
82
+ // Returns 32-bit integer value for RGBA color.
83
+ static unsigned ColorIndex(const unsigned char* color) {
84
+ return color[0] + 256u * color[1] + 65536u * color[1] + 16777216u * color[3];
85
+ }
86
+
87
+ // Counts amount of colors in the image, up to 257. If transparent_counts_as_one
88
+ // is enabled, any color with alpha channel 0 is treated as a single color with
89
+ // index 0.
90
+ void CountColors(std::set<unsigned>* unique,
91
+ const unsigned char* image, unsigned w, unsigned h,
92
+ bool transparent_counts_as_one) {
93
+ unique->clear();
94
+ for (size_t i = 0; i < w * h; i++) {
95
+ unsigned index = ColorIndex(&image[i * 4]);
96
+ if (transparent_counts_as_one && image[i * 4 + 3] == 0) index = 0;
97
+ unique->insert(index);
98
+ if (unique->size() > 256) break;
99
+ }
100
+ }
101
+
102
+ // Remove RGB information from pixels with alpha=0
103
+ void LossyOptimizeTransparent(lodepng::State* inputstate, unsigned char* image,
104
+ unsigned w, unsigned h) {
105
+ // First check if we want to preserve potential color-key background color,
106
+ // or instead use the last encountered RGB value all the time to save bytes.
107
+ bool key = true;
108
+ for (size_t i = 0; i < w * h; i++) {
109
+ if (image[i * 4 + 3] > 0 && image[i * 4 + 3] < 255) {
110
+ key = false;
111
+ break;
112
+ }
113
+ }
114
+ std::set<unsigned> count; // Color count, up to 257.
115
+ CountColors(&count, image, w, h, true);
116
+ // If true, means palette is possible so avoid using different RGB values for
117
+ // the transparent color.
118
+ bool palette = count.size() <= 256;
119
+
120
+ // Choose the color key or first initial background color.
121
+ int r = 0, g = 0, b = 0;
122
+ if (key || palette) {
123
+ for (size_t i = 0; i < w * h; i++) {
124
+ if (image[i * 4 + 3] == 0) {
125
+ // Use RGB value of first encountered transparent pixel. This can be
126
+ // used as a valid color key, or in case of palette ensures a color
127
+ // existing in the input image palette is used.
128
+ r = image[i * 4 + 0];
129
+ g = image[i * 4 + 1];
130
+ b = image[i * 4 + 2];
131
+ }
132
+ }
133
+ }
134
+
135
+ for (size_t i = 0; i < w * h; i++) {
136
+ // if alpha is 0, alter the RGB value to a possibly more efficient one.
137
+ if (image[i * 4 + 3] == 0) {
138
+ image[i * 4 + 0] = r;
139
+ image[i * 4 + 1] = g;
140
+ image[i * 4 + 2] = b;
141
+ } else {
142
+ if (!key && !palette) {
143
+ // Use the last encountered RGB value if no key or palette is used: that
144
+ // way more values can be 0 thanks to the PNG filter types.
145
+ r = image[i * 4 + 0];
146
+ g = image[i * 4 + 1];
147
+ b = image[i * 4 + 2];
148
+ }
149
+ }
150
+ }
151
+
152
+ // If there are now less colors, update palette of input image to match this.
153
+ if (palette && inputstate->info_png.color.palettesize > 0) {
154
+ CountColors(&count, image, w, h, false);
155
+ if (count.size() < inputstate->info_png.color.palettesize) {
156
+ std::vector<unsigned char> palette_out;
157
+ unsigned char* palette_in = inputstate->info_png.color.palette;
158
+ for (size_t i = 0; i < inputstate->info_png.color.palettesize; i++) {
159
+ if (count.count(ColorIndex(&palette_in[i * 4])) != 0) {
160
+ palette_out.push_back(palette_in[i * 4 + 0]);
161
+ palette_out.push_back(palette_in[i * 4 + 1]);
162
+ palette_out.push_back(palette_in[i * 4 + 2]);
163
+ palette_out.push_back(palette_in[i * 4 + 3]);
164
+ }
165
+ }
166
+ inputstate->info_png.color.palettesize = palette_out.size() / 4;
167
+ for (size_t i = 0; i < palette_out.size(); i++) {
168
+ palette_in[i] = palette_out[i];
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ // Tries to optimize given a single PNG filter strategy.
175
+ // Returns 0 if ok, other value for error
176
+ unsigned TryOptimize(
177
+ const std::vector<unsigned char>& image, unsigned w, unsigned h,
178
+ const lodepng::State& inputstate, bool bit16,
179
+ const std::vector<unsigned char>& origfile,
180
+ ZopfliPNGFilterStrategy filterstrategy,
181
+ bool use_zopfli, int windowsize, const ZopfliPNGOptions* png_options,
182
+ std::vector<unsigned char>* out) {
183
+ unsigned error = 0;
184
+
185
+ lodepng::State state;
186
+ state.encoder.zlibsettings.windowsize = windowsize;
187
+ if (use_zopfli && png_options->use_zopfli) {
188
+ state.encoder.zlibsettings.custom_deflate = CustomPNGDeflate;
189
+ state.encoder.zlibsettings.custom_context = png_options;
190
+ }
191
+
192
+ if (inputstate.info_png.color.colortype == LCT_PALETTE) {
193
+ // Make it preserve the original palette order
194
+ lodepng_color_mode_copy(&state.info_raw, &inputstate.info_png.color);
195
+ state.info_raw.colortype = LCT_RGBA;
196
+ state.info_raw.bitdepth = 8;
197
+ }
198
+ if (bit16) {
199
+ state.info_raw.bitdepth = 16;
200
+ }
201
+
202
+ state.encoder.filter_palette_zero = 0;
203
+
204
+ std::vector<unsigned char> filters;
205
+ switch (filterstrategy) {
206
+ case kStrategyZero:
207
+ state.encoder.filter_strategy = LFS_ZERO;
208
+ break;
209
+ case kStrategyMinSum:
210
+ state.encoder.filter_strategy = LFS_MINSUM;
211
+ break;
212
+ case kStrategyEntropy:
213
+ state.encoder.filter_strategy = LFS_ENTROPY;
214
+ break;
215
+ case kStrategyBruteForce:
216
+ state.encoder.filter_strategy = LFS_BRUTE_FORCE;
217
+ break;
218
+ case kStrategyOne:
219
+ case kStrategyTwo:
220
+ case kStrategyThree:
221
+ case kStrategyFour:
222
+ // Set the filters of all scanlines to that number.
223
+ filters.resize(h, filterstrategy);
224
+ state.encoder.filter_strategy = LFS_PREDEFINED;
225
+ state.encoder.predefined_filters = &filters[0];
226
+ break;
227
+ case kStrategyPredefined:
228
+ lodepng::getFilterTypes(filters, origfile);
229
+ state.encoder.filter_strategy = LFS_PREDEFINED;
230
+ state.encoder.predefined_filters = &filters[0];
231
+ break;
232
+ default:
233
+ break;
234
+ }
235
+
236
+ state.encoder.add_id = false;
237
+ state.encoder.text_compression = 1;
238
+
239
+ error = lodepng::encode(*out, image, w, h, state);
240
+
241
+ // For very small output, also try without palette, it may be smaller thanks
242
+ // to no palette storage overhead.
243
+ if (!error && out->size() < 4096) {
244
+ lodepng::State teststate;
245
+ std::vector<unsigned char> temp;
246
+ lodepng::decode(temp, w, h, teststate, *out);
247
+ LodePNGColorMode& color = teststate.info_png.color;
248
+ if (color.colortype == LCT_PALETTE) {
249
+ std::vector<unsigned char> out2;
250
+ state.encoder.auto_convert = LAC_ALPHA;
251
+ bool grey = true;
252
+ for (size_t i = 0; i < color.palettesize; i++) {
253
+ if (color.palette[i * 4 + 0] != color.palette[i * 4 + 2]
254
+ || color.palette[i * 4 + 1] != color.palette[i * 4 + 2]) {
255
+ grey = false;
256
+ break;
257
+ }
258
+ }
259
+ if (grey) state.info_png.color.colortype = LCT_GREY_ALPHA;
260
+
261
+ error = lodepng::encode(out2, image, w, h, state);
262
+ if (out2.size() < out->size()) out->swap(out2);
263
+ }
264
+ }
265
+
266
+ if (error) {
267
+ printf("Encoding error %u: %s\n", error, lodepng_error_text(error));
268
+ return error;
269
+ }
270
+
271
+ return 0;
272
+ }
273
+
274
+ // Use fast compression to check which PNG filter strategy gives the smallest
275
+ // output. This allows to then do the slow and good compression only on that
276
+ // filter type.
277
+ unsigned AutoChooseFilterStrategy(const std::vector<unsigned char>& image,
278
+ unsigned w, unsigned h,
279
+ const lodepng::State& inputstate, bool bit16,
280
+ const std::vector<unsigned char>& origfile,
281
+ int numstrategies,
282
+ ZopfliPNGFilterStrategy* strategies,
283
+ bool* enable) {
284
+ std::vector<unsigned char> out;
285
+ size_t bestsize = 0;
286
+ int bestfilter = 0;
287
+
288
+ // A large window size should still be used to do the quick compression to
289
+ // try out filter strategies: which filter strategy is the best depends
290
+ // largely on the window size, the closer to the actual used window size the
291
+ // better.
292
+ int windowsize = 8192;
293
+
294
+ for (int i = 0; i < numstrategies; i++) {
295
+ out.clear();
296
+ unsigned error = TryOptimize(image, w, h, inputstate, bit16, origfile,
297
+ strategies[i], false, windowsize, 0, &out);
298
+ if (error) return error;
299
+ if (bestsize == 0 || out.size() < bestsize) {
300
+ bestsize = out.size();
301
+ bestfilter = i;
302
+ }
303
+ }
304
+
305
+ for (int i = 0; i < numstrategies; i++) {
306
+ enable[i] = (i == bestfilter);
307
+ }
308
+
309
+ return 0; /* OK */
310
+ }
311
+
312
+ // Keeps chunks with given names from the original png by literally copying them
313
+ // into the new png
314
+ void KeepChunks(const std::vector<unsigned char>& origpng,
315
+ const std::vector<std::string>& keepnames,
316
+ std::vector<unsigned char>* png) {
317
+ std::vector<std::string> names[3];
318
+ std::vector<std::vector<unsigned char> > chunks[3];
319
+
320
+ lodepng::getChunks(names, chunks, origpng);
321
+ std::vector<std::vector<unsigned char> > keepchunks[3];
322
+
323
+ // There are 3 distinct locations in a PNG file for chunks: between IHDR and
324
+ // PLTE, between PLTE and IDAT, and between IDAT and IEND. Keep each chunk at
325
+ // its corresponding location in the new PNG.
326
+ for (size_t i = 0; i < 3; i++) {
327
+ for (size_t j = 0; j < names[i].size(); j++) {
328
+ for (size_t k = 0; k < keepnames.size(); k++) {
329
+ if (keepnames[k] == names[i][j]) {
330
+ keepchunks[i].push_back(chunks[i][j]);
331
+ }
332
+ }
333
+ }
334
+ }
335
+
336
+ lodepng::insertChunks(*png, keepchunks);
337
+ }
338
+
339
+ int ZopfliPNGOptimize(const std::vector<unsigned char>& origpng,
340
+ const ZopfliPNGOptions& png_options,
341
+ bool verbose,
342
+ std::vector<unsigned char>* resultpng) {
343
+ // Use the largest possible deflate window size
344
+ int windowsize = 32768;
345
+
346
+ ZopfliPNGFilterStrategy filterstrategies[kNumFilterStrategies] = {
347
+ kStrategyZero, kStrategyOne, kStrategyTwo, kStrategyThree, kStrategyFour,
348
+ kStrategyMinSum, kStrategyEntropy, kStrategyPredefined, kStrategyBruteForce
349
+ };
350
+ bool strategy_enable[kNumFilterStrategies] = {
351
+ false, false, false, false, false, false, false, false, false
352
+ };
353
+ std::string strategy_name[kNumFilterStrategies] = {
354
+ "zero", "one", "two", "three", "four",
355
+ "minimum sum", "entropy", "predefined", "brute force"
356
+ };
357
+ for (size_t i = 0; i < png_options.filter_strategies.size(); i++) {
358
+ strategy_enable[png_options.filter_strategies[i]] = true;
359
+ }
360
+
361
+ std::vector<unsigned char> image;
362
+ unsigned w, h;
363
+ unsigned error;
364
+ lodepng::State inputstate;
365
+ error = lodepng::decode(image, w, h, inputstate, origpng);
366
+
367
+ if (error) {
368
+ if (verbose) {
369
+ printf("Decoding error %i: %s\n", error, lodepng_error_text(error));
370
+ }
371
+ return error;
372
+ }
373
+
374
+ bool bit16 = false; // Using 16-bit per channel raw image
375
+ if (inputstate.info_png.color.bitdepth == 16 && !png_options.lossy_8bit) {
376
+ // Decode as 16-bit
377
+ image.clear();
378
+ error = lodepng::decode(image, w, h, origpng, LCT_RGBA, 16);
379
+ bit16 = true;
380
+ }
381
+
382
+ if (!error) {
383
+ // If lossy_transparent, remove RGB information from pixels with alpha=0
384
+ if (png_options.lossy_transparent && !bit16) {
385
+ LossyOptimizeTransparent(&inputstate, &image[0], w, h);
386
+ }
387
+
388
+ if (png_options.auto_filter_strategy) {
389
+ error = AutoChooseFilterStrategy(image, w, h, inputstate, bit16,
390
+ origpng,
391
+ /* Don't try brute force */
392
+ kNumFilterStrategies - 1,
393
+ filterstrategies, strategy_enable);
394
+ }
395
+ }
396
+
397
+ if (!error) {
398
+ size_t bestsize = 0;
399
+
400
+ for (int i = 0; i < kNumFilterStrategies; i++) {
401
+ if (!strategy_enable[i]) continue;
402
+
403
+ std::vector<unsigned char> temp;
404
+ error = TryOptimize(image, w, h, inputstate, bit16, origpng,
405
+ filterstrategies[i], true /* use_zopfli */,
406
+ windowsize, &png_options, &temp);
407
+ if (!error) {
408
+ if (verbose) {
409
+ printf("Filter strategy %s: %d bytes\n",
410
+ strategy_name[i].c_str(), (int) temp.size());
411
+ }
412
+ if (bestsize == 0 || temp.size() < bestsize) {
413
+ bestsize = temp.size();
414
+ (*resultpng).swap(temp); // Store best result so far in the output.
415
+ }
416
+ }
417
+ }
418
+
419
+ if (!png_options.keepchunks.empty()) {
420
+ KeepChunks(origpng, png_options.keepchunks, resultpng);
421
+ }
422
+ }
423
+
424
+ return error;
425
+ }
@@ -0,0 +1,79 @@
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 ZOPFLIPNG_LIB_H_
23
+ #define 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 // ZOPFLIPNG_LIB_H_