LCOV - code coverage report
Current view: top level - src - pngx.c (source / functions) Coverage Total Hit
Test: colopresso Coverage Report Lines: 93.0 % 257 239
Test Date: 2026-11-09 10:50:48 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit

            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              : }
        

Generated by: LCOV version 2.0-1