pngquant_error pngquant_file(const char *filename, const char *outname, struct pngquant_options *options) { pngquant_error retval = SUCCESS; verbose_printf(options, "%s:", filename); liq_image *input_image = NULL; png24_image input_image_rwpng = {}; bool keep_input_pixels = options->using_stdin && options->min_quality_limit; // original may need to be output to stdout if (!retval) { retval = read_image(options->liq, filename, options->using_stdin, &input_image_rwpng, &input_image, keep_input_pixels); } png8_image output_image = {}; if (!retval) { verbose_printf(options, " read %luKB file corrected for gamma %2.1f", (input_image_rwpng.file_size+1023UL)/1024UL, 1.0/input_image_rwpng.gamma); // when using image as source of a fixed palette the palette is extracted using regular quantization liq_result *remap = liq_quantize_image(options->liq, options->fixed_palette_image ? options->fixed_palette_image : input_image); if (remap) { liq_set_output_gamma(remap, 0.45455); // fixed gamma ~2.2 for the web. PNG can't store exact 1/2.2 liq_set_dithering_level(remap, options->floyd); retval = prepare_output_image(remap, input_image, &output_image); if (!retval) { if (LIQ_OK != liq_write_remapped_image_rows(remap, input_image, output_image.row_pointers)) { retval = OUT_OF_MEMORY_ERROR; } set_palette(remap, &output_image); double palette_error = liq_get_quantization_error(remap); if (palette_error >= 0) { verbose_printf(options, " mapped image to new colors...MSE=%.3f (Q=%d)", palette_error, liq_get_quantization_quality(remap)); } } liq_result_destroy(remap); } else { retval = TOO_LOW_QUALITY; } } if (!retval) { output_image.fast_compression = options->fast_compression; retval = write_image(&output_image, NULL, outname, options); } else if (TOO_LOW_QUALITY == retval && options->using_stdin) { // when outputting to stdout it'd be nasty to create 0-byte file // so if quality is too low, output 24-bit original pngquant_error write_retval = write_image(NULL, &input_image_rwpng, outname, options); if (write_retval) retval = write_retval; } liq_image_destroy(input_image); pngquant_output_image_free(&output_image); free(input_image_rwpng.row_pointers); free(input_image_rwpng.rgba_data); return retval; }
pngquant_error pngquant_file(const char *filename, const char *outname, struct pngquant_options *options) { pngquant_error retval = SUCCESS; verbose_printf(options, "%s:", filename); liq_image *input_image = NULL; png24_image input_image_rwpng = {}; bool keep_input_pixels = options->skip_if_larger || (options->using_stdin && options->min_quality_limit); // original may need to be output to stdout if (!retval) { retval = read_image(options->liq, filename, options->using_stdin, &input_image_rwpng, &input_image, keep_input_pixels); } int quality_percent = 90; // quality on 0-100 scale, updated upon successful remap png8_image output_image = {}; if (!retval) { verbose_printf(options, " read %luKB file corrected for gamma %2.1f", (input_image_rwpng.file_size+1023UL)/1024UL, 1.0/input_image_rwpng.gamma); // when using image as source of a fixed palette the palette is extracted using regular quantization liq_result *remap = liq_quantize_image(options->liq, options->fixed_palette_image ? options->fixed_palette_image : input_image); if (remap) { liq_set_output_gamma(remap, 0.45455); // fixed gamma ~2.2 for the web. PNG can't store exact 1/2.2 liq_set_dithering_level(remap, options->floyd); retval = prepare_output_image(remap, input_image, &output_image); if (!retval) { if (LIQ_OK != liq_write_remapped_image_rows(remap, input_image, output_image.row_pointers)) { retval = OUT_OF_MEMORY_ERROR; } set_palette(remap, &output_image); double palette_error = liq_get_quantization_error(remap); if (palette_error >= 0) { quality_percent = liq_get_quantization_quality(remap); verbose_printf(options, " mapped image to new colors...MSE=%.3f (Q=%d)", palette_error, quality_percent); } } liq_result_destroy(remap); } else { retval = TOO_LOW_QUALITY; } } if (!retval) { if (options->skip_if_larger) { // this is very rough approximation, but generally avoid losing more quality than is gained in file size. // Quality is squared, because even greater savings are needed to justify big quality loss. double quality = quality_percent/100.0; output_image.maximum_file_size = input_image_rwpng.file_size * quality*quality; } output_image.fast_compression = options->fast_compression; retval = write_image(&output_image, NULL, outname, options); if (TOO_LARGE_FILE == retval) { verbose_printf(options, " file exceeded expected size of %luKB", (unsigned long)output_image.maximum_file_size/1024UL); } } if (TOO_LARGE_FILE == retval || (TOO_LOW_QUALITY == retval && options->using_stdin)) { // when outputting to stdout it'd be nasty to create 0-byte file // so if quality is too low, output 24-bit original if (keep_input_pixels) { pngquant_error write_retval = write_image(NULL, &input_image_rwpng, outname, options); if (write_retval) retval = write_retval; } } liq_image_destroy(input_image); pngquant_output_image_free(&output_image); free(input_image_rwpng.row_pointers); free(input_image_rwpng.rgba_data); return retval; }