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 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 <errno.h>
13 : #include <stdbool.h>
14 : #include <stdint.h>
15 : #include <stdio.h>
16 : #include <stdlib.h>
17 : #include <string.h>
18 :
19 : #include <webp/encode.h>
20 :
21 : #include <colopresso.h>
22 :
23 : #include "internal/log.h"
24 : #include "internal/webp.h"
25 :
26 : static int g_last_webp_error = 0;
27 :
28 1 : int cpres_webp_get_last_error(void) { return g_last_webp_error; }
29 :
30 28 : void cpres_webp_set_last_error(int error_code) { g_last_webp_error = error_code; }
31 :
32 27 : static void apply_webp_config(WebPConfig *webp_config, const cpres_config_t *config) {
33 27 : webp_config->quality = config->webp_quality;
34 27 : webp_config->target_size = config->webp_target_size;
35 27 : webp_config->target_PSNR = config->webp_target_psnr;
36 27 : webp_config->method = config->webp_method;
37 27 : webp_config->segments = config->webp_segments;
38 27 : webp_config->sns_strength = config->webp_sns_strength;
39 27 : webp_config->filter_strength = config->webp_filter_strength;
40 27 : webp_config->filter_sharpness = config->webp_filter_sharpness;
41 27 : webp_config->filter_type = config->webp_filter_type;
42 27 : webp_config->autofilter = config->webp_autofilter;
43 27 : webp_config->alpha_compression = config->webp_alpha_compression;
44 27 : webp_config->alpha_filtering = config->webp_alpha_filtering;
45 27 : webp_config->alpha_quality = config->webp_alpha_quality;
46 27 : webp_config->pass = config->webp_pass;
47 27 : webp_config->preprocessing = config->webp_preprocessing;
48 27 : webp_config->partitions = config->webp_partitions;
49 27 : webp_config->partition_limit = config->webp_partition_limit;
50 27 : webp_config->emulate_jpeg_size = config->webp_emulate_jpeg_size;
51 27 : webp_config->thread_level = (config->webp_thread_level > 0) ? 1 : 0;
52 27 : webp_config->low_memory = config->webp_low_memory;
53 27 : webp_config->near_lossless = config->webp_near_lossless;
54 27 : webp_config->exact = config->webp_exact;
55 27 : webp_config->use_delta_palette = config->webp_use_delta_palette;
56 27 : webp_config->use_sharp_yuv = config->webp_use_sharp_yuv;
57 27 : webp_config->lossless = config->webp_lossless;
58 27 : }
59 :
60 28 : cpres_error_t cpres_webp_encode_rgba_to_memory(uint8_t *rgba_data, uint32_t width, uint32_t height, uint8_t **webp_data, size_t *webp_size, const cpres_config_t *config) {
61 : WebPConfig webp_config;
62 : WebPPicture picture;
63 : WebPMemoryWriter writer;
64 :
65 28 : if (!rgba_data || !webp_data || !webp_size || !config) {
66 0 : return CPRES_ERROR_INVALID_PARAMETER;
67 : }
68 :
69 28 : memset(&webp_config, 0, sizeof(webp_config));
70 28 : memset(&picture, 0, sizeof(picture));
71 28 : memset(&writer, 0, sizeof(writer));
72 :
73 28 : cpres_log(CPRES_LOG_LEVEL_DEBUG, "Starting WebP encoding to memory - %dx%d pixels", width, height);
74 :
75 28 : if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, config->webp_quality)) {
76 1 : return CPRES_ERROR_INVALID_PARAMETER;
77 : }
78 :
79 27 : apply_webp_config(&webp_config, config);
80 :
81 27 : if (!WebPValidateConfig(&webp_config)) {
82 0 : return CPRES_ERROR_INVALID_PARAMETER;
83 : }
84 :
85 27 : if (!WebPPictureInit(&picture)) {
86 0 : return CPRES_ERROR_OUT_OF_MEMORY;
87 : }
88 :
89 27 : picture.width = (int)width;
90 27 : picture.height = (int)height;
91 27 : picture.use_argb = 1;
92 :
93 27 : if (!WebPPictureImportRGBA(&picture, rgba_data, width * 4)) {
94 0 : WebPPictureFree(&picture);
95 0 : return CPRES_ERROR_ENCODE_FAILED;
96 : }
97 :
98 27 : WebPMemoryWriterInit(&writer);
99 27 : picture.writer = WebPMemoryWrite;
100 27 : picture.custom_ptr = &writer;
101 :
102 27 : cpres_log(CPRES_LOG_LEVEL_DEBUG, "Starting WebP encoding (memory)...");
103 :
104 27 : if (!WebPEncode(&webp_config, &picture)) {
105 0 : cpres_webp_set_last_error(picture.error_code);
106 0 : cpres_log(CPRES_LOG_LEVEL_ERROR, "WebP encoding failed - error code: %d", picture.error_code);
107 0 : WebPMemoryWriterClear(&writer);
108 0 : WebPPictureFree(&picture);
109 0 : return CPRES_ERROR_ENCODE_FAILED;
110 : }
111 27 : cpres_webp_set_last_error(0);
112 :
113 27 : cpres_log(CPRES_LOG_LEVEL_DEBUG, "WebP encoding successful - size: %zu bytes", writer.size);
114 :
115 27 : *webp_data = (uint8_t *)malloc(writer.size);
116 27 : if (!*webp_data) {
117 0 : WebPMemoryWriterClear(&writer);
118 0 : WebPPictureFree(&picture);
119 0 : return CPRES_ERROR_OUT_OF_MEMORY;
120 : }
121 :
122 27 : memcpy(*webp_data, writer.mem, writer.size);
123 27 : *webp_size = writer.size;
124 :
125 27 : WebPMemoryWriterClear(&writer);
126 27 : WebPPictureFree(&picture);
127 :
128 27 : return CPRES_OK;
129 : }
|