2017-12-29 23:09:13 +01:00
|
|
|
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
|
|
|
|
|
|
#define STBIW_ASSERT(x)
|
2016-11-13 14:43:54 +01:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
2018-12-26 16:05:14 +01:00
|
|
|
#include <zopflipng_lib.h>
|
2016-11-13 14:43:54 +01:00
|
|
|
|
2017-12-29 23:09:13 +01:00
|
|
|
#include "vendor/stb_image.h"
|
|
|
|
#include "vendor/stb_image_write.h"
|
|
|
|
#include "vendor/stb_image_resize.h"
|
2016-11-13 14:43:54 +01:00
|
|
|
#include "png.h"
|
2017-12-29 23:09:13 +01:00
|
|
|
#include "vendor/lodepng.h"
|
2016-11-13 14:43:54 +01:00
|
|
|
#include "error.h"
|
|
|
|
|
|
|
|
bool cs_png_optimize(const char *input, const char *output, cs_png_pars *options)
|
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
CZopfliPNGOptions png_options;
|
2017-06-03 12:22:23 +02:00
|
|
|
int error_code = 0;
|
2016-11-13 14:43:54 +01:00
|
|
|
|
2017-12-29 23:09:13 +01:00
|
|
|
if (options->scale_factor > 0.0 && options->scale_factor < 1.0) {
|
|
|
|
result = cs_png_resize(input, output, options->scale_factor);
|
|
|
|
if (!result) {
|
|
|
|
display_error(ERROR, 304);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
} else if (options->scale_factor != 1.0) {
|
|
|
|
display_error(ERROR, 305);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-13 14:43:54 +01:00
|
|
|
CZopfliPNGSetDefaults(&png_options);
|
|
|
|
|
|
|
|
unsigned char *orig_buffer;
|
|
|
|
size_t orig_buffer_size;
|
|
|
|
|
|
|
|
unsigned char *resultpng = NULL;
|
|
|
|
size_t resultpng_size;
|
|
|
|
|
|
|
|
png_options.num_iterations = options->iterations;
|
|
|
|
png_options.num_iterations_large = options->iterations_large;
|
|
|
|
png_options.block_split_strategy = options->block_split_strategy;
|
|
|
|
|
|
|
|
png_options.lossy_8bit = options->lossy_8;
|
|
|
|
png_options.lossy_transparent = options->transparent;
|
|
|
|
|
|
|
|
png_options.auto_filter_strategy = options->auto_filter_strategy;
|
|
|
|
|
2017-12-29 23:09:13 +01:00
|
|
|
if (lodepng_load_file(&orig_buffer, &orig_buffer_size, options->scale_factor == 1 ? input : output) != 0) {
|
2017-06-03 12:22:23 +02:00
|
|
|
error_code = 300;
|
2016-11-13 14:43:54 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-12-29 23:09:13 +01:00
|
|
|
int code = CZopfliPNGOptimize(orig_buffer,
|
|
|
|
orig_buffer_size,
|
|
|
|
&png_options,
|
|
|
|
0,
|
|
|
|
&resultpng,
|
|
|
|
&resultpng_size);
|
|
|
|
|
|
|
|
if (code != 0) {
|
2017-06-03 12:22:23 +02:00
|
|
|
error_code = 301;
|
2016-11-13 14:43:54 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lodepng_save_file(resultpng, resultpng_size, output) != 0) {
|
2017-06-03 12:22:23 +02:00
|
|
|
error_code = 302;
|
2016-11-13 14:43:54 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
free(orig_buffer);
|
|
|
|
free(resultpng);
|
2017-06-03 12:22:23 +02:00
|
|
|
if (error_code != 0) {
|
|
|
|
display_error(ERROR, error_code);
|
|
|
|
}
|
2016-11-13 14:43:54 +01:00
|
|
|
return result;
|
|
|
|
}
|
2017-12-29 23:09:13 +01:00
|
|
|
|
|
|
|
bool cs_png_resize(const char *input, const char *output, double factor)
|
|
|
|
{
|
|
|
|
unsigned char *input_pixels;
|
|
|
|
unsigned char *output_pixels;
|
|
|
|
int w, h;
|
|
|
|
int n;
|
|
|
|
int out_w, out_h;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
input_pixels = stbi_load(input, &w, &h, &n, 0);
|
|
|
|
if (input_pixels == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
out_w = (int) round(w * factor);
|
|
|
|
out_h = (int) round(h * factor);
|
|
|
|
|
|
|
|
output_pixels = (unsigned char *) malloc(out_w * out_h * n);
|
|
|
|
result = stbir_resize_uint8(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, n);
|
|
|
|
if (!result) {
|
|
|
|
free(output_pixels);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
result = stbi_write_png(output, out_w, out_h, n, output_pixels, 0);
|
|
|
|
if (!result) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|