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