LCOV - code coverage report
Current view: top level - src - colopresso.c (source / functions) Coverage Total Hit
Test: colopresso Coverage Report Lines: 94.7 % 245 232
Test Date: 2026-02-16 05:23:27 Functions: 100.0 % 15 15
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 <stdbool.h>
      13              : #include <stdio.h>
      14              : #include <stdlib.h>
      15              : #include <string.h>
      16              : 
      17              : #include <avif/avif.h>
      18              : #include <png.h>
      19              : #include <webp/encode.h>
      20              : 
      21              : #include <colopresso.h>
      22              : #include <colopresso/portable.h>
      23              : 
      24              : #include "internal/log.h"
      25              : #include "internal/png.h"
      26              : 
      27              : #include "internal/avif.h"
      28              : #include "internal/pngx.h"
      29              : #include "internal/webp.h"
      30              : 
      31          141 : extern void cpres_config_init_defaults(cpres_config_t *config) {
      32          141 :   if (!config) {
      33            1 :     return;
      34              :   }
      35              : 
      36          140 :   memset(config, 0, sizeof(*config));
      37              : 
      38          140 :   config->webp_quality = COLOPRESSO_WEBP_DEFAULT_QUALITY;
      39          140 :   config->webp_lossless = COLOPRESSO_WEBP_DEFAULT_LOSSLESS;
      40          140 :   config->webp_method = COLOPRESSO_WEBP_DEFAULT_METHOD;
      41          140 :   config->webp_target_size = COLOPRESSO_WEBP_DEFAULT_TARGET_SIZE;
      42          140 :   config->webp_target_psnr = COLOPRESSO_WEBP_DEFAULT_TARGET_PSNR;
      43          140 :   config->webp_segments = COLOPRESSO_WEBP_DEFAULT_SEGMENTS;
      44          140 :   config->webp_sns_strength = COLOPRESSO_WEBP_DEFAULT_SNS_STRENGTH;
      45          140 :   config->webp_filter_strength = COLOPRESSO_WEBP_DEFAULT_FILTER_STRENGTH;
      46          140 :   config->webp_filter_sharpness = COLOPRESSO_WEBP_DEFAULT_FILTER_SHARPNESS;
      47          140 :   config->webp_filter_type = COLOPRESSO_WEBP_DEFAULT_FILTER_TYPE;
      48          140 :   config->webp_autofilter = COLOPRESSO_WEBP_DEFAULT_AUTOFILTER;
      49          140 :   config->webp_alpha_compression = COLOPRESSO_WEBP_DEFAULT_ALPHA_COMPRESSION;
      50          140 :   config->webp_alpha_filtering = COLOPRESSO_WEBP_DEFAULT_ALPHA_FILTERING;
      51          140 :   config->webp_alpha_quality = COLOPRESSO_WEBP_DEFAULT_ALPHA_QUALITY;
      52          140 :   config->webp_pass = COLOPRESSO_WEBP_DEFAULT_PASS;
      53          140 :   config->webp_preprocessing = COLOPRESSO_WEBP_DEFAULT_PREPROCESSING;
      54          140 :   config->webp_partitions = COLOPRESSO_WEBP_DEFAULT_PARTITIONS;
      55          140 :   config->webp_partition_limit = COLOPRESSO_WEBP_DEFAULT_PARTITION_LIMIT;
      56          140 :   config->webp_emulate_jpeg_size = COLOPRESSO_WEBP_DEFAULT_EMULATE_JPEG_SIZE;
      57          140 :   config->webp_thread_level = COLOPRESSO_WEBP_DEFAULT_THREAD_LEVEL;
      58          140 :   config->webp_low_memory = COLOPRESSO_WEBP_DEFAULT_LOW_MEMORY;
      59          140 :   config->webp_near_lossless = COLOPRESSO_WEBP_DEFAULT_NEAR_LOSSLESS;
      60          140 :   config->webp_exact = COLOPRESSO_WEBP_DEFAULT_EXACT;
      61          140 :   config->webp_use_delta_palette = COLOPRESSO_WEBP_DEFAULT_USE_DELTA_PALETTE;
      62          140 :   config->webp_use_sharp_yuv = COLOPRESSO_WEBP_DEFAULT_USE_SHARP_YUV;
      63              : 
      64          140 :   config->avif_quality = COLOPRESSO_AVIF_DEFAULT_QUALITY;
      65          140 :   config->avif_alpha_quality = COLOPRESSO_AVIF_DEFAULT_ALPHA_QUALITY;
      66          140 :   config->avif_lossless = COLOPRESSO_AVIF_DEFAULT_LOSSLESS;
      67          140 :   config->avif_speed = COLOPRESSO_AVIF_DEFAULT_SPEED;
      68          140 :   config->avif_threads = COLOPRESSO_AVIF_DEFAULT_THREADS;
      69              : 
      70          140 :   config->pngx_level = COLOPRESSO_PNGX_DEFAULT_LEVEL;
      71          140 :   config->pngx_strip_safe = COLOPRESSO_PNGX_DEFAULT_STRIP_SAFE;
      72          140 :   config->pngx_optimize_alpha = COLOPRESSO_PNGX_DEFAULT_OPTIMIZE_ALPHA;
      73          140 :   config->pngx_lossy_enable = COLOPRESSO_PNGX_DEFAULT_LOSSY_ENABLE;
      74          140 :   config->pngx_lossy_type = COLOPRESSO_PNGX_DEFAULT_LOSSY_TYPE;
      75          140 :   config->pngx_lossy_max_colors = COLOPRESSO_PNGX_DEFAULT_LOSSY_MAX_COLORS;
      76          140 :   config->pngx_lossy_reduced_colors = COLOPRESSO_PNGX_DEFAULT_REDUCED_COLORS;
      77          140 :   config->pngx_lossy_reduced_bits_rgb = COLOPRESSO_PNGX_DEFAULT_REDUCED_BITS_RGB;
      78          140 :   config->pngx_lossy_reduced_alpha_bits = COLOPRESSO_PNGX_DEFAULT_REDUCED_ALPHA_BITS;
      79          140 :   config->pngx_lossy_quality_min = COLOPRESSO_PNGX_DEFAULT_LOSSY_QUALITY_MIN;
      80          140 :   config->pngx_lossy_quality_max = COLOPRESSO_PNGX_DEFAULT_LOSSY_QUALITY_MAX;
      81          140 :   config->pngx_lossy_speed = COLOPRESSO_PNGX_DEFAULT_LOSSY_SPEED;
      82          140 :   config->pngx_lossy_dither_level = COLOPRESSO_PNGX_DEFAULT_LOSSY_DITHER_LEVEL;
      83          140 :   config->pngx_saliency_map_enable = COLOPRESSO_PNGX_DEFAULT_SALIENCY_MAP_ENABLE;
      84          140 :   config->pngx_chroma_anchor_enable = COLOPRESSO_PNGX_DEFAULT_CHROMA_ANCHOR_ENABLE;
      85          140 :   config->pngx_adaptive_dither_enable = COLOPRESSO_PNGX_DEFAULT_ADAPTIVE_DITHER_ENABLE;
      86          140 :   config->pngx_gradient_boost_enable = COLOPRESSO_PNGX_DEFAULT_GRADIENT_BOOST_ENABLE;
      87          140 :   config->pngx_chroma_weight_enable = COLOPRESSO_PNGX_DEFAULT_CHROMA_WEIGHT_ENABLE;
      88          140 :   config->pngx_postprocess_smooth_enable = COLOPRESSO_PNGX_DEFAULT_POSTPROCESS_SMOOTH_ENABLE;
      89          140 :   config->pngx_postprocess_smooth_importance_cutoff = COLOPRESSO_PNGX_DEFAULT_POSTPROCESS_SMOOTH_IMPORTANCE_CUTOFF;
      90          140 :   config->pngx_palette256_gradient_profile_enable = COLOPRESSO_PNGX_DEFAULT_PALETTE256_GRADIENT_PROFILE_ENABLE;
      91          140 :   config->pngx_palette256_gradient_dither_floor = COLOPRESSO_PNGX_DEFAULT_PALETTE256_GRADIENT_DITHER_FLOOR;
      92          140 :   config->pngx_palette256_alpha_bleed_enable = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_ENABLE;
      93          140 :   config->pngx_palette256_alpha_bleed_max_distance = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_MAX_DISTANCE;
      94          140 :   config->pngx_palette256_alpha_bleed_opaque_threshold = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_OPAQUE_THRESHOLD;
      95          140 :   config->pngx_palette256_alpha_bleed_soft_limit = COLOPRESSO_PNGX_DEFAULT_PALETTE256_ALPHA_BLEED_SOFT_LIMIT;
      96          140 :   config->pngx_palette256_profile_opaque_ratio_threshold = COLOPRESSO_PNGX_DEFAULT_PALETTE256_PROFILE_OPAQUE_RATIO_THRESHOLD;
      97          140 :   config->pngx_palette256_profile_gradient_mean_max = COLOPRESSO_PNGX_DEFAULT_PALETTE256_PROFILE_GRADIENT_MEAN_MAX;
      98          140 :   config->pngx_palette256_profile_saturation_mean_max = COLOPRESSO_PNGX_DEFAULT_PALETTE256_PROFILE_SATURATION_MEAN_MAX;
      99          140 :   config->pngx_palette256_tune_opaque_ratio_threshold = COLOPRESSO_PNGX_DEFAULT_PALETTE256_TUNE_OPAQUE_RATIO_THRESHOLD;
     100          140 :   config->pngx_palette256_tune_gradient_mean_max = COLOPRESSO_PNGX_DEFAULT_PALETTE256_TUNE_GRADIENT_MEAN_MAX;
     101          140 :   config->pngx_palette256_tune_saturation_mean_max = COLOPRESSO_PNGX_DEFAULT_PALETTE256_TUNE_SATURATION_MEAN_MAX;
     102          140 :   config->pngx_palette256_tune_speed_max = COLOPRESSO_PNGX_DEFAULT_PALETTE256_TUNE_SPEED_MAX;
     103          140 :   config->pngx_palette256_tune_quality_min_floor = COLOPRESSO_PNGX_DEFAULT_PALETTE256_TUNE_QUALITY_MIN_FLOOR;
     104          140 :   config->pngx_palette256_tune_quality_max_target = COLOPRESSO_PNGX_DEFAULT_PALETTE256_TUNE_QUALITY_MAX_TARGET;
     105          140 :   config->pngx_threads = COLOPRESSO_PNGX_DEFAULT_THREADS;
     106              : }
     107              : 
     108           37 : extern cpres_error_t cpres_encode_webp_memory(const uint8_t *png_data, size_t png_size, uint8_t **webp_data, size_t *webp_size, const cpres_config_t *config) {
     109              :   uint32_t width, height;
     110              :   cpres_error_t error;
     111              :   uint8_t *rgba_data;
     112              :   size_t encoded_size;
     113              : 
     114           37 :   if (!png_data || !webp_data || !webp_size || !config) {
     115            8 :     return CPRES_ERROR_INVALID_PARAMETER;
     116              :   }
     117              : 
     118           29 :   if (png_size == 0) {
     119            2 :     return CPRES_ERROR_INVALID_PARAMETER;
     120              :   }
     121              : 
     122           27 :   if (png_size > COLOPRESSO_PNG_MAX_MEMORY_INPUT_SIZE) {
     123            2 :     return CPRES_ERROR_INVALID_PARAMETER;
     124              :   }
     125              : 
     126           25 :   *webp_data = NULL;
     127           25 :   *webp_size = 0;
     128           25 :   encoded_size = 0;
     129              : 
     130           25 :   rgba_data = NULL;
     131           25 :   error = png_decode_from_memory(png_data, png_size, &rgba_data, &width, &height);
     132           25 :   if (error != CPRES_OK) {
     133            3 :     colopresso_log(CPRES_LOG_LEVEL_ERROR, "PNG decode from memory failed: %s", cpres_error_string(error));
     134            3 :     return error;
     135              :   }
     136              : 
     137           22 :   colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNG decoded from memory - %dx%d pixels", width, height);
     138              : 
     139           22 :   error = webp_encode_rgba_to_memory(rgba_data, width, height, webp_data, &encoded_size, config);
     140           22 :   if (error == CPRES_OK) {
     141           22 :     if (*webp_data && encoded_size >= png_size) {
     142            1 :       colopresso_log(CPRES_LOG_LEVEL_WARNING, "WebP: Encoded output larger than input (%zu > %zu)", encoded_size, png_size);
     143            1 :       cpres_free(*webp_data);
     144            1 :       *webp_data = NULL;
     145            1 :       error = CPRES_ERROR_OUTPUT_NOT_SMALLER;
     146              :     }
     147           22 :     *webp_size = encoded_size;
     148              :   }
     149              : 
     150           22 :   free(rgba_data);
     151              : 
     152           22 :   return error;
     153              : }
     154              : 
     155           18 : extern cpres_error_t cpres_encode_avif_memory(const uint8_t *png_data, size_t png_size, uint8_t **avif_data, size_t *avif_size, const cpres_config_t *config) {
     156              :   uint32_t width, height;
     157              :   uint8_t *rgba_data;
     158              :   size_t encoded_size;
     159              :   cpres_error_t error;
     160              : 
     161           18 :   if (!png_data || !avif_data || !avif_size || !config) {
     162            4 :     return CPRES_ERROR_INVALID_PARAMETER;
     163              :   }
     164           14 :   if (png_size == 0) {
     165            1 :     return CPRES_ERROR_INVALID_PARAMETER;
     166              :   }
     167              : 
     168           13 :   if (png_size > COLOPRESSO_PNG_MAX_MEMORY_INPUT_SIZE) {
     169            1 :     return CPRES_ERROR_INVALID_PARAMETER;
     170              :   }
     171              : 
     172           12 :   *avif_data = NULL;
     173           12 :   *avif_size = 0;
     174           12 :   encoded_size = 0;
     175              : 
     176           12 :   rgba_data = NULL;
     177           12 :   error = png_decode_from_memory(png_data, png_size, &rgba_data, &width, &height);
     178           12 :   if (error != CPRES_OK) {
     179            0 :     colopresso_log(CPRES_LOG_LEVEL_ERROR, "PNG decode (AVIF) from memory failed: %s", cpres_error_string(error));
     180            0 :     return error;
     181              :   }
     182              : 
     183           12 :   colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNG decoded (AVIF) from memory - %dx%d pixels", width, height);
     184              : 
     185           12 :   error = avif_encode_rgba_to_memory(rgba_data, width, height, avif_data, &encoded_size, config);
     186           12 :   if (error == CPRES_OK) {
     187           12 :     if (*avif_data && encoded_size >= png_size) {
     188            1 :       colopresso_log(CPRES_LOG_LEVEL_WARNING, "AVIF: Encoded output larger than input (%zu > %zu)", encoded_size, png_size);
     189            1 :       cpres_free(*avif_data);
     190            1 :       *avif_data = NULL;
     191            1 :       error = CPRES_ERROR_OUTPUT_NOT_SMALLER;
     192              :     }
     193           12 :     *avif_size = encoded_size;
     194              :   }
     195           12 :   free(rgba_data);
     196              : 
     197           12 :   return error;
     198              : }
     199              : 
     200           36 : extern cpres_error_t cpres_encode_pngx_memory(const uint8_t *png_data, size_t png_size, uint8_t **optimized_data, size_t *optimized_size, const cpres_config_t *config) {
     201              :   pngx_options_t opts;
     202              :   uint8_t *lossless_data, *quant_data, *quant_optimized, *final_data;
     203              :   size_t lossless_size, quant_size, quant_optimized_size, final_size, candidate_size;
     204              :   bool lossless_ok, quant_ok, quant_lossless_ok, quant_is_rgba_lossy, final_is_quantized;
     205              :   int quant_quality, threads;
     206              : 
     207           36 :   if (!png_data || png_size == 0 || !optimized_data || !optimized_size || !config) {
     208            5 :     return CPRES_ERROR_INVALID_PARAMETER;
     209              :   }
     210              : 
     211           31 :   if (png_size > COLOPRESSO_PNG_MAX_MEMORY_INPUT_SIZE) {
     212            0 :     return CPRES_ERROR_INVALID_PARAMETER;
     213              :   }
     214              : 
     215           31 :   *optimized_data = NULL;
     216           31 :   *optimized_size = 0;
     217              : 
     218           31 :   lossless_data = NULL;
     219           31 :   lossless_size = 0;
     220           31 :   quant_data = NULL;
     221           31 :   quant_size = 0;
     222           31 :   quant_optimized = NULL;
     223           31 :   quant_optimized_size = 0;
     224           31 :   final_data = NULL;
     225           31 :   final_size = 0;
     226           31 :   candidate_size = 0;
     227           31 :   lossless_ok = false;
     228           31 :   quant_ok = false;
     229           31 :   quant_lossless_ok = false;
     230           31 :   quant_is_rgba_lossy = false;
     231           31 :   final_is_quantized = false;
     232           31 :   quant_quality = -1;
     233           31 :   threads = 0;
     234              : 
     235           31 :   colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: Starting optimization - input size: %zu bytes", png_size);
     236              : 
     237           31 :   pngx_fill_pngx_options(&opts, config);
     238              : 
     239           31 :   threads = config ? config->pngx_threads : 0;
     240              : #if !defined(PNGX_BRIDGE_WASM_SEPARATION)
     241           31 :   if (threads >= 0) {
     242           31 :     pngx_bridge_init_threads(threads);
     243              :   }
     244              : #else
     245              :   (void)threads;
     246              : #endif
     247              : 
     248           31 :   quant_is_rgba_lossy = (opts.lossy_type == PNGX_LOSSY_TYPE_LIMITED_RGBA4444 || opts.lossy_type == PNGX_LOSSY_TYPE_REDUCED_RGBA32);
     249              : 
     250           31 :   quant_ok = pngx_should_attempt_quantization(&opts) && pngx_run_quantization(png_data, png_size, &opts, &quant_data, &quant_size, &quant_quality);
     251           31 :   if (quant_ok) {
     252           29 :     colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: Quantization produced %zu bytes (quality=%d)", quant_size, quant_quality);
     253              :   }
     254              : 
     255           31 :   lossless_ok = pngx_run_lossless_optimization(png_data, png_size, &opts, &lossless_data, &lossless_size);
     256           31 :   if (!lossless_ok) {
     257            0 :     lossless_data = (uint8_t *)malloc(png_size);
     258            0 :     if (!lossless_data) {
     259            0 :       free(quant_data);
     260            0 :       return CPRES_ERROR_OUT_OF_MEMORY;
     261              :     }
     262            0 :     memcpy(lossless_data, png_data, png_size);
     263            0 :     lossless_size = png_size;
     264              :   }
     265           31 :   colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: Lossless optimization produced %zu bytes", lossless_size);
     266              : 
     267           31 :   final_data = lossless_data;
     268           31 :   final_size = lossless_size;
     269           31 :   final_is_quantized = false;
     270              : 
     271           31 :   if (quant_ok) {
     272           29 :     if (!quant_is_rgba_lossy) {
     273           22 :       quant_lossless_ok = pngx_run_lossless_optimization(quant_data, quant_size, &opts, &quant_optimized, &quant_optimized_size);
     274           22 :       if (quant_lossless_ok) {
     275           22 :         colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: Lossless optimization on quantized data produced %zu bytes", quant_optimized_size);
     276           22 :         free(quant_data);
     277           22 :         quant_data = NULL;
     278              :       } else {
     279            0 :         quant_optimized = quant_data;
     280            0 :         quant_optimized_size = quant_size;
     281            0 :         quant_data = NULL;
     282              :       }
     283              :     } else {
     284            7 :       quant_optimized = quant_data;
     285            7 :       quant_optimized_size = quant_size;
     286            7 :       quant_data = NULL;
     287              :     }
     288              :   }
     289              : 
     290           31 :   if (quant_ok) {
     291           29 :     candidate_size = quant_optimized_size;
     292           29 :     if (quant_is_rgba_lossy || pngx_quantization_better(lossless_size, candidate_size)) {
     293           25 :       final_data = quant_optimized;
     294           25 :       final_size = candidate_size;
     295           25 :       final_is_quantized = true;
     296           25 :       free(lossless_data);
     297           25 :       colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: Selected quantized result (%zu bytes)", final_size);
     298              :     } else {
     299            4 :       free(quant_optimized);
     300            4 :       quant_optimized = NULL;
     301            4 :       colopresso_log(CPRES_LOG_LEVEL_DEBUG, "PNGX: Selected lossless result (%zu bytes)", final_size);
     302              :     }
     303              :   }
     304              : 
     305           31 :   if (!final_data) {
     306            0 :     return CPRES_ERROR_ENCODE_FAILED;
     307              :   }
     308              : 
     309           31 :   if (final_size >= png_size) {
     310            5 :     if (!(quant_is_rgba_lossy && final_is_quantized)) {
     311            2 :       colopresso_log(CPRES_LOG_LEVEL_WARNING, "PNGX: Optimized output larger than input (%zu > %zu)", final_size, png_size);
     312            2 :       free(final_data);
     313            2 :       *optimized_data = NULL;
     314            2 :       *optimized_size = final_size;
     315            2 :       return CPRES_ERROR_OUTPUT_NOT_SMALLER;
     316              :     }
     317              : 
     318            3 :     colopresso_log(CPRES_LOG_LEVEL_WARNING, "PNGX: RGBA lossy output larger than input (%zu > %zu) but forcing write per RGBA mode", final_size, png_size);
     319              :   }
     320              : 
     321           29 :   *optimized_data = final_data;
     322           29 :   *optimized_size = final_size;
     323              : 
     324           29 :   return CPRES_OK;
     325              : }
     326              : 
     327           87 : extern void cpres_free(uint8_t *data) {
     328           87 :   if (data) {
     329           83 :     free(data);
     330              :   }
     331           87 : }
     332              : 
     333           18 : extern const char *cpres_error_string(cpres_error_t error) {
     334           18 :   switch (error) {
     335            1 :   case CPRES_OK:
     336            1 :     return "Success";
     337            4 :   case CPRES_ERROR_FILE_NOT_FOUND:
     338            4 :     return "File not found";
     339            4 :   case CPRES_ERROR_INVALID_PNG:
     340            4 :     return "Invalid PNG file";
     341            1 :   case CPRES_ERROR_INVALID_FORMAT:
     342            1 :     return "Invalid WebP file";
     343            1 :   case CPRES_ERROR_OUT_OF_MEMORY:
     344            1 :     return "Out of memory";
     345            1 :   case CPRES_ERROR_ENCODE_FAILED:
     346            1 :     return "Encoding failed";
     347            1 :   case CPRES_ERROR_DECODE_FAILED:
     348            1 :     return "Decoding failed";
     349            1 :   case CPRES_ERROR_IO:
     350            1 :     return "I/O error";
     351            1 :   case CPRES_ERROR_INVALID_PARAMETER:
     352            1 :     return "Invalid parameter";
     353            2 :   case CPRES_ERROR_OUTPUT_NOT_SMALLER:
     354            2 :     return "Output image would be larger than input";
     355            1 :   default:
     356            1 :     return "Unknown error";
     357              :   }
     358              : }
     359              : 
     360            1 : extern uint32_t cpres_get_version(void) { return (uint32_t)COLOPRESSO_VERSION; }
     361              : 
     362            1 : extern uint32_t cpres_get_libwebp_version(void) { return (uint32_t)WebPGetEncoderVersion(); }
     363              : 
     364            1 : extern uint32_t cpres_get_libpng_version(void) { return (uint32_t)png_access_version_number(); }
     365              : 
     366            1 : extern uint32_t cpres_get_libavif_version(void) { return (uint32_t)AVIF_VERSION; }
     367              : 
     368            1 : extern uint32_t cpres_get_pngx_oxipng_version(void) {
     369              : #if !defined(PNGX_BRIDGE_WASM_SEPARATION)
     370            1 :   return pngx_bridge_oxipng_version();
     371              : #else
     372              :   return 0;
     373              : #endif
     374              : }
     375              : 
     376            1 : extern uint32_t cpres_get_pngx_libimagequant_version(void) {
     377              : #if !defined(PNGX_BRIDGE_WASM_SEPARATION)
     378            1 :   return pngx_bridge_libimagequant_version();
     379              : #else
     380              :   return 0;
     381              : #endif
     382              : }
     383              : 
     384            1 : extern uint32_t cpres_get_buildtime(void) {
     385              : #ifdef COLOPRESSO_BUILDTIME
     386            1 :   return (uint32_t)COLOPRESSO_BUILDTIME;
     387              : #else
     388              :   return 0;
     389              : #endif
     390              : }
     391              : 
     392            1 : extern const char *cpres_get_compiler_version_string(void) {
     393              : #ifdef COLOPRESSO_COMPILER_VERSION_STRING
     394            1 :   return COLOPRESSO_COMPILER_VERSION_STRING;
     395              : #else
     396              :   return "unknown";
     397              : #endif
     398              : }
     399              : 
     400            1 : extern const char *cpres_get_rust_version_string(void) {
     401              : #if !defined(PNGX_BRIDGE_WASM_SEPARATION)
     402            1 :   return pngx_bridge_rust_version_string();
     403              : #else
     404              :   return "unknown";
     405              : #endif
     406              : }
        

Generated by: LCOV version 2.0-1