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

Generated by: LCOV version 2.0-1