1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 #include "gd_errors.h"
7 #include "gdhelpers.h"
8
9 #ifdef HAVE_LIBWEBP
10 #include "webp/decode.h"
11 #include "webp/encode.h"
12
13 #define GD_WEBP_ALLOC_STEP (4*1024)
14
gdImageCreateFromWebp(FILE * inFile)15 gdImagePtr gdImageCreateFromWebp (FILE * inFile)
16 {
17 gdImagePtr im;
18 gdIOCtx *in = gdNewFileCtx(inFile);
19 if (!in)
20 return 0;
21 im = gdImageCreateFromWebpCtx(in);
22 in->gd_free(in);
23
24 return im;
25 }
26
27
gdImageCreateFromWebpPtr(int size,void * data)28 gdImagePtr gdImageCreateFromWebpPtr (int size, void *data)
29 {
30 gdImagePtr im;
31 gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
32 if (!in)
33 return 0;
34 im = gdImageCreateFromWebpCtx(in);
35 in->gd_free(in);
36 return im;
37 }
38
gdImageCreateFromWebpCtx(gdIOCtx * infile)39 gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
40 {
41 int width, height;
42 uint8_t *filedata = NULL;
43 uint8_t *argb = NULL;
44 size_t size = 0, n;
45 gdImagePtr im;
46 int x, y;
47 uint8_t *p;
48
49 do {
50 unsigned char *read, *temp;
51
52 temp = gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
53 if (temp) {
54 filedata = temp;
55 read = temp + size;
56 } else {
57 if (filedata) {
58 gdFree(filedata);
59 }
60 gd_error("WebP decode: realloc failed");
61 return NULL;
62 }
63
64 n = gdGetBuf(read, GD_WEBP_ALLOC_STEP, infile);
65 if (n>0 && n!=EOF) {
66 size += n;
67 }
68 } while (n>0 && n!=EOF);
69
70 if (WebPGetInfo(filedata,size, &width, &height) == 0) {
71 gd_error("gd-webp cannot get webp info");
72 gdFree(filedata);
73 return NULL;
74 }
75
76 im = gdImageCreateTrueColor(width, height);
77 if (!im) {
78 gdFree(filedata);
79 return NULL;
80 }
81 argb = WebPDecodeARGB(filedata, size, &width, &height);
82 if (!argb) {
83 gd_error("gd-webp cannot allocate temporary buffer");
84 gdFree(filedata);
85 gdImageDestroy(im);
86 return NULL;
87 }
88 for (y = 0, p = argb; y < height; y++) {
89 for (x = 0; x < width; x++) {
90 register uint8_t a = gdAlphaMax - (*(p++) >> 1);
91 register uint8_t r = *(p++);
92 register uint8_t g = *(p++);
93 register uint8_t b = *(p++);
94 im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a);
95 }
96 }
97 gdFree(filedata);
98 /* do not use gdFree here, in case gdFree/alloc is mapped to something else than libc */
99 free(argb);
100 im->saveAlphaFlag = 1;
101 return im;
102 }
103
gdImageWebpCtx(gdImagePtr im,gdIOCtx * outfile,int quality)104 void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
105 {
106 uint8_t *argb;
107 int x, y;
108 uint8_t *p;
109 uint8_t *out;
110 size_t out_size;
111
112 if (im == NULL) {
113 return;
114 }
115
116 if (!gdImageTrueColor(im)) {
117 gd_error("Palette image not supported by webp");
118 return;
119 }
120
121 if (quality == -1) {
122 quality = 80;
123 }
124
125 if (overflow2(gdImageSX(im), 4)) {
126 return;
127 }
128
129 if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
130 return;
131 }
132
133 argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
134 if (!argb) {
135 return;
136 }
137 p = argb;
138 for (y = 0; y < gdImageSY(im); y++) {
139 for (x = 0; x < gdImageSX(im); x++) {
140 register int c;
141 register char a;
142 c = im->tpixels[y][x];
143 a = gdTrueColorGetAlpha(c);
144 if (a == 127) {
145 a = 0;
146 } else {
147 a = 255 - ((a << 1) + (a >> 6));
148 }
149 *(p++) = gdTrueColorGetRed(c);
150 *(p++) = gdTrueColorGetGreen(c);
151 *(p++) = gdTrueColorGetBlue(c);
152 *(p++) = a;
153 }
154 }
155
156 if (quality >= gdWebpLossless) {
157 out_size = WebPEncodeLosslessRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, &out);
158 } else {
159 out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out);
160 }
161
162 if (out_size == 0) {
163 gd_error("gd-webp encoding failed");
164 goto freeargb;
165 }
166 gdPutBuf(out, out_size, outfile);
167 free(out);
168
169 freeargb:
170 gdFree(argb);
171 }
172
gdImageWebpEx(gdImagePtr im,FILE * outFile,int quality)173 void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quality)
174 {
175 gdIOCtx *out = gdNewFileCtx(outFile);
176 gdImageWebpCtx(im, out, quality);
177 out->gd_free(out);
178 }
179
gdImageWebp(gdImagePtr im,FILE * outFile)180 void gdImageWebp (gdImagePtr im, FILE * outFile)
181 {
182 gdIOCtx *out = gdNewFileCtx(outFile);
183 gdImageWebpCtx(im, out, -1);
184 out->gd_free(out);
185 }
186
gdImageWebpPtr(gdImagePtr im,int * size)187 void * gdImageWebpPtr (gdImagePtr im, int *size)
188 {
189 void *rv;
190 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
191 gdImageWebpCtx(im, out, -1);
192 rv = gdDPExtractData(out, size);
193 out->gd_free(out);
194
195 return rv;
196 }
197
gdImageWebpPtrEx(gdImagePtr im,int * size,int quality)198 void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quality)
199 {
200 void *rv;
201 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
202 gdImageWebpCtx(im, out, quality);
203 rv = gdDPExtractData(out, size);
204 out->gd_free(out);
205 return rv;
206 }
207 #endif /* HAVE_LIBWEBP */
208