1337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Copyright 2013 Google Inc. All Rights Reserved. 2337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// 3337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Licensed under the Apache License, Version 2.0 (the "License"); 4337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// you may not use this file except in compliance with the License. 5337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// You may obtain a copy of the License at 6337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// 7337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// http://www.apache.org/licenses/LICENSE-2.0 8337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// 9337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Unless required by applicable law or agreed to in writing, software 10337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// distributed under the License is distributed on an "AS IS" BASIS, 11337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// See the License for the specific language governing permissions and 13337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// limitations under the License. 14337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// 15337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Author: lode.vandevenne@gmail.com (Lode Vandevenne) 16337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala) 17337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 18337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Command line tool to recompress and optimize PNG images, using zopflipng_lib. 19337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 20337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne#include <stdlib.h> 21337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne#include <stdio.h> 22337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 23337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne#include "lodepng/lodepng.h" 24337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne#include "zopflipng_lib.h" 25337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 26337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Returns directory path (including last slash) in dir, filename without 27337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// extension in file, extension (including the dot) in ext 28337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennevoid GetFileNameParts(const std::string& filename, 29337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string* dir, std::string* file, std::string* ext) { 30337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t npos = (size_t)(-1); 31337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t slashpos = filename.find_last_of("/\\"); 32337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string nodir; 33337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (slashpos == npos) { 34337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne *dir = ""; 35337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne nodir = filename; 36337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 37337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne *dir = filename.substr(0, slashpos + 1); 38337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne nodir = filename.substr(slashpos + 1); 39337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 40337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t dotpos = nodir.find_last_of('.'); 41337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (dotpos == (size_t)(-1)) { 42337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne *file = nodir; 43337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne *ext = ""; 44337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 45337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne *file = nodir.substr(0, dotpos); 46337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne *ext = nodir.substr(dotpos); 47337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 48337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne} 49337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 50337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne// Returns the size of the file 51337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennesize_t GetFileSize(const std::string& filename) { 52337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t size; 53337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne FILE* file = fopen(filename.c_str(), "rb"); 54337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!file) return 0; 55337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne fseek(file , 0 , SEEK_END); 56337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size = static_cast<size_t>(ftell(file)); 57337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne fclose(file); 58337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return size; 59337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne} 60337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 61337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennevoid ShowHelp() { 62337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("ZopfliPNG, a Portable Network Graphics (PNG) image optimizer.\n" 63337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "\n" 64337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "Usage: zopflipng [options]... infile.png outfile.png\n" 65337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " zopflipng [options]... --prefix=[fileprefix] [files.png]...\n" 66337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "\n" 67337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "If the output file exists, it is considered a result from a" 68337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " previous run and not overwritten if its filesize is smaller.\n" 69337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "\n" 70337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "Options:\n" 71337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "-m: compress more: use more iterations (depending on file size) and" 72337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " use block split strategy 3\n" 73337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--prefix=[fileprefix]: Adds a prefix to output filenames. May also" 74337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " contain a directory path. When using a prefix, multiple input files" 75337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " can be given and the output filenames are generated with the" 76337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " prefix\n" 77337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " If --prefix is specified without value, 'zopfli_' is used.\n" 78337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " If input file names contain the prefix, they are not processed but" 79337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " considered as output from previous runs. This is handy when using" 80337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " *.png wildcard expansion with multiple runs.\n" 81337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "-y: do not ask about overwriting files.\n" 82337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--lossy_transparent: remove colors behind alpha channel 0. No visual" 83337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " difference, removes hidden information.\n" 84337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--lossy_8bit: convert 16-bit per channel image to 8-bit per" 85337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " channel.\n" 86337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "-d: dry run: don't save any files, just see the console output" 87337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " (e.g. for benchmarking)\n" 88337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--always_zopflify: always output the image encoded by Zopfli, even if" 89337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " it's bigger than the original, for benchmarking the algorithm. Not" 90337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " good for real optimization.\n" 91337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "-q: use quick, but not very good, compression" 92337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " (e.g. for only trying the PNG filter and color types)\n" 93337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--iterations=[number]: number of iterations, more iterations makes it" 94337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " slower but provides slightly better compression. Default: 15 for" 95337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " small files, 5 for large files.\n" 96337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--splitting=[0-3]: block split strategy:" 97337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " 0=none, 1=first, 2=last, 3=try both and take the best\n" 98337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--filters=[types]: filter strategies to try:\n" 99337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " 0-4: give all scanlines PNG filter type 0-4\n" 100337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " m: minimum sum\n" 101337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " e: entropy\n" 102337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " p: predefined (keep from input, this likely overlaps another" 103337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " strategy)\n" 104337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " b: brute force (experimental)\n" 105337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " By default, if this argument is not given, one that is most likely" 106337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " the best for this image is chosen by trying faster compression with" 107337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " each type.\n" 108337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " If this argument is used, all given filter types" 109337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " are tried with slow compression and the best result retained. A good" 110337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " set of filters to try is --filters=0me.\n" 111337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "--keepchunks=nAME,nAME,...: keep metadata chunks with these names" 112337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " that would normally be removed, e.g. tEXt,zTXt,iTXt,gAMA, ... \n" 113337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " Due to adding extra data, this increases the result size. By default" 114337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " ZopfliPNG only keeps the following chunks because they are" 115337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " essential: IHDR, PLTE, tRNS, IDAT and IEND.\n" 116337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "\n" 117337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "Usage examples:\n" 118337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "Optimize a file and overwrite if smaller: zopflipng infile.png" 119337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " outfile.png\n" 120337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "Compress more: zopflipng -m infile.png outfile.png\n" 121337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "Optimize multiple files: zopflipng --prefix a.png b.png c.png\n" 122337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne "Compress really good and trying all filter strategies: zopflipng" 123337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " --iterations=500 --splitting=3 --filters=01234mepb" 124337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " --lossy_8bit --lossy_transparent infile.png outfile.png\n"); 125337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne} 126337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 127337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennevoid PrintSize(const char* label, size_t size) { 128337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("%s: %d (%dK)\n", label, (int) size, (int) size / 1024); 129337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne} 130337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 131337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevennevoid PrintResultSize(const char* label, size_t oldsize, size_t newsize) { 132337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("%s: %d (%dK). Percentage of original: %.3f%%\n", 133337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne label, (int) newsize, (int) newsize / 1024, newsize * 100.0 / oldsize); 134337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne} 135337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 136337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenneint main(int argc, char *argv[]) { 137337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (argc < 2) { 138337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ShowHelp(); 139337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 0; 140337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 141337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 142337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ZopfliPNGOptions png_options; 143337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 144337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // cmd line options 145337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool always_zopflify = false; // overwrite file even if we have bigger result 146337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool yes = false; // do not ask to overwrite files 147337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool dryrun = false; // never save anything 148337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 149337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string user_out_filename; // output filename if no prefix is used 150337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool use_prefix = false; 151337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string prefix = "zopfli_"; // prefix for output filenames 152337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 153337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::vector<std::string> files; 154337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::vector<char> options; 155337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne for (int i = 1; i < argc; i++) { 156337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string arg = argv[i]; 157337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (arg[0] == '-' && arg.size() > 1 && arg[1] != '-') { 158337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne for (size_t pos = 1; pos < arg.size(); pos++) { 159337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne char c = arg[pos]; 160337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (c == 'y') { 161337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne yes = true; 162337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (c == 'd') { 163337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne dryrun = true; 164337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (c == 'm') { 165337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.num_iterations *= 4; 166337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.num_iterations_large *= 4; 167337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.block_split_strategy = 3; 168337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (c == 'q') { 169337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.use_zopfli = false; 170337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (c == 'h') { 171337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ShowHelp(); 172337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 0; 173337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 174337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Unknown flag: %c\n", c); 175337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 0; 176337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 177337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 178337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (arg[0] == '-' && arg.size() > 1 && arg[1] == '-') { 179337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t eq = arg.find('='); 180337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string name = arg.substr(0, eq); 181337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string value = eq >= arg.size() - 1 ? "" : arg.substr(eq + 1); 182337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne int num = atoi(value.c_str()); 183337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (name == "--always_zopflify") { 184337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne always_zopflify = true; 185337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--lossy_transparent") { 186337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.lossy_transparent = true; 187337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--lossy_8bit") { 188337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.lossy_8bit = true; 189337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--iterations") { 190337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (num < 1) num = 1; 191337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.num_iterations = num; 192337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.num_iterations_large = num; 193337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--splitting") { 194337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (num < 0 || num > 3) num = 1; 195337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.block_split_strategy = num; 196337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--filters") { 197337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne for (size_t j = 0; j < value.size(); j++) { 198337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ZopfliPNGFilterStrategy strategy = kStrategyZero; 199337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne char f = value[j]; 200337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne switch (f) { 201337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case '0': strategy = kStrategyZero; break; 202337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case '1': strategy = kStrategyOne; break; 203337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case '2': strategy = kStrategyTwo; break; 204337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case '3': strategy = kStrategyThree; break; 205337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case '4': strategy = kStrategyFour; break; 206337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case 'm': strategy = kStrategyMinSum; break; 207337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case 'e': strategy = kStrategyEntropy; break; 208337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case 'p': strategy = kStrategyPredefined; break; 209337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne case 'b': strategy = kStrategyBruteForce; break; 210337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne default: 211337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Unknown filter strategy: %c\n", f); 212337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 1; 213337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 214337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.filter_strategies.push_back(strategy); 215337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // Enable auto filter strategy only if no user-specified filter is 216337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // given. 217337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.auto_filter_strategy = false; 218337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 219337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--keepchunks") { 220337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool correct = true; 221337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if ((value.size() + 1) % 5 != 0) correct = false; 222337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne for (size_t i = 0; i + 4 <= value.size() && correct; i += 5) { 223337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne png_options.keepchunks.push_back(value.substr(i, 4)); 224337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (i > 4 && value[i - 1] != ',') correct = false; 225337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 226337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!correct) { 227337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Error: keepchunks format must be like for example:\n" 228337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne " --keepchunks=gAMA,cHRM,sRGB,iCCP\n"); 229337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 0; 230337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 231337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--prefix") { 232337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne use_prefix = true; 233337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!value.empty()) prefix = value; 234337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (name == "--help") { 235337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ShowHelp(); 236337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 0; 237337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 238337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Unknown flag: %s\n", name.c_str()); 239337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 0; 240337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 241337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 242337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne files.push_back(argv[i]); 243337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 244337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 245337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 246337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!use_prefix) { 247337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (files.size() == 2) { 248337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // The second filename is the output instead of an input if no prefix is 249337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // given. 250337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne user_out_filename = files[1]; 251337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne files.resize(1); 252337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 253337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Please provide one input and output filename\n\n"); 254337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ShowHelp(); 255337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return 0; 256337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 257337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 258337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 259337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_in_size = 0; 260337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // Total output size, taking input size if the input file was smaller 261337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_out_size = 0; 262337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // Total output size that zopfli produced, even if input was smaller, for 263337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // benchmark information 264337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_out_size_zopfli = 0; 265337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_errors = 0; 266337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_files = 0; 267337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_files_smaller = 0; 268337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_files_saved = 0; 269337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t total_files_equal = 0; 270337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 271337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne for (size_t i = 0; i < files.size(); i++) { 272337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (use_prefix && files.size() > 1) { 273337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string dir, file, ext; 274337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne GetFileNameParts(files[i], &dir, &file, &ext); 275337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // avoid doing filenames which were already output by this so that you 276337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // don't get zopfli_zopfli_zopfli_... files after multiple runs. 277337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (file.find(prefix) == 0) continue; 278337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 279337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 280337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_files++; 281337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 282337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Optimizing %s\n", files[i].c_str()); 283337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::vector<unsigned char> image; 284337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne unsigned w, h; 285337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::vector<unsigned char> origpng; 286337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne unsigned error; 287337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne lodepng::State inputstate; 288337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::vector<unsigned char> resultpng; 289337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 290337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne lodepng::load_file(origpng, files[i]); 291337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne error = ZopfliPNGOptimize(origpng, png_options, true, &resultpng); 292337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 293337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (error) { 294337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Decoding error %i: %s\n", error, lodepng_error_text(error)); 295337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 296337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 297337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // Verify result, check that the result causes no decoding errors 298337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!error) { 299337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne error = lodepng::decode(image, w, h, inputstate, resultpng); 300337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (error) printf("Error: verification of result failed.\n"); 301337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 302337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 303337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (error) { 304337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("There was an error\n"); 305337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_errors++; 306337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 307337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t origsize = GetFileSize(files[i]); 308337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t resultsize = resultpng.size(); 309337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 310337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (resultsize < origsize) { 311337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Result is smaller\n"); 312337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else if (resultsize == origsize) { 313337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Result has exact same size\n"); 314337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 315337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf(always_zopflify 316337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ? "Original was smaller\n" 317337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne : "Preserving original PNG since it was smaller\n"); 318337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 319337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne PrintSize("Input size", origsize); 320337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne PrintResultSize("Result size", origsize, resultsize); 321337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 322337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string out_filename = user_out_filename; 323337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (use_prefix) { 324337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne std::string dir, file, ext; 325337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne GetFileNameParts(files[i], &dir, &file, &ext); 326337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne out_filename = dir + prefix + file + ext; 327337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 328337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool different_output_name = out_filename != files[i]; 329337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 330337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_in_size += origsize; 331337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_out_size_zopfli += resultpng.size(); 332337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (resultpng.size() < origsize) total_files_smaller++; 333337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne else if (resultpng.size() == origsize) total_files_equal++; 334337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 335337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!always_zopflify && resultpng.size() > origsize) { 336337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // Set output file to input since input was smaller. 337337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne resultpng = origpng; 338337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 339337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 340337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne size_t origoutfilesize = GetFileSize(out_filename); 341337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool already_exists = true; 342337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (origoutfilesize == 0) already_exists = false; 343337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 344337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // When using a prefix, and the output file already exist, assume it's 345337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // from a previous run. If that file is smaller, it may represent a 346337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // previous run with different parameters that gave a smaller PNG image. 347337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // In that case, do not overwrite it. This behaviour can be removed by 348337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // adding the always_zopflify flag. 349337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool keep_earlier_output_file = already_exists && 350337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne resultpng.size() >= origoutfilesize && !always_zopflify && use_prefix; 351337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 352337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (keep_earlier_output_file) { 353337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // An output file from a previous run is kept, add that files' size 354337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // to the output size statistics. 355337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_out_size += origoutfilesize; 356337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (different_output_name) { 357337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf(resultpng.size() == origoutfilesize 358337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne ? "File not written because a previous run was as good.\n" 359337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne : "File not written because a previous run was better.\n"); 360337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 361337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 362337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne bool confirmed = true; 363337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!yes && !dryrun && already_exists) { 364337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("File %s exists, overwrite? (y/N) ", out_filename.c_str()); 365c54dc204ef4278f949a965dc90e693799b6aae41Lode Vandevenne char answer = 0; 366c54dc204ef4278f949a965dc90e693799b6aae41Lode Vandevenne // Read the first character, the others and enter with getchar. 367c54dc204ef4278f949a965dc90e693799b6aae41Lode Vandevenne while (int input = getchar()) { 368c54dc204ef4278f949a965dc90e693799b6aae41Lode Vandevenne if (input == '\n' || input == EOF) break; 369c54dc204ef4278f949a965dc90e693799b6aae41Lode Vandevenne else if (!answer) answer = input; 370c54dc204ef4278f949a965dc90e693799b6aae41Lode Vandevenne } 371c54dc204ef4278f949a965dc90e693799b6aae41Lode Vandevenne confirmed = answer == 'y' || answer == 'Y'; 372337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 373337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (confirmed) { 374337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (!dryrun) { 375337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne lodepng::save_file(resultpng, out_filename); 376337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_files_saved++; 377337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 378337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_out_size += resultpng.size(); 379337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } else { 380337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // An output file from a previous run is kept, add that files' size 381337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne // to the output size statistics. 382337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_out_size += origoutfilesize; 383337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 384337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 385337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 386337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("\n"); 387337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 388337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 389337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (total_files > 1) { 390337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Summary for all files:\n"); 391337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Files tried: %d\n", (int) total_files); 392337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Files smaller: %d\n", (int) total_files_smaller); 393337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (total_files_equal) { 394337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Files equal: %d\n", (int) total_files_equal); 395337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 396337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne printf("Files saved: %d\n", (int) total_files_saved); 397337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (total_errors) printf("Errors: %d\n", (int) total_errors); 398337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne PrintSize("Total input size", total_in_size); 399337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne PrintResultSize("Total output size", total_in_size, total_out_size); 400337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne PrintResultSize("Benchmark result size", 401337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne total_in_size, total_out_size_zopfli); 402337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne } 403337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 404337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne if (dryrun) printf("No files were written because dry run was specified\n"); 405337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne 406337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne return total_errors; 407337d27f25ef15a6cf34fef2acd0613fddc411cb1Lode Vandevenne} 408