Dillo v3.1.1-119-g140d9ebd
Loading...
Searching...
No Matches
webp.c
Go to the documentation of this file.
1/*
2 * File: webp.c
3 *
4 * Copyright (C) 2024 dogma
5 * Copyright (C) 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <config.h>
14#ifdef ENABLE_WEBP
15
16#include <stdlib.h> /* For abort() */
17
18#include <webp/decode.h>
19
20#include "msg.h"
21#include "image.hh"
22#include "cache.h"
23#include "dicache.h"
24
25enum prog_state {
27};
28
29typedef struct {
30 DilloImage *Image; /* Image meta data */
31 DilloUrl *url; /* Primary Key for the dicache */
32 int version; /* Secondary Key for the dicache */
33 int bgcolor; /* Parent widget background color */
34 int state;
35 int y;
36 WebPIDecoder* idec;
37 WebPDecBuffer output_buffer; /* for RGBA */
38} DilloWebp;
39
40
41/*
42 * Free up the resources for this image.
43 */
44static void Webp_free(DilloWebp *webp)
45{
46 _MSG("Webp_free: webp=%p\n", webp);
47
48 WebPFreeDecBuffer(&webp->output_buffer);
49 if (webp->idec)
50 WebPIDelete(webp->idec);
51 dFree(webp);
52}
53
54/*
55 * Finish the decoding process (and free the memory)
56 */
57static void Webp_close(DilloWebp *webp, CacheClient_t *Client)
58{
59 _MSG("Webp_close\n");
60 /* Let dicache know decoding is over */
61 a_Dicache_close(webp->url, webp->version, Client);
62 Webp_free(webp);
63}
64
65/*
66 * Op: Operation to perform.
67 * If (Op == 0)
68 * start or continue processing an image if image data exists.
69 * else
70 * terminate processing, cleanup any allocated memory,
71 * close down the decoding process.
72 *
73 * Client->CbData : pointer to previously allocated work area.
74 * This holds the current state of the image processing and is kept
75 * across calls to this routine.
76 * Client->Buf : Pointer to data start.
77 * Client->BufSize : the size of the data buffer.
78 *
79 * You have to keep track of where you are in the image data and
80 * how much has been processed.
81 *
82 * It's entirely possible that you will not see the end of the data. The
83 * user may terminate transfer via a Stop button or there may be a network
84 * failure. This means that you can't just wait for all the data to be
85 * presented before starting conversion and display.
86 */
87void a_Webp_callback(int Op, void *data)
88{
89 CacheClient_t *Client = data;
90
91 if (Op == CA_Send) {
92 uint8_t* output;
93 VP8StatusCode ret;
94
95 DilloWebp *webp = (DilloWebp *)Client->CbData;
96
97 if (webp->state == IS_init) {
98 WebPBitstreamFeatures features;
99
100 ret = WebPGetFeatures(Client->Buf, Client->BufSize, &features);
101 if (ret != VP8_STATUS_OK) {
102 MSG("features ret is %d\n", ret);
103 return;
104 }
105 if (features.has_alpha) {
106 _MSG("WEBP: Alpha!\n");
107 }
108 webp->output_buffer.colorspace = features.has_alpha ? MODE_RGBA : MODE_RGB;
109
110 a_Dicache_set_parms(webp->url, webp->version, webp->Image,
111 features.width, features.height,
112 DILLO_IMG_TYPE_RGB, 1 / 2.2);
113
114 webp->idec = WebPINewDecoder(&webp->output_buffer);
115 webp->state = IS_nextdata;
116 }
117
118 ret = WebPIUpdate(webp->idec, Client->Buf, Client->BufSize);
119 /* SUSPENDED is a success state that means you don't have the entire file yet */
120 if (ret == VP8_STATUS_SUSPENDED || ret == VP8_STATUS_OK) {
121 /* last_y seems 1-based, which would be kind of crazy, but I would expect
122 * crazy idiocy from google.
123 */
124 int last_y, width, height, stride;
125
126 _MSG("webp completed. status: %s\n", ret == VP8_STATUS_SUSPENDED ? "suspended" : "ok (done)");
127 output = WebPIDecGetRGB(webp->idec, &last_y, &width, &height, &stride);
128 if (!output) {
129 _MSG("webp decoding no output\n");
130 } else {
131 unsigned char *line;
132 int row = webp->y;
133
134 if (webp->output_buffer.colorspace == MODE_RGBA)
135 line = dNew(unsigned char, width * 3);
136 else
137 line = output + row * stride;
138
139 for (; row < last_y; row++) {
140
141 if (webp->output_buffer.colorspace == MODE_RGBA) {
142 int j;
143
144 uint_t bg_blue = (webp->bgcolor) & 0xFF;
145 uint_t bg_green = (webp->bgcolor>>8) & 0xFF;
146 uint_t bg_red = (webp->bgcolor>>16) & 0xFF;
147 for (j = 0; j < width; j++) {
148 uchar_t alpha = output[row * stride + 4 * j + 3];
149 uchar_t r = output[row * stride + 4 * j];
150 uchar_t g = output[row * stride + 4 * j + 1];
151 uchar_t b = output[row * stride + 4 * j + 2];
152 line[3 * j] = (r * alpha + (bg_red * (0xFF - alpha))) / 0xFF;
153 line[3 * j + 1] = (g * alpha + (bg_green * (0xFF - alpha))) / 0xFF;
154 line[3 * j + 2] = (b * alpha + (bg_blue * (0xFF - alpha))) / 0xFF;
155 }
156 } else {
157 line = output + row * stride;
158 }
159 a_Dicache_write(webp->url, webp->version, line, row);
160 }
161 webp->y = last_y;
162
163 if (webp->output_buffer.colorspace == MODE_RGBA)
164 dFree(line);
165 }
166 } else {
167 MSG("webp WebPIUpdate failed with %d\n", ret);
168 }
169 } else if (Op == CA_Close) {
170 Webp_close(Client->CbData, Client);
171 } else if (Op == CA_Abort) {
172 Webp_free(data);
173 }
174}
175
176const char *a_Webp_version(char *buf, int n)
177{
178 /* Return the decoder's version number, packed in
179 * hexadecimal using 8bits for each of major/minor/revision.
180 * E.g: v2.5.7 is 0x020507. */
181 int ver = WebPGetDecoderVersion();
182
183 int major = (ver >> 16) & 0xff;
184 int minor = (ver >> 8) & 0xff;
185 int rev = (ver >> 0) & 0xff;
186
187 int k = snprintf(buf, n, "%d.%d.%d", major, minor, rev);
188 if (k >= n)
189 return "?";
190 return buf;
191}
192
193/*
194 * Create the image state data that must be kept between calls
195 */
196void *a_Webp_new(DilloImage *Image, DilloUrl *url, int version)
197{
198 DilloWebp *webp = dNew0(DilloWebp, 1);
199 _MSG("a_Webp_new: webp=%p\n", webp);
200
201 webp->Image = Image;
202 webp->url = url;
203 webp->version = version;
204
205 webp->bgcolor = Image->bg_color;
206 webp->state = IS_init;
207 webp->y = 0;
208 webp->idec = NULL;
209 WebPInitDecBuffer(&webp->output_buffer);
210
211 return webp;
212}
213
214#else /* ENABLE_WEBP */
215
216void *a_Webp_new() { return 0; }
217void a_Webp_callback() { return; }
218const char *a_Webp_version(char *buf, int n) { return 0; }
219
220#endif /* ENABLE_WEBP */
#define _MSG(...)
Definition bookmarks.c:45
#define MSG(...)
Definition bookmarks.c:46
#define CA_Send
Definition cache.h:15
#define CA_Abort
Definition cache.h:17
#define CA_Close
Definition cache.h:16
unsigned char uchar_t
Definition d_size.h:17
unsigned int uint_t
Definition d_size.h:20
void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, uint_t width, uint_t height, DilloImgType type, double gamma)
Set image's width, height & type.
Definition dicache.c:248
void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client)
Implement the close method of the decoding process.
Definition dicache.c:349
void a_Dicache_write(DilloUrl *url, int version, const uchar_t *buf, uint_t Y)
Implement the write method (Write a scan line into the Dicache entry) buf: row buffer Y : row number.
Definition dicache.c:329
void dFree(void *mem)
Definition dlib.c:68
#define dNew0(type, count)
Definition dlib.h:51
#define dNew(type, count)
Definition dlib.h:49
prog_state
Definition png.c:33
@ IS_finished
Definition png.c:34
@ IS_init
Definition png.c:34
@ IS_nextdata
Definition png.c:34
@ DILLO_IMG_TYPE_RGB
Definition image.hh:44
Data structure for cache clients.
Definition cache.h:48
void * CbData
Client function data.
Definition cache.h:55
uint_t BufSize
Valid size of cache-data.
Definition cache.h:53
void * Buf
Pointer to cache-data.
Definition cache.h:52
Definition url.h:88
int32_t bg_color
Background color.
Definition image.hh:68
const char * a_Webp_version(char *buf, int n)
Definition webp.c:218
void a_Webp_callback()
Definition webp.c:217
void * a_Webp_new()
Definition webp.c:216