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