1 /**
2 * File: WebP IO
3 *
4 * Read and write WebP images.
5 */
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif /* HAVE_CONFIG_H */
10
11
12 #include <stdio.h>
13 #include <math.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include "gd.h"
17 #include "gd_errors.h"
18 #include "gdhelpers.h"
19
20 #ifdef HAVE_LIBWEBP
21 #include "webp/decode.h"
22 #include "webp/encode.h"
23
24 #define GD_WEBP_ALLOC_STEP (4*1024)
25
26 /*
27 Function: gdImageCreateFromWebp
28
29 <gdImageCreateFromWebp> is called to load truecolor images from
30 WebP format files. Invoke <gdImageCreateFromWebp> with an
31 already opened pointer to a file containing the desired
32 image. <gdImageCreateFromWebp> returns a <gdImagePtr> to the new
33 truecolor image, or NULL if unable to load the image (most often
34 because the file is corrupt or does not contain a WebP
35 image). <gdImageCreateFromWebp> does not close the file.
36
37 You can inspect the sx and sy members of the image to determine
38 its size. The image must eventually be destroyed using
39 <gdImageDestroy>.
40
41 *The returned image is always a truecolor image.*
42
43 Variants:
44
45 <gdImageCreateFromJpegPtr> creates an image from WebP data
46 already in memory.
47
48 <gdImageCreateFromJpegCtx> reads its data via the function
49 pointers in a <gdIOCtx> structure.
50
51 Parameters:
52
53 infile - The input FILE pointer.
54
55 Returns:
56
57 A pointer to the new *truecolor* image. This will need to be
58 destroyed with <gdImageDestroy> once it is no longer needed.
59
60 On error, returns NULL.
61 */
gdImageCreateFromWebp(FILE * inFile)62 BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile)
63 {
64 gdImagePtr im;
65 gdIOCtx *in = gdNewFileCtx(inFile);
66 if (!in) {
67 return 0;
68 }
69 im = gdImageCreateFromWebpCtx(in);
70 in->gd_free(in);
71
72 return im;
73 }
74
75
76 /*
77 Function: gdImageCreateFromWebpPtr
78
79 See <gdImageCreateFromWebp>.
80
81 Parameters:
82
83 size - size of WebP data in bytes.
84 data - pointer to WebP data.
85 */
gdImageCreateFromWebpPtr(int size,void * data)86 BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data)
87 {
88 gdImagePtr im;
89 gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
90 if (!in)
91 return 0;
92 im = gdImageCreateFromWebpCtx(in);
93 in->gd_free(in);
94 return im;
95 }
96
97 /*
98 Function: gdImageCreateFromWebpCtx
99
100 See <gdImageCreateFromWebp>.
101 */
gdImageCreateFromWebpCtx(gdIOCtx * infile)102 BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx (gdIOCtx * infile)
103 {
104 int width, height;
105 uint8_t *filedata = NULL;
106 uint8_t *argb = NULL;
107 unsigned char *read, *temp;
108 size_t size = 0, n;
109 gdImagePtr im;
110 int x, y;
111 uint8_t *p;
112
113 do {
114 temp = gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
115 if (temp) {
116 filedata = temp;
117 read = temp + size;
118 } else {
119 if (filedata) {
120 gdFree(filedata);
121 }
122 gd_error("WebP decode: realloc failed");
123 return NULL;
124 }
125
126 n = gdGetBuf(read, GD_WEBP_ALLOC_STEP, infile);
127 if (n>0 && n!=EOF) {
128 size += n;
129 }
130 } while (n>0 && n!=EOF);
131
132 if (WebPGetInfo(filedata,size, &width, &height) == 0) {
133 gd_error("gd-webp cannot get webp info");
134 gdFree(temp);
135 return NULL;
136 }
137
138 im = gdImageCreateTrueColor(width, height);
139 if (!im) {
140 gdFree(temp);
141 return NULL;
142 }
143 argb = WebPDecodeARGB(filedata, size, &width, &height);
144 if (!argb) {
145 gd_error("gd-webp cannot allocate temporary buffer");
146 gdFree(temp);
147 gdImageDestroy(im);
148 return NULL;
149 }
150 for (y = 0, p = argb; y < height; y++) {
151 for (x = 0; x < width; x++) {
152 register uint8_t a = gdAlphaMax - (*(p++) >> 1);
153 register uint8_t r = *(p++);
154 register uint8_t g = *(p++);
155 register uint8_t b = *(p++);
156 im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a);
157 }
158 }
159 /* do not use gdFree here, in case gdFree/alloc is mapped to something else than libc */
160 free(argb);
161 gdFree(temp);
162 im->saveAlphaFlag = 1;
163 return im;
164 }
165
166
167 /* returns 0 on success, 1 on failure */
_gdImageWebpCtx(gdImagePtr im,gdIOCtx * outfile,int quality)168 static int _gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
169 {
170 uint8_t *argb;
171 int x, y;
172 uint8_t *p;
173 uint8_t *out;
174 size_t out_size;
175 int ret = 0;
176
177 if (im == NULL) {
178 return 1;
179 }
180
181 if (!gdImageTrueColor(im)) {
182 gd_error("Palette image not supported by webp");
183 return 1;
184 }
185
186 if (quality == -1) {
187 quality = 80;
188 }
189
190 if (overflow2(gdImageSX(im), 4)) {
191 return 1;
192 }
193
194 if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
195 return 1;
196 }
197
198 argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
199 if (!argb) {
200 return 1;
201 }
202 p = argb;
203 for (y = 0; y < gdImageSY(im); y++) {
204 for (x = 0; x < gdImageSX(im); x++) {
205 register int c;
206 register char a;
207 c = im->tpixels[y][x];
208 a = gdTrueColorGetAlpha(c);
209 if (a == 127) {
210 a = 0;
211 } else {
212 a = 255 - ((a << 1) + (a >> 6));
213 }
214 *(p++) = gdTrueColorGetRed(c);
215 *(p++) = gdTrueColorGetGreen(c);
216 *(p++) = gdTrueColorGetBlue(c);
217 *(p++) = a;
218 }
219 }
220 out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out);
221 if (out_size == 0) {
222 gd_error("gd-webp encoding failed");
223 ret = 1;
224 goto freeargb;
225 }
226 gdPutBuf(out, out_size, outfile);
227 free(out);
228
229 freeargb:
230 gdFree(argb);
231
232 return ret;
233 }
234
235
236 /*
237 Function: gdImageWebpCtx
238
239 Write the image as WebP data via a <gdIOCtx>. See <gdImageWebpEx>
240 for more details.
241
242 Parameters:
243
244 im - The image to write.
245 outfile - The output sink.
246 quality - Image quality.
247
248 Returns:
249
250 Nothing.
251 */
gdImageWebpCtx(gdImagePtr im,gdIOCtx * outfile,int quality)252 BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
253 {
254 _gdImageWebpCtx(im, outfile, quality);
255 }
256
257 /*
258 Function: gdImageWebpEx
259
260 <gdImageWebpEx> outputs the specified image to the specified file in
261 WebP format. The file must be open for writing. Under MSDOS and
262 all versions of Windows, it is important to use "wb" as opposed to
263 simply "w" as the mode when opening the file, and under Unix there
264 is no penalty for doing so. <gdImageWebpEx> does not close the file;
265 your code must do so.
266
267 If _quality_ is -1, a reasonable quality value (which should yield a
268 good general quality / size tradeoff for most situations) is used. Otherwise
269 _quality_ should be a value in the range 0-100, higher quality values
270 usually implying both higher quality and larger image sizes.
271
272 Variants:
273
274 <gdImageWebpCtx> stores the image using a <gdIOCtx> struct.
275
276 <gdImageWebpPtrEx> stores the image to RAM.
277
278 Parameters:
279
280 im - The image to save.
281 outFile - The FILE pointer to write to.
282 quality - Compression quality (0-100).
283
284 Returns:
285
286 Nothing.
287 */
gdImageWebpEx(gdImagePtr im,FILE * outFile,int quality)288 BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quality)
289 {
290 gdIOCtx *out = gdNewFileCtx(outFile);
291 if (out == NULL) {
292 return;
293 }
294 _gdImageWebpCtx(im, out, quality);
295 out->gd_free(out);
296 }
297
298 /*
299 Function: gdImageWebp
300
301 Variant of <gdImageWebpEx> which uses the default quality (-1).
302
303 Parameters:
304
305 im - The image to save
306 outFile - The FILE pointer to write to.
307
308 Returns:
309
310 Nothing.
311 */
gdImageWebp(gdImagePtr im,FILE * outFile)312 BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile)
313 {
314 gdIOCtx *out = gdNewFileCtx(outFile);
315 if (out == NULL) {
316 return;
317 }
318 _gdImageWebpCtx(im, out, -1);
319 out->gd_free(out);
320 }
321
322 /*
323 Function: gdImageWebpPtr
324
325 See <gdImageWebpEx>.
326 */
gdImageWebpPtr(gdImagePtr im,int * size)327 BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size)
328 {
329 void *rv;
330 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
331 if (out == NULL) {
332 return NULL;
333 }
334 if (_gdImageWebpCtx(im, out, -1)) {
335 rv = NULL;
336 } else {
337 rv = gdDPExtractData(out, size);
338 }
339 out->gd_free(out);
340
341 return rv;
342 }
343
344 /*
345 Function: gdImageWebpPtrEx
346
347 See <gdImageWebpEx>.
348 */
gdImageWebpPtrEx(gdImagePtr im,int * size,int quality)349 BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quality)
350 {
351 void *rv;
352 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
353 if (out == NULL) {
354 return NULL;
355 }
356 if (_gdImageWebpCtx(im, out, quality)) {
357 rv = NULL;
358 } else {
359 rv = gdDPExtractData(out, size);
360 }
361 out->gd_free(out);
362 return rv;
363 }
364
365 #else /* !HAVE_LIBWEBP */
366
_noWebpError(void)367 static void _noWebpError(void)
368 {
369 gd_error("WEBP image support has been disabled\n");
370 }
371
gdImageCreateFromWebp(FILE * inFile)372 BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile)
373 {
374 _noWebpError();
375 return NULL;
376 }
377
gdImageCreateFromWebpPtr(int size,void * data)378 BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data)
379 {
380 _noWebpError();
381 return NULL;
382 }
383
gdImageCreateFromWebpCtx(gdIOCtx * infile)384 BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx (gdIOCtx * infile)
385 {
386 _noWebpError();
387 return NULL;
388 }
389
gdImageWebpCtx(gdImagePtr im,gdIOCtx * outfile,int quality)390 BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
391 {
392 _noWebpError();
393 }
394
gdImageWebpEx(gdImagePtr im,FILE * outFile,int quality)395 BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quality)
396 {
397 _noWebpError();
398 }
399
gdImageWebp(gdImagePtr im,FILE * outFile)400 BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile)
401 {
402 _noWebpError();
403 }
404
gdImageWebpPtr(gdImagePtr im,int * size)405 BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size)
406 {
407 _noWebpError();
408 return NULL;
409 }
410
gdImageWebpPtrEx(gdImagePtr im,int * size,int quality)411 BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quality)
412 {
413 _noWebpError();
414 return NULL;
415 }
416
417 #endif /* HAVE_LIBWEBP */
418