LCOV - code coverage report
Current view: top level - src - pngx.c (source / functions) Coverage Total Hit
Test: colopresso Coverage Report Lines: 91.5 % 212 194
Test Date: 2026-02-16 05:23:27 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 : int pngx_get_last_error(void) { return g_pngx_last_error; }
      25              : 
      26           80 : void pngx_set_last_error(int error_code) { g_pngx_last_error = error_code; }
      27              : 
      28           31 : bool pngx_run_quantization(const uint8_t *png_data, size_t png_size, const pngx_options_t *opts, uint8_t **out_data, size_t *out_size, int *quant_quality) {
      29              :   const char *label;
      30           31 :   uint32_t resolved_colors = 0, applied_colors = 0;
      31              :   bool success;
      32              : 
      33           31 :   if (!png_data || png_size == 0 || !opts || !out_data || !out_size) {
      34            0 :     return false;
      35              :   }
      36              : 
      37           31 :   *out_data = NULL;
      38           31 :   *out_size = 0;
      39           31 :   if (quant_quality) {
      40           31 :     *quant_quality = -1;
      41              :   }
      42              : 
      43           31 :   if (opts->lossy_type == PNGX_LOSSY_TYPE_REDUCED_RGBA32) {
      44            5 :     success = pngx_quantize_reduced_rgba32(png_data, png_size, opts, &resolved_colors, &applied_colors, out_data, out_size);
      45            5 :     if (success) {
      46            5 :       label = lossy_type_label(opts->lossy_type);
      47            5 :       colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: %s target %u colors -> %u unique", label, resolved_colors, applied_colors);
      48              :     }
      49            5 :     return success;
      50              :   }
      51              : 
      52           26 :   if (opts->lossy_type == PNGX_LOSSY_TYPE_LIMITED_RGBA4444) {
      53            3 :     return pngx_quantize_limited4444(png_data, png_size, opts, out_data, out_size);
      54              :   }
      55              : 
      56           23 :   return pngx_quantize_palette256(png_data, png_size, opts, out_data, out_size, quant_quality);
      57              : }
      58              : 
      59           37 : void pngx_fill_pngx_options(pngx_options_t *opts, const cpres_config_t *config) {
      60           37 :   uint16_t lossy_max_colors = COLOPRESSO_PNGX_DEFAULT_LOSSY_MAX_COLORS, palette256_alpha_bleed_max_distance = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_MAX_DISTANCE;
      61           37 :   uint8_t level = COLOPRESSO_PNGX_DEFAULT_LEVEL, lossy_quality_min = COLOPRESSO_PNGX_DEFAULT_LOSSY_QUALITY_MIN, lossy_quality_max = COLOPRESSO_PNGX_DEFAULT_LOSSY_QUALITY_MAX,
      62           37 :           lossy_speed = COLOPRESSO_PNGX_DEFAULT_LOSSY_SPEED, lossy_type = COLOPRESSO_PNGX_DEFAULT_LOSSY_TYPE, lossy_reduced_bits_rgb = COLOPRESSO_PNGX_DEFAULT_REDUCED_BITS_RGB,
      63           37 :           lossy_reduced_bits_alpha = COLOPRESSO_PNGX_DEFAULT_REDUCED_ALPHA_BITS, tmp, palette256_alpha_bleed_opaque_threshold = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_OPAQUE_THRESHOLD,
      64           37 :           palette256_alpha_bleed_soft_limit = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_SOFT_LIMIT;
      65           37 :   int32_t lossy_reduced_colors = COLOPRESSO_PNGX_DEFAULT_REDUCED_COLORS, clamped, thread_count = 0;
      66           37 :   int16_t palette256_tune_speed_max = PNGX_PALETTE256_TUNE_SPEED_MAX, palette256_tune_quality_min_floor = PNGX_PALETTE256_TUNE_QUALITY_MIN_FLOOR,
      67           37 :           palette256_tune_quality_max_target = PNGX_PALETTE256_TUNE_QUALITY_MAX_TARGET;
      68           37 :   bool strip_safe = COLOPRESSO_PNGX_DEFAULT_STRIP_SAFE, optimize_alpha = COLOPRESSO_PNGX_DEFAULT_OPTIMIZE_ALPHA, lossy_enable = COLOPRESSO_PNGX_DEFAULT_LOSSY_ENABLE, lossy_dither_auto = false,
      69           37 :        saliency_map_enable = COLOPRESSO_PNGX_DEFAULT_SALIENCY_MAP_ENABLE, chroma_anchor_enable = COLOPRESSO_PNGX_DEFAULT_CHROMA_ANCHOR_ENABLE,
      70           37 :        adaptive_dither_enable = COLOPRESSO_PNGX_DEFAULT_ADAPTIVE_DITHER_ENABLE, gradient_boost_enable = COLOPRESSO_PNGX_DEFAULT_GRADIENT_BOOST_ENABLE,
      71           37 :        chroma_weight_enable = COLOPRESSO_PNGX_DEFAULT_CHROMA_WEIGHT_ENABLE, postprocess_smooth_enable = COLOPRESSO_PNGX_DEFAULT_POSTPROCESS_SMOOTH_ENABLE,
      72           37 :        palette256_gradient_profile_enable = COLOPRESSO_PNGX_DEFAULT_PALETTE256_GRADIENT_PROFILE_ENABLE, palette256_alpha_bleed_enable = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_ENABLE;
      73           37 :   float lossy_dither_level = COLOPRESSO_PNGX_DEFAULT_LOSSY_DITHER_LEVEL, postprocess_smooth_importance_cutoff = COLOPRESSO_PNGX_DEFAULT_POSTPROCESS_SMOOTH_IMPORTANCE_CUTOFF,
      74           37 :         palette256_gradient_profile_dither_floor = PNGX_PALETTE256_GRADIENT_PROFILE_DITHER_FLOOR, palette256_profile_opaque_ratio_threshold = PNGX_PALETTE256_GRADIENT_PROFILE_OPAQUE_RATIO_THRESHOLD,
      75           37 :         palette256_profile_gradient_mean_max = PNGX_PALETTE256_GRADIENT_PROFILE_GRADIENT_MEAN_MAX, palette256_profile_saturation_mean_max = PNGX_PALETTE256_GRADIENT_PROFILE_SATURATION_MEAN_MAX,
      76           37 :         palette256_tune_opaque_ratio_threshold = PNGX_PALETTE256_TUNE_OPAQUE_RATIO_THRESHOLD, palette256_tune_gradient_mean_max = PNGX_PALETTE256_TUNE_GRADIENT_MEAN_MAX,
      77           37 :         palette256_tune_saturation_mean_max = PNGX_PALETTE256_TUNE_SATURATION_MEAN_MAX;
      78              : 
      79           37 :   if (!opts) {
      80            0 :     return;
      81              :   }
      82              : 
      83           37 :   if (config) {
      84           37 :     if (config->pngx_level >= 0 && config->pngx_level <= 6) {
      85           37 :       level = (uint8_t)config->pngx_level;
      86              :     }
      87           37 :     strip_safe = config->pngx_strip_safe;
      88           37 :     optimize_alpha = config->pngx_optimize_alpha;
      89           37 :     lossy_enable = config->pngx_lossy_enable;
      90           37 :     if (config->pngx_lossy_type >= CPRES_PNGX_LOSSY_TYPE_PALETTE256 && config->pngx_lossy_type <= CPRES_PNGX_LOSSY_TYPE_REDUCED_RGBA32) {
      91           37 :       lossy_type = (uint8_t)config->pngx_lossy_type;
      92              :     }
      93              : 
      94           37 :     if (config->pngx_lossy_max_colors > 0 && config->pngx_lossy_max_colors <= 256) {
      95           36 :       lossy_max_colors = (uint16_t)config->pngx_lossy_max_colors;
      96              :     }
      97           37 :     if (config->pngx_lossy_reduced_colors == COLOPRESSO_PNGX_DEFAULT_REDUCED_COLORS) {
      98           32 :       lossy_reduced_colors = COLOPRESSO_PNGX_DEFAULT_REDUCED_COLORS;
      99            5 :     } else if (config->pngx_lossy_reduced_colors >= (int32_t)COLOPRESSO_PNGX_REDUCED_COLORS_MIN) {
     100            2 :       clamped = config->pngx_lossy_reduced_colors;
     101            2 :       if (clamped > (int32_t)COLOPRESSO_PNGX_REDUCED_COLORS_MAX) {
     102            0 :         clamped = (int32_t)COLOPRESSO_PNGX_REDUCED_COLORS_MAX;
     103              :       }
     104              : 
     105            2 :       lossy_reduced_colors = clamped;
     106              :     }
     107           37 :     if (config->pngx_lossy_reduced_bits_rgb >= COLOPRESSO_PNGX_REDUCED_BITS_MIN && config->pngx_lossy_reduced_bits_rgb <= COLOPRESSO_PNGX_REDUCED_BITS_MAX) {
     108           37 :       lossy_reduced_bits_rgb = (uint8_t)config->pngx_lossy_reduced_bits_rgb;
     109              :     }
     110           37 :     if (config->pngx_lossy_reduced_alpha_bits >= COLOPRESSO_PNGX_REDUCED_BITS_MIN && config->pngx_lossy_reduced_alpha_bits <= COLOPRESSO_PNGX_REDUCED_BITS_MAX) {
     111           37 :       lossy_reduced_bits_alpha = (uint8_t)config->pngx_lossy_reduced_alpha_bits;
     112              :     }
     113           37 :     if (config->pngx_lossy_quality_min >= 0 && config->pngx_lossy_quality_min <= 100) {
     114           36 :       lossy_quality_min = (uint8_t)config->pngx_lossy_quality_min;
     115              :     }
     116           37 :     if (config->pngx_lossy_quality_max >= 0 && config->pngx_lossy_quality_max <= 100) {
     117           36 :       lossy_quality_max = (uint8_t)config->pngx_lossy_quality_max;
     118              :     }
     119           37 :     if (lossy_quality_max < lossy_quality_min) {
     120            1 :       tmp = lossy_quality_min;
     121            1 :       lossy_quality_min = lossy_quality_max;
     122            1 :       lossy_quality_max = tmp;
     123              :     }
     124           37 :     if (config->pngx_lossy_speed >= 1 && config->pngx_lossy_speed <= 10) {
     125           36 :       lossy_speed = (uint8_t)config->pngx_lossy_speed;
     126              :     }
     127           37 :     if (config->pngx_lossy_dither_level < 0.0f) {
     128            1 :       lossy_dither_auto = true;
     129           36 :     } else if (config->pngx_lossy_dither_level <= 1.0f) {
     130           35 :       lossy_dither_level = config->pngx_lossy_dither_level;
     131              :     }
     132           37 :     if (config->pngx_protected_colors && config->pngx_protected_colors_count > 0) {
     133            2 :       opts->protected_colors = config->pngx_protected_colors;
     134            2 :       opts->protected_colors_count = config->pngx_protected_colors_count;
     135              :     } else {
     136           35 :       opts->protected_colors = NULL;
     137           35 :       opts->protected_colors_count = 0;
     138              :     }
     139              : 
     140           37 :     saliency_map_enable = config->pngx_saliency_map_enable;
     141           37 :     chroma_anchor_enable = config->pngx_chroma_anchor_enable;
     142           37 :     adaptive_dither_enable = config->pngx_adaptive_dither_enable;
     143           37 :     gradient_boost_enable = config->pngx_gradient_boost_enable;
     144           37 :     chroma_weight_enable = config->pngx_chroma_weight_enable;
     145           37 :     postprocess_smooth_enable = config->pngx_postprocess_smooth_enable;
     146           37 :     postprocess_smooth_importance_cutoff = config->pngx_postprocess_smooth_importance_cutoff;
     147              : 
     148           37 :     palette256_gradient_profile_enable = config->pngx_palette256_gradient_profile_enable;
     149           37 :     if (config->pngx_palette256_gradient_dither_floor >= 0.0f && config->pngx_palette256_gradient_dither_floor <= 1.0f) {
     150           37 :       palette256_gradient_profile_dither_floor = config->pngx_palette256_gradient_dither_floor;
     151              :     }
     152           37 :     palette256_alpha_bleed_enable = config->pngx_palette256_alpha_bleed_enable;
     153              : 
     154           37 :     if (config->pngx_palette256_alpha_bleed_max_distance >= 0 && config->pngx_palette256_alpha_bleed_max_distance <= 65535) {
     155           37 :       palette256_alpha_bleed_max_distance = (uint16_t)config->pngx_palette256_alpha_bleed_max_distance;
     156              :     }
     157           37 :     if (config->pngx_palette256_alpha_bleed_opaque_threshold >= 0 && config->pngx_palette256_alpha_bleed_opaque_threshold <= 255) {
     158           37 :       palette256_alpha_bleed_opaque_threshold = (uint8_t)config->pngx_palette256_alpha_bleed_opaque_threshold;
     159              :     }
     160           37 :     if (config->pngx_palette256_alpha_bleed_soft_limit >= 0 && config->pngx_palette256_alpha_bleed_soft_limit <= 255) {
     161           37 :       palette256_alpha_bleed_soft_limit = (uint8_t)config->pngx_palette256_alpha_bleed_soft_limit;
     162              :     }
     163              : 
     164           37 :     if (config->pngx_palette256_profile_opaque_ratio_threshold >= 0.0f && config->pngx_palette256_profile_opaque_ratio_threshold <= 1.0f) {
     165           36 :       palette256_profile_opaque_ratio_threshold = config->pngx_palette256_profile_opaque_ratio_threshold;
     166              :     }
     167           37 :     if (config->pngx_palette256_profile_gradient_mean_max >= 0.0f && config->pngx_palette256_profile_gradient_mean_max <= 1.0f) {
     168           36 :       palette256_profile_gradient_mean_max = config->pngx_palette256_profile_gradient_mean_max;
     169              :     }
     170           37 :     if (config->pngx_palette256_profile_saturation_mean_max >= 0.0f && config->pngx_palette256_profile_saturation_mean_max <= 1.0f) {
     171           36 :       palette256_profile_saturation_mean_max = config->pngx_palette256_profile_saturation_mean_max;
     172              :     }
     173              : 
     174           37 :     if (config->pngx_palette256_tune_opaque_ratio_threshold >= 0.0f && config->pngx_palette256_tune_opaque_ratio_threshold <= 1.0f) {
     175           37 :       palette256_tune_opaque_ratio_threshold = config->pngx_palette256_tune_opaque_ratio_threshold;
     176              :     }
     177           37 :     if (config->pngx_palette256_tune_gradient_mean_max >= 0.0f && config->pngx_palette256_tune_gradient_mean_max <= 1.0f) {
     178           37 :       palette256_tune_gradient_mean_max = config->pngx_palette256_tune_gradient_mean_max;
     179              :     }
     180           37 :     if (config->pngx_palette256_tune_saturation_mean_max >= 0.0f && config->pngx_palette256_tune_saturation_mean_max <= 1.0f) {
     181           37 :       palette256_tune_saturation_mean_max = config->pngx_palette256_tune_saturation_mean_max;
     182              :     }
     183              : 
     184           37 :     if (config->pngx_palette256_tune_speed_max >= 1 && config->pngx_palette256_tune_speed_max <= 10) {
     185           37 :       palette256_tune_speed_max = (int16_t)config->pngx_palette256_tune_speed_max;
     186              :     }
     187           37 :     if (config->pngx_palette256_tune_quality_min_floor >= 0 && config->pngx_palette256_tune_quality_min_floor <= 100) {
     188           37 :       palette256_tune_quality_min_floor = (int16_t)config->pngx_palette256_tune_quality_min_floor;
     189              :     }
     190           37 :     if (config->pngx_palette256_tune_quality_max_target >= 0 && config->pngx_palette256_tune_quality_max_target <= 100) {
     191           37 :       palette256_tune_quality_max_target = (int16_t)config->pngx_palette256_tune_quality_max_target;
     192              :     }
     193           37 :     if (config->pngx_threads >= 0) {
     194           37 :       thread_count = (uint32_t)config->pngx_threads;
     195              :     }
     196              :   } else {
     197            0 :     opts->protected_colors = NULL;
     198            0 :     opts->protected_colors_count = 0;
     199              :   }
     200              : 
     201           37 :   lossy_quality_min = clamp_uint8_t(lossy_quality_min, 0, 100);
     202           37 :   lossy_quality_max = clamp_uint8_t(lossy_quality_max, lossy_quality_min, 100);
     203           37 :   lossy_speed = clamp_uint8_t(lossy_speed, 1, 10);
     204           37 :   lossy_max_colors = clamp_uint16_t(lossy_max_colors, 2, 256);
     205           37 :   lossy_dither_level = clamp_float(lossy_dither_level, 0.0f, 1.0f);
     206           37 :   lossy_reduced_bits_rgb = clamp_reduced_bits(lossy_reduced_bits_rgb);
     207           37 :   lossy_reduced_bits_alpha = clamp_reduced_bits(lossy_reduced_bits_alpha);
     208           37 :   if (postprocess_smooth_importance_cutoff < 0.0f) {
     209            1 :     postprocess_smooth_importance_cutoff = -1.0f;
     210              :   } else {
     211           36 :     postprocess_smooth_importance_cutoff = clamp_float(postprocess_smooth_importance_cutoff, 0.0f, 1.0f);
     212              :   }
     213              : 
     214           37 :   if (palette256_gradient_profile_dither_floor < 0.0f) {
     215            0 :     palette256_gradient_profile_dither_floor = -1.0f;
     216              :   } else {
     217           37 :     palette256_gradient_profile_dither_floor = clamp_float(palette256_gradient_profile_dither_floor, 0.0f, 1.0f);
     218              :   }
     219              : 
     220           37 :   if (palette256_profile_opaque_ratio_threshold < 0.0f) {
     221            0 :     palette256_profile_opaque_ratio_threshold = -1.0f;
     222              :   } else {
     223           37 :     palette256_profile_opaque_ratio_threshold = clamp_float(palette256_profile_opaque_ratio_threshold, 0.0f, 1.0f);
     224              :   }
     225           37 :   if (palette256_profile_gradient_mean_max < 0.0f) {
     226            0 :     palette256_profile_gradient_mean_max = -1.0f;
     227              :   } else {
     228           37 :     palette256_profile_gradient_mean_max = clamp_float(palette256_profile_gradient_mean_max, 0.0f, 1.0f);
     229              :   }
     230           37 :   if (palette256_profile_saturation_mean_max < 0.0f) {
     231            0 :     palette256_profile_saturation_mean_max = -1.0f;
     232              :   } else {
     233           37 :     palette256_profile_saturation_mean_max = clamp_float(palette256_profile_saturation_mean_max, 0.0f, 1.0f);
     234              :   }
     235              : 
     236           37 :   if (palette256_tune_opaque_ratio_threshold < 0.0f) {
     237            0 :     palette256_tune_opaque_ratio_threshold = -1.0f;
     238              :   } else {
     239           37 :     palette256_tune_opaque_ratio_threshold = clamp_float(palette256_tune_opaque_ratio_threshold, 0.0f, 1.0f);
     240              :   }
     241           37 :   if (palette256_tune_gradient_mean_max < 0.0f) {
     242            0 :     palette256_tune_gradient_mean_max = -1.0f;
     243              :   } else {
     244           37 :     palette256_tune_gradient_mean_max = clamp_float(palette256_tune_gradient_mean_max, 0.0f, 1.0f);
     245              :   }
     246           37 :   if (palette256_tune_saturation_mean_max < 0.0f) {
     247            0 :     palette256_tune_saturation_mean_max = -1.0f;
     248              :   } else {
     249           37 :     palette256_tune_saturation_mean_max = clamp_float(palette256_tune_saturation_mean_max, 0.0f, 1.0f);
     250              :   }
     251              : 
     252           37 :   if (palette256_tune_speed_max < -1) {
     253            0 :     palette256_tune_speed_max = -1;
     254              :   }
     255           37 :   if (palette256_tune_quality_min_floor < -1) {
     256            0 :     palette256_tune_quality_min_floor = -1;
     257              :   }
     258           37 :   if (palette256_tune_quality_max_target < -1) {
     259            0 :     palette256_tune_quality_max_target = -1;
     260              :   }
     261              : 
     262           37 :   opts->bridge.optimization_level = level;
     263           37 :   opts->bridge.strip_safe = strip_safe;
     264           37 :   opts->bridge.optimize_alpha = optimize_alpha;
     265           37 :   opts->lossy_enable = lossy_enable;
     266           37 :   opts->lossy_type = lossy_type;
     267           37 :   opts->lossy_max_colors = lossy_max_colors;
     268           37 :   opts->lossy_reduced_colors = lossy_reduced_colors;
     269           37 :   opts->lossy_reduced_bits_rgb = lossy_reduced_bits_rgb;
     270           37 :   opts->lossy_reduced_alpha_bits = lossy_reduced_bits_alpha;
     271           37 :   opts->lossy_quality_min = lossy_quality_min;
     272           37 :   opts->lossy_quality_max = lossy_quality_max;
     273           37 :   opts->lossy_speed = lossy_speed;
     274           37 :   opts->lossy_dither_level = lossy_dither_level;
     275           37 :   opts->lossy_dither_auto = lossy_dither_auto;
     276           37 :   opts->saliency_map_enable = saliency_map_enable;
     277           37 :   opts->chroma_anchor_enable = chroma_anchor_enable;
     278           37 :   opts->adaptive_dither_enable = adaptive_dither_enable;
     279           37 :   opts->gradient_boost_enable = gradient_boost_enable;
     280           37 :   opts->chroma_weight_enable = chroma_weight_enable;
     281           37 :   opts->postprocess_smooth_enable = postprocess_smooth_enable;
     282           37 :   opts->postprocess_smooth_importance_cutoff = postprocess_smooth_importance_cutoff;
     283           37 :   opts->palette256_gradient_profile_enable = palette256_gradient_profile_enable;
     284           37 :   opts->palette256_gradient_profile_dither_floor = palette256_gradient_profile_dither_floor;
     285           37 :   opts->palette256_alpha_bleed_enable = palette256_alpha_bleed_enable;
     286           37 :   opts->palette256_alpha_bleed_max_distance = palette256_alpha_bleed_max_distance;
     287           37 :   opts->palette256_alpha_bleed_opaque_threshold = palette256_alpha_bleed_opaque_threshold;
     288           37 :   opts->palette256_alpha_bleed_soft_limit = palette256_alpha_bleed_soft_limit;
     289           37 :   opts->palette256_profile_opaque_ratio_threshold = palette256_profile_opaque_ratio_threshold;
     290           37 :   opts->palette256_profile_gradient_mean_max = palette256_profile_gradient_mean_max;
     291           37 :   opts->palette256_profile_saturation_mean_max = palette256_profile_saturation_mean_max;
     292           37 :   opts->palette256_tune_opaque_ratio_threshold = palette256_tune_opaque_ratio_threshold;
     293           37 :   opts->palette256_tune_gradient_mean_max = palette256_tune_gradient_mean_max;
     294           37 :   opts->palette256_tune_saturation_mean_max = palette256_tune_saturation_mean_max;
     295           37 :   opts->palette256_tune_speed_max = palette256_tune_speed_max;
     296           37 :   opts->palette256_tune_quality_min_floor = palette256_tune_quality_min_floor;
     297           37 :   opts->palette256_tune_quality_max_target = palette256_tune_quality_max_target;
     298           37 :   opts->thread_count = thread_count;
     299              : }
     300              : 
     301           53 : bool pngx_run_lossless_optimization(const uint8_t *png_data, size_t png_size, const pngx_options_t *opts, uint8_t **out_data, size_t *out_size) {
     302              :   PngxBridgeLosslessOptions lossless;
     303              :   PngxBridgeResult result;
     304              : 
     305           53 :   if (!png_data || png_size == 0 || !opts || !out_data || !out_size) {
     306            0 :     return false;
     307              :   }
     308              : 
     309           53 :   *out_data = NULL;
     310           53 :   *out_size = 0;
     311              : 
     312           53 :   memset(&lossless, 0, sizeof(lossless));
     313           53 :   lossless.optimization_level = opts->bridge.optimization_level;
     314           53 :   lossless.strip_safe = opts->bridge.strip_safe;
     315           53 :   lossless.optimize_alpha = opts->bridge.optimize_alpha;
     316           53 :   result = pngx_bridge_optimize_lossless(png_data, png_size, out_data, out_size, &lossless);
     317           53 :   pngx_set_last_error((int)result);
     318              : 
     319           53 :   if (result != PNGX_BRIDGE_RESULT_SUCCESS) {
     320            0 :     return false;
     321              :   }
     322              : 
     323           53 :   return true;
     324              : }
     325              : 
     326           31 : bool pngx_should_attempt_quantization(const pngx_options_t *opts) {
     327           31 :   if (!opts) {
     328            0 :     return false;
     329              :   }
     330              : 
     331           31 :   return opts->lossy_enable;
     332              : }
     333              : 
     334           22 : bool pngx_quantization_better(size_t baseline_size, size_t candidate_size) { return candidate_size == 0 ? false : (baseline_size == 0 ? true : candidate_size < baseline_size); }
        

Generated by: LCOV version 2.0-1