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 quantization)103 void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
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 (quantization == -1) {
121 quantization = 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 out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quantization, &out);
155 if (out_size == 0) {
156 zend_error(E_ERROR, "gd-webp encoding failed");
157 goto freeargb;
158 }
159 gdPutBuf(out, out_size, outfile);
160 free(out);
161
162 freeargb:
163 gdFree(argb);
164 }
165
gdImageWebpEx(gdImagePtr im,FILE * outFile,int quantization)166 void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
167 {
168 gdIOCtx *out = gdNewFileCtx(outFile);
169 gdImageWebpCtx(im, out, quantization);
170 out->gd_free(out);
171 }
172
gdImageWebp(gdImagePtr im,FILE * outFile)173 void gdImageWebp (gdImagePtr im, FILE * outFile)
174 {
175 gdIOCtx *out = gdNewFileCtx(outFile);
176 gdImageWebpCtx(im, out, -1);
177 out->gd_free(out);
178 }
179
gdImageWebpPtr(gdImagePtr im,int * size)180 void * gdImageWebpPtr (gdImagePtr im, int *size)
181 {
182 void *rv;
183 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
184 gdImageWebpCtx(im, out, -1);
185 rv = gdDPExtractData(out, size);
186 out->gd_free(out);
187
188 return rv;
189 }
190
gdImageWebpPtrEx(gdImagePtr im,int * size,int quantization)191 void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization)
192 {
193 void *rv;
194 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
195 gdImageWebpCtx(im, out, quantization);
196 rv = gdDPExtractData(out, size);
197 out->gd_free(out);
198 return rv;
199 }
200 #endif /* HAVE_LIBWEBP */
201