Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-or-later
3 : *
4 : * This file is part of colopresso
5 : *
6 : * Copyright (C) 2025-2026 COLOPL, Inc.
7 : *
8 : * Author: Go Kudo <g-kudo@colopl.co.jp>
9 : * Developed with AI (LLM) code assistance. See `NOTICE` for details.
10 : */
11 :
12 : #include <colopresso.h>
13 :
14 : #include <stdbool.h>
15 : #include <stddef.h>
16 : #include <stdint.h>
17 : #include <string.h>
18 :
19 : #include "internal/log.h"
20 : #include "internal/pngx_common.h"
21 :
22 : static int g_pngx_last_error = 0;
23 :
24 1 : extern int pngx_get_last_error(void)
25 : {
26 1 : return g_pngx_last_error;
27 : }
28 :
29 93 : extern void pngx_set_last_error(int error_code)
30 : {
31 93 : g_pngx_last_error = error_code;
32 93 : }
33 :
34 36 : extern bool pngx_run_quantization(const uint8_t *png_data, size_t png_size,
35 : const pngx_options_t *opts, uint8_t **out_data, size_t *out_size,
36 : int *quant_quality)
37 : {
38 : const char *label;
39 36 : uint32_t resolved_colors = 0, applied_colors = 0;
40 : bool success;
41 :
42 36 : if (!png_data || png_size == 0 || !opts || !out_data || !out_size) {
43 0 : return false;
44 : }
45 :
46 36 : *out_data = NULL;
47 36 : *out_size = 0;
48 :
49 36 : if (quant_quality) {
50 36 : *quant_quality = -1;
51 : }
52 :
53 36 : if (opts->lossy_type == PNGX_LOSSY_TYPE_REDUCED_RGBA32) {
54 5 : success = pngx_quantize_reduced_rgba32(png_data, png_size, opts, &resolved_colors,
55 : &applied_colors, out_data, out_size);
56 5 : if (success) {
57 5 : label = lossy_type_label(opts->lossy_type);
58 5 : colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: %s target %u colors -> %u unique", label,
59 : resolved_colors, applied_colors);
60 : }
61 :
62 5 : return success;
63 : }
64 :
65 31 : if (opts->lossy_type == PNGX_LOSSY_TYPE_LIMITED_RGBA4444) {
66 3 : return pngx_quantize_limited4444(png_data, png_size, opts, out_data, out_size);
67 : }
68 :
69 28 : return pngx_quantize_palette256(png_data, png_size, opts, out_data, out_size, quant_quality);
70 : }
71 :
72 44 : extern void pngx_fill_pngx_options(pngx_options_t *opts, const cpres_config_t *config)
73 : {
74 44 : uint16_t lossy_max_colors = COLOPRESSO_PNGX_DEFAULT_LOSSY_MAX_COLORS,
75 44 : palette256_alpha_bleed_max_distance =
76 : COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_MAX_DISTANCE;
77 44 : uint8_t level = COLOPRESSO_PNGX_DEFAULT_LEVEL,
78 44 : lossy_quality_min = COLOPRESSO_PNGX_DEFAULT_LOSSY_QUALITY_MIN,
79 44 : lossy_quality_max = COLOPRESSO_PNGX_DEFAULT_LOSSY_QUALITY_MAX,
80 44 : lossy_speed = COLOPRESSO_PNGX_DEFAULT_LOSSY_SPEED,
81 44 : lossy_type = COLOPRESSO_PNGX_DEFAULT_LOSSY_TYPE,
82 44 : lossy_reduced_bits_rgb = COLOPRESSO_PNGX_DEFAULT_REDUCED_BITS_RGB,
83 44 : lossy_reduced_bits_alpha = COLOPRESSO_PNGX_DEFAULT_REDUCED_ALPHA_BITS, tmp,
84 44 : palette256_alpha_bleed_opaque_threshold =
85 : COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_OPAQUE_THRESHOLD,
86 44 : palette256_alpha_bleed_soft_limit =
87 : COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_SOFT_LIMIT;
88 44 : int32_t lossy_reduced_colors = COLOPRESSO_PNGX_DEFAULT_REDUCED_COLORS, clamped,
89 44 : thread_count = 0;
90 44 : int16_t palette256_tune_speed_max = PNGX_PALETTE256_TUNE_SPEED_MAX,
91 44 : palette256_tune_quality_min_floor = PNGX_PALETTE256_TUNE_QUALITY_MIN_FLOOR,
92 44 : palette256_tune_quality_max_target = PNGX_PALETTE256_TUNE_QUALITY_MAX_TARGET;
93 44 : bool strip_safe = COLOPRESSO_PNGX_DEFAULT_STRIP_SAFE,
94 44 : optimize_alpha = COLOPRESSO_PNGX_DEFAULT_OPTIMIZE_ALPHA,
95 44 : lossy_enable = COLOPRESSO_PNGX_DEFAULT_LOSSY_ENABLE, lossy_dither_auto = false,
96 44 : saliency_map_enable = COLOPRESSO_PNGX_DEFAULT_SALIENCY_MAP_ENABLE,
97 44 : chroma_anchor_enable = COLOPRESSO_PNGX_DEFAULT_CHROMA_ANCHOR_ENABLE,
98 44 : adaptive_dither_enable = COLOPRESSO_PNGX_DEFAULT_ADAPTIVE_DITHER_ENABLE,
99 44 : gradient_boost_enable = COLOPRESSO_PNGX_DEFAULT_GRADIENT_BOOST_ENABLE,
100 44 : chroma_weight_enable = COLOPRESSO_PNGX_DEFAULT_CHROMA_WEIGHT_ENABLE,
101 44 : postprocess_smooth_enable = COLOPRESSO_PNGX_DEFAULT_POSTPROCESS_SMOOTH_ENABLE,
102 44 : palette256_gradient_profile_enable =
103 : COLOPRESSO_PNGX_DEFAULT_PALETTE256_GRADIENT_PROFILE_ENABLE,
104 44 : palette256_alpha_bleed_enable = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_ENABLE;
105 44 : float lossy_dither_level = COLOPRESSO_PNGX_DEFAULT_LOSSY_DITHER_LEVEL,
106 44 : postprocess_smooth_importance_cutoff =
107 : COLOPRESSO_PNGX_DEFAULT_POSTPROCESS_SMOOTH_IMPORTANCE_CUTOFF,
108 44 : palette256_gradient_profile_dither_floor = PNGX_PALETTE256_GRADIENT_PROFILE_DITHER_FLOOR,
109 44 : palette256_profile_opaque_ratio_threshold =
110 : PNGX_PALETTE256_GRADIENT_PROFILE_OPAQUE_RATIO_THRESHOLD,
111 44 : palette256_profile_gradient_mean_max = PNGX_PALETTE256_GRADIENT_PROFILE_GRADIENT_MEAN_MAX,
112 44 : palette256_profile_saturation_mean_max =
113 : PNGX_PALETTE256_GRADIENT_PROFILE_SATURATION_MEAN_MAX,
114 44 : palette256_tune_opaque_ratio_threshold = PNGX_PALETTE256_TUNE_OPAQUE_RATIO_THRESHOLD,
115 44 : palette256_tune_gradient_mean_max = PNGX_PALETTE256_TUNE_GRADIENT_MEAN_MAX,
116 44 : palette256_tune_saturation_mean_max = PNGX_PALETTE256_TUNE_SATURATION_MEAN_MAX;
117 :
118 44 : if (!opts) {
119 0 : return;
120 : }
121 :
122 44 : if (config) {
123 44 : if (config->pngx_level >= 0 && config->pngx_level <= 6) {
124 44 : level = (uint8_t)config->pngx_level;
125 : }
126 :
127 44 : strip_safe = config->pngx_strip_safe;
128 44 : optimize_alpha = config->pngx_optimize_alpha;
129 44 : lossy_enable = config->pngx_lossy_enable;
130 :
131 44 : if (config->pngx_lossy_type >= CPRES_PNGX_LOSSY_TYPE_PALETTE256 &&
132 44 : config->pngx_lossy_type <= CPRES_PNGX_LOSSY_TYPE_REDUCED_RGBA32) {
133 44 : lossy_type = (uint8_t)config->pngx_lossy_type;
134 : }
135 :
136 44 : if (config->pngx_lossy_max_colors > 0 && config->pngx_lossy_max_colors <= 256) {
137 43 : lossy_max_colors = (uint16_t)config->pngx_lossy_max_colors;
138 : }
139 :
140 44 : if (config->pngx_lossy_reduced_colors == COLOPRESSO_PNGX_DEFAULT_REDUCED_COLORS) {
141 39 : lossy_reduced_colors = COLOPRESSO_PNGX_DEFAULT_REDUCED_COLORS;
142 5 : } else if (config->pngx_lossy_reduced_colors >=
143 : (int32_t)COLOPRESSO_PNGX_REDUCED_COLORS_MIN) {
144 2 : clamped = config->pngx_lossy_reduced_colors;
145 2 : if (clamped > (int32_t)COLOPRESSO_PNGX_REDUCED_COLORS_MAX) {
146 0 : clamped = (int32_t)COLOPRESSO_PNGX_REDUCED_COLORS_MAX;
147 : }
148 :
149 2 : lossy_reduced_colors = clamped;
150 : }
151 :
152 44 : if (config->pngx_lossy_reduced_bits_rgb >= COLOPRESSO_PNGX_REDUCED_BITS_MIN &&
153 44 : config->pngx_lossy_reduced_bits_rgb <= COLOPRESSO_PNGX_REDUCED_BITS_MAX) {
154 44 : lossy_reduced_bits_rgb = (uint8_t)config->pngx_lossy_reduced_bits_rgb;
155 : }
156 :
157 44 : if (config->pngx_lossy_reduced_alpha_bits >= COLOPRESSO_PNGX_REDUCED_BITS_MIN &&
158 44 : config->pngx_lossy_reduced_alpha_bits <= COLOPRESSO_PNGX_REDUCED_BITS_MAX) {
159 44 : lossy_reduced_bits_alpha = (uint8_t)config->pngx_lossy_reduced_alpha_bits;
160 : }
161 :
162 44 : if (config->pngx_lossy_quality_min >= 0 && config->pngx_lossy_quality_min <= 100) {
163 43 : lossy_quality_min = (uint8_t)config->pngx_lossy_quality_min;
164 : }
165 :
166 44 : if (config->pngx_lossy_quality_max >= 0 && config->pngx_lossy_quality_max <= 100) {
167 43 : lossy_quality_max = (uint8_t)config->pngx_lossy_quality_max;
168 : }
169 :
170 44 : if (lossy_quality_max < lossy_quality_min) {
171 1 : tmp = lossy_quality_min;
172 1 : lossy_quality_min = lossy_quality_max;
173 1 : lossy_quality_max = tmp;
174 : }
175 :
176 44 : if (config->pngx_lossy_speed >= 1 && config->pngx_lossy_speed <= 10) {
177 43 : lossy_speed = (uint8_t)config->pngx_lossy_speed;
178 : }
179 :
180 44 : if (config->pngx_lossy_dither_level < 0.0f) {
181 1 : lossy_dither_auto = true;
182 43 : } else if (config->pngx_lossy_dither_level <= 1.0f) {
183 42 : lossy_dither_level = config->pngx_lossy_dither_level;
184 : }
185 :
186 44 : if (config->pngx_protected_colors && config->pngx_protected_colors_count > 0) {
187 3 : opts->protected_colors = config->pngx_protected_colors;
188 3 : opts->protected_colors_count = config->pngx_protected_colors_count;
189 : } else {
190 41 : opts->protected_colors = NULL;
191 41 : opts->protected_colors_count = 0;
192 : }
193 :
194 44 : saliency_map_enable = config->pngx_saliency_map_enable;
195 44 : chroma_anchor_enable = config->pngx_chroma_anchor_enable;
196 44 : adaptive_dither_enable = config->pngx_adaptive_dither_enable;
197 44 : gradient_boost_enable = config->pngx_gradient_boost_enable;
198 44 : chroma_weight_enable = config->pngx_chroma_weight_enable;
199 44 : postprocess_smooth_enable = config->pngx_postprocess_smooth_enable;
200 44 : postprocess_smooth_importance_cutoff = config->pngx_postprocess_smooth_importance_cutoff;
201 :
202 44 : palette256_gradient_profile_enable = config->pngx_palette256_gradient_profile_enable;
203 :
204 44 : if (config->pngx_palette256_gradient_dither_floor >= 0.0f &&
205 44 : config->pngx_palette256_gradient_dither_floor <= 1.0f) {
206 44 : palette256_gradient_profile_dither_floor =
207 : config->pngx_palette256_gradient_dither_floor;
208 : }
209 :
210 44 : palette256_alpha_bleed_enable = config->pngx_palette256_alpha_bleed_enable;
211 :
212 44 : if (config->pngx_palette256_alpha_bleed_max_distance >= 0 &&
213 44 : config->pngx_palette256_alpha_bleed_max_distance <= 65535) {
214 44 : palette256_alpha_bleed_max_distance =
215 44 : (uint16_t)config->pngx_palette256_alpha_bleed_max_distance;
216 : }
217 :
218 44 : if (config->pngx_palette256_alpha_bleed_opaque_threshold >= 0 &&
219 44 : config->pngx_palette256_alpha_bleed_opaque_threshold <= 255) {
220 44 : palette256_alpha_bleed_opaque_threshold =
221 44 : (uint8_t)config->pngx_palette256_alpha_bleed_opaque_threshold;
222 : }
223 :
224 44 : if (config->pngx_palette256_alpha_bleed_soft_limit >= 0 &&
225 44 : config->pngx_palette256_alpha_bleed_soft_limit <= 255) {
226 44 : palette256_alpha_bleed_soft_limit =
227 44 : (uint8_t)config->pngx_palette256_alpha_bleed_soft_limit;
228 : }
229 :
230 44 : if (config->pngx_palette256_profile_opaque_ratio_threshold >= 0.0f &&
231 43 : config->pngx_palette256_profile_opaque_ratio_threshold <= 1.0f) {
232 43 : palette256_profile_opaque_ratio_threshold =
233 : config->pngx_palette256_profile_opaque_ratio_threshold;
234 : }
235 :
236 44 : if (config->pngx_palette256_profile_gradient_mean_max >= 0.0f &&
237 43 : config->pngx_palette256_profile_gradient_mean_max <= 1.0f) {
238 43 : palette256_profile_gradient_mean_max =
239 : config->pngx_palette256_profile_gradient_mean_max;
240 : }
241 :
242 44 : if (config->pngx_palette256_profile_saturation_mean_max >= 0.0f &&
243 43 : config->pngx_palette256_profile_saturation_mean_max <= 1.0f) {
244 43 : palette256_profile_saturation_mean_max =
245 : config->pngx_palette256_profile_saturation_mean_max;
246 : }
247 :
248 44 : if (config->pngx_palette256_tune_opaque_ratio_threshold >= 0.0f &&
249 44 : config->pngx_palette256_tune_opaque_ratio_threshold <= 1.0f) {
250 44 : palette256_tune_opaque_ratio_threshold =
251 : config->pngx_palette256_tune_opaque_ratio_threshold;
252 : }
253 :
254 44 : if (config->pngx_palette256_tune_gradient_mean_max >= 0.0f &&
255 44 : config->pngx_palette256_tune_gradient_mean_max <= 1.0f) {
256 44 : palette256_tune_gradient_mean_max = config->pngx_palette256_tune_gradient_mean_max;
257 : }
258 :
259 44 : if (config->pngx_palette256_tune_saturation_mean_max >= 0.0f &&
260 44 : config->pngx_palette256_tune_saturation_mean_max <= 1.0f) {
261 44 : palette256_tune_saturation_mean_max = config->pngx_palette256_tune_saturation_mean_max;
262 : }
263 :
264 44 : if (config->pngx_palette256_tune_speed_max >= 1 &&
265 44 : config->pngx_palette256_tune_speed_max <= 10) {
266 44 : palette256_tune_speed_max = (int16_t)config->pngx_palette256_tune_speed_max;
267 : }
268 :
269 44 : if (config->pngx_palette256_tune_quality_min_floor >= 0 &&
270 44 : config->pngx_palette256_tune_quality_min_floor <= 100) {
271 44 : palette256_tune_quality_min_floor =
272 44 : (int16_t)config->pngx_palette256_tune_quality_min_floor;
273 : }
274 :
275 44 : if (config->pngx_palette256_tune_quality_max_target >= 0 &&
276 44 : config->pngx_palette256_tune_quality_max_target <= 100) {
277 44 : palette256_tune_quality_max_target =
278 44 : (int16_t)config->pngx_palette256_tune_quality_max_target;
279 : }
280 :
281 44 : if (config->pngx_threads >= 0) {
282 88 : thread_count = (uint32_t)config->pngx_threads > cpres_get_max_thread_count()
283 1 : ? (int32_t)cpres_get_max_thread_count()
284 44 : : (int32_t)config->pngx_threads;
285 : }
286 : } else {
287 0 : opts->protected_colors = NULL;
288 0 : opts->protected_colors_count = 0;
289 : }
290 :
291 44 : lossy_quality_min = clamp_uint8_t(lossy_quality_min, 0, 100);
292 44 : lossy_quality_max = clamp_uint8_t(lossy_quality_max, lossy_quality_min, 100);
293 44 : lossy_speed = clamp_uint8_t(lossy_speed, 1, 10);
294 44 : lossy_max_colors = clamp_uint16_t(lossy_max_colors, 2, 256);
295 44 : lossy_dither_level = clamp_float(lossy_dither_level, 0.0f, 1.0f);
296 44 : lossy_reduced_bits_rgb = clamp_reduced_bits(lossy_reduced_bits_rgb);
297 44 : lossy_reduced_bits_alpha = clamp_reduced_bits(lossy_reduced_bits_alpha);
298 :
299 44 : if (!(postprocess_smooth_importance_cutoff >= 0.0f)) {
300 2 : postprocess_smooth_importance_cutoff = -1.0f;
301 : } else {
302 : postprocess_smooth_importance_cutoff =
303 42 : clamp_float(postprocess_smooth_importance_cutoff, 0.0f, 1.0f);
304 : }
305 :
306 44 : if (palette256_gradient_profile_dither_floor < 0.0f) {
307 0 : palette256_gradient_profile_dither_floor = -1.0f;
308 : } else {
309 : palette256_gradient_profile_dither_floor =
310 44 : clamp_float(palette256_gradient_profile_dither_floor, 0.0f, 1.0f);
311 : }
312 :
313 44 : if (palette256_profile_opaque_ratio_threshold < 0.0f) {
314 0 : palette256_profile_opaque_ratio_threshold = -1.0f;
315 : } else {
316 : palette256_profile_opaque_ratio_threshold =
317 44 : clamp_float(palette256_profile_opaque_ratio_threshold, 0.0f, 1.0f);
318 : }
319 :
320 44 : if (palette256_profile_gradient_mean_max < 0.0f) {
321 0 : palette256_profile_gradient_mean_max = -1.0f;
322 : } else {
323 : palette256_profile_gradient_mean_max =
324 44 : clamp_float(palette256_profile_gradient_mean_max, 0.0f, 1.0f);
325 : }
326 :
327 44 : if (palette256_profile_saturation_mean_max < 0.0f) {
328 0 : palette256_profile_saturation_mean_max = -1.0f;
329 : } else {
330 : palette256_profile_saturation_mean_max =
331 44 : clamp_float(palette256_profile_saturation_mean_max, 0.0f, 1.0f);
332 : }
333 :
334 44 : if (palette256_tune_opaque_ratio_threshold < 0.0f) {
335 0 : palette256_tune_opaque_ratio_threshold = -1.0f;
336 : } else {
337 : palette256_tune_opaque_ratio_threshold =
338 44 : clamp_float(palette256_tune_opaque_ratio_threshold, 0.0f, 1.0f);
339 : }
340 :
341 44 : if (palette256_tune_gradient_mean_max < 0.0f) {
342 0 : palette256_tune_gradient_mean_max = -1.0f;
343 : } else {
344 : palette256_tune_gradient_mean_max =
345 44 : clamp_float(palette256_tune_gradient_mean_max, 0.0f, 1.0f);
346 : }
347 :
348 44 : if (palette256_tune_saturation_mean_max < 0.0f) {
349 0 : palette256_tune_saturation_mean_max = -1.0f;
350 : } else {
351 : palette256_tune_saturation_mean_max =
352 44 : clamp_float(palette256_tune_saturation_mean_max, 0.0f, 1.0f);
353 : }
354 :
355 44 : if (palette256_tune_speed_max < -1) {
356 0 : palette256_tune_speed_max = -1;
357 : }
358 :
359 44 : if (palette256_tune_quality_min_floor < -1) {
360 0 : palette256_tune_quality_min_floor = -1;
361 : }
362 :
363 44 : if (palette256_tune_quality_max_target < -1) {
364 0 : palette256_tune_quality_max_target = -1;
365 : }
366 :
367 44 : opts->bridge.optimization_level = level;
368 44 : opts->bridge.strip_safe = strip_safe;
369 44 : opts->bridge.optimize_alpha = optimize_alpha;
370 44 : opts->lossy_enable = lossy_enable;
371 44 : opts->lossy_type = lossy_type;
372 44 : opts->lossy_max_colors = lossy_max_colors;
373 44 : opts->lossy_reduced_colors = lossy_reduced_colors;
374 44 : opts->lossy_reduced_bits_rgb = lossy_reduced_bits_rgb;
375 44 : opts->lossy_reduced_alpha_bits = lossy_reduced_bits_alpha;
376 44 : opts->lossy_quality_min = lossy_quality_min;
377 44 : opts->lossy_quality_max = lossy_quality_max;
378 44 : opts->lossy_speed = lossy_speed;
379 44 : opts->lossy_dither_level = lossy_dither_level;
380 44 : opts->lossy_dither_auto = lossy_dither_auto;
381 44 : opts->saliency_map_enable = saliency_map_enable;
382 44 : opts->chroma_anchor_enable = chroma_anchor_enable;
383 44 : opts->adaptive_dither_enable = adaptive_dither_enable;
384 44 : opts->gradient_boost_enable = gradient_boost_enable;
385 44 : opts->chroma_weight_enable = chroma_weight_enable;
386 44 : opts->postprocess_smooth_enable = postprocess_smooth_enable;
387 44 : opts->postprocess_smooth_importance_cutoff = postprocess_smooth_importance_cutoff;
388 44 : opts->palette256_gradient_profile_enable = palette256_gradient_profile_enable;
389 44 : opts->palette256_gradient_profile_dither_floor = palette256_gradient_profile_dither_floor;
390 44 : opts->palette256_alpha_bleed_enable = palette256_alpha_bleed_enable;
391 44 : opts->palette256_alpha_bleed_max_distance = palette256_alpha_bleed_max_distance;
392 44 : opts->palette256_alpha_bleed_opaque_threshold = palette256_alpha_bleed_opaque_threshold;
393 44 : opts->palette256_alpha_bleed_soft_limit = palette256_alpha_bleed_soft_limit;
394 44 : opts->palette256_profile_opaque_ratio_threshold = palette256_profile_opaque_ratio_threshold;
395 44 : opts->palette256_profile_gradient_mean_max = palette256_profile_gradient_mean_max;
396 44 : opts->palette256_profile_saturation_mean_max = palette256_profile_saturation_mean_max;
397 44 : opts->palette256_tune_opaque_ratio_threshold = palette256_tune_opaque_ratio_threshold;
398 44 : opts->palette256_tune_gradient_mean_max = palette256_tune_gradient_mean_max;
399 44 : opts->palette256_tune_saturation_mean_max = palette256_tune_saturation_mean_max;
400 44 : opts->palette256_tune_speed_max = palette256_tune_speed_max;
401 44 : opts->palette256_tune_quality_min_floor = palette256_tune_quality_min_floor;
402 44 : opts->palette256_tune_quality_max_target = palette256_tune_quality_max_target;
403 44 : opts->thread_count = thread_count;
404 : }
405 :
406 62 : extern bool pngx_run_lossless_optimization(const uint8_t *png_data, size_t png_size,
407 : const pngx_options_t *opts, uint8_t **out_data,
408 : size_t *out_size)
409 : {
410 : pngx_bridge_lossless_options_t lossless;
411 : pngx_bridge_result_t result;
412 :
413 62 : if (!png_data || png_size == 0 || !opts || !out_data || !out_size) {
414 0 : return false;
415 : }
416 :
417 62 : *out_data = NULL;
418 62 : *out_size = 0;
419 :
420 62 : memset(&lossless, 0, sizeof(lossless));
421 62 : lossless.optimization_level = opts->bridge.optimization_level;
422 62 : lossless.strip_safe = opts->bridge.strip_safe;
423 62 : lossless.optimize_alpha = opts->bridge.optimize_alpha;
424 62 : result = pngx_bridge_optimize_lossless(png_data, png_size, out_data, out_size, &lossless);
425 62 : pngx_set_last_error((int)result);
426 :
427 62 : if (result != PNGX_BRIDGE_RESULT_SUCCESS) {
428 0 : return false;
429 : }
430 :
431 62 : return true;
432 : }
433 :
434 36 : extern bool pngx_should_attempt_quantization(const pngx_options_t *opts)
435 : {
436 36 : if (!opts) {
437 0 : return false;
438 : }
439 :
440 36 : return opts->lossy_enable;
441 : }
442 :
443 26 : extern bool pngx_quantization_better(size_t baseline_size, size_t candidate_size)
444 : {
445 : return candidate_size == 0 ? false
446 26 : : (baseline_size == 0 ? true : candidate_size < baseline_size);
447 : }
|