/* LodePNG Examples Copyright (c) 2005-2012 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* This example saves the PNG with the best compression LodePNG can do, and with unnecessary chunks removed. It tries out several combinations of settings and keeps the smallest one. NOTE: This is not as good as a true PNG optimizer like optipng or pngcrush. */ //g++ lodepng.cpp example_optimize_png.cpp -ansi -pedantic -Wall -Wextra -O3 #include "lodepng.h" #include int main(int argc, char *argv[]) { std::vector image; unsigned w, h; std::vector buffer; unsigned error; //check if user gave a filename if(argc < 3) { std::cout << "please provide in and out filename" << std::endl; return 0; } lodepng::load_file(buffer, argv[1]); error = lodepng::decode(image, w, h, buffer); if(error) { std::cout << "decoding error " << error << ": " << lodepng_error_text(error) << std::endl; return 0; } size_t origsize = buffer.size(); std::cout << "Original size: " << origsize << " (" << (origsize / 1024) << "K)" << std::endl; buffer.clear(); //Now encode as hard as possible with several filter types and window sizes lodepng::State state; state.encoder.filter_palette_zero = 0; //We try several filter types, including zero, allow trying them all on palette images too. state.encoder.add_id = false; //Don't add LodePNG version chunk to save more bytes state.encoder.text_compression = 1; //Not needed because we don't add text chunks, but this demonstrates another optimization setting state.encoder.zlibsettings.nicematch = 258; //Set this to the max possible, otherwise it can hurt compression state.encoder.zlibsettings.lazymatching = 1; //Definitely use lazy matching for better compression state.encoder.zlibsettings.windowsize = 32768; //Use maximum possible window size for best compression size_t bestsize = 0; bool inited = false; int beststrategy = 0; LodePNGFilterStrategy strategies[4] = { LFS_ZERO, LFS_MINSUM, LFS_ENTROPY, LFS_BRUTE_FORCE }; std::string strategynames[4] = { "LFS_ZERO", "LFS_MINSUM", "LFS_ENTROPY", "LFS_BRUTE_FORCE" }; // min match 3 allows all deflate lengths. min match 6 is similar to "Z_FILTERED" of zlib. int minmatches[2] = { 3, 6 }; int bestminmatch = 0; int autoconverts[2] = { 0, 1 }; std::string autoconvertnames[2] = { "0", "1" }; int bestautoconvert = 0; int bestblocktype = 0; // Try out all combinations of everything for(int i = 0; i < 4; i++) //filter strategy for(int j = 0; j < 2; j++) //min match for(int k = 0; k < 2; k++) //block type (for small images only) for(int l = 0; l < 2; l++) { //color convert strategy if(bestsize > 3000 && (k > 0 || l > 0)) continue; /* these only make sense on small images */ std::vector temp; state.encoder.filter_strategy = strategies[i]; state.encoder.zlibsettings.minmatch = minmatches[j]; state.encoder.zlibsettings.btype = k == 0 ? 2 : 1; state.encoder.auto_convert = autoconverts[l]; error = lodepng::encode(temp, image, w, h, state); if(error) { std::cout << "encoding error " << error << ": " << lodepng_error_text(error) << std::endl; return 0; } if(!inited || temp.size() < bestsize) { bestsize = temp.size(); beststrategy = i; bestminmatch = state.encoder.zlibsettings.minmatch; bestautoconvert = l; bestblocktype = state.encoder.zlibsettings.btype; temp.swap(buffer); inited = true; } } std::cout << "Chosen filter strategy: " << strategynames[beststrategy] << std::endl; std::cout << "Chosen min match: " << bestminmatch << std::endl; std::cout << "Chosen block type: " << bestblocktype << std::endl; std::cout << "Chosen auto convert: " << autoconvertnames[bestautoconvert] << std::endl; lodepng::save_file(buffer, argv[2]); std::cout << "New size: " << buffer.size() << " (" << (buffer.size() / 1024) << "K)" << std::endl; }