1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6
7
8 #ifdef HAVE_LIBVPX
9 #include "webpimg.h"
10 #include "gdhelpers.h"
11
12 extern void gd_YUV420toRGBA(uint8* Y,
13 uint8* U,
14 uint8* V,
15 gdImagePtr im);
16
17 extern void gd_RGBAToYUV420(gdImagePtr im2,
18 uint8* Y,
19 uint8* U,
20 uint8* V);
21
gdWebpGetVersionString()22 const char * gdWebpGetVersionString()
23 {
24 return "not defined";
25 }
26
gdImageCreateFromWebp(FILE * inFile)27 gdImagePtr gdImageCreateFromWebp (FILE * inFile)
28 {
29 gdImagePtr im;
30 gdIOCtx *in = gdNewFileCtx(inFile);
31 im = gdImageCreateFromWebpCtx(in);
32 in->gd_free(in);
33
34 return im;
35 }
36
gdImageCreateFromWebpPtr(int size,void * data)37 gdImagePtr gdImageCreateFromWebpPtr (int size, void *data)
38 {
39 int width, height, ret;
40 unsigned char *Y = NULL;
41 unsigned char *U = NULL;
42 unsigned char *V = NULL;
43 gdImagePtr im;
44
45 ret = WebPDecode(data, size, &Y, &U, &V, &width, &height);
46 if (ret != webp_success) {
47 if (Y) free(Y);
48 if (U) free(U);
49 if (V) free(V);
50 php_gd_error("WebP decode: fail to decode input data");
51 return NULL;
52 }
53 im = gdImageCreateTrueColor(width, height);
54 if (!im) {
55 return NULL;
56 }
57 gd_YUV420toRGBA(Y, U, V, im);
58 return im;
59 }
60
61 #define GD_WEBP_ALLOC_STEP (4*1024)
62
gdImageCreateFromWebpCtx(gdIOCtx * infile)63 gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
64 {
65 int width, height, ret;
66 unsigned char *filedata = NULL;
67 unsigned char *read, *temp;
68 unsigned char *Y = NULL;
69 unsigned char *U = NULL;
70 unsigned char *V = NULL;
71 size_t size = 0, n;
72 gdImagePtr im;
73
74 do {
75 temp = gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
76 if (temp) {
77 filedata = temp;
78 read = temp + size;
79 } else {
80 if (filedata) {
81 gdFree(filedata);
82 }
83 php_gd_error("WebP decode: realloc failed");
84 return NULL;
85 }
86
87 n = gdGetBuf(read, GD_WEBP_ALLOC_STEP, infile);
88 /* differs from upstream where gdGetBuf return 0 instead of EOF */
89 if (n>0 && n!=EOF) {
90 size += n;
91 }
92 } while (n>0 && n!=EOF);
93
94 ret = WebPDecode(filedata, size, &Y, &U, &V, &width, &height);
95 gdFree(filedata);
96 if (ret != webp_success) {
97 if (Y) free(Y);
98 if (U) free(U);
99 if (V) free(V);
100 php_gd_error("WebP decode: fail to decode input data");
101 return NULL;
102 }
103 im = gdImageCreateTrueColor(width, height);
104 gd_YUV420toRGBA(Y, U, V, im);
105 return im;
106 }
107
gdImageWebpEx(gdImagePtr im,FILE * outFile,int quantization)108 void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
109 {
110 gdIOCtx *out = gdNewFileCtx(outFile);
111 gdImageWebpCtx(im, out, quantization);
112 out->gd_free(out);
113 }
114
gdImageWebp(gdImagePtr im,FILE * outFile)115 void gdImageWebp (gdImagePtr im, FILE * outFile)
116 {
117 gdIOCtx *out = gdNewFileCtx(outFile);
118 gdImageWebpCtx(im, out, -1);
119 out->gd_free(out);
120 }
121
gdImageWebpPtr(gdImagePtr im,int * size)122 void * gdImageWebpPtr (gdImagePtr im, int *size)
123 {
124 void *rv;
125 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
126 gdImageWebpCtx(im, out, -1);
127 rv = gdDPExtractData(out, size);
128 out->gd_free(out);
129
130 return rv;
131 }
132
gdImageWebpPtrEx(gdImagePtr im,int * size,int quantization)133 void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization)
134 {
135 void *rv;
136 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
137 gdImageWebpCtx(im, out, quantization);
138 rv = gdDPExtractData(out, size);
139 out->gd_free(out);
140 return rv;
141 }
142
143 /*
144 * Maps normalized QP (quality) to VP8 QP
145 */
mapQualityToVP8QP(int quality)146 int mapQualityToVP8QP(int quality) {
147 #define MIN_QUALITY 0
148 #define MAX_QUALITY 100
149 #define MIN_VP8QP 1
150 #define MAX_VP8QP 63
151 const float scale = MAX_VP8QP - MIN_VP8QP;
152 const float vp8qp =
153 scale * (MAX_QUALITY - quality) / (MAX_QUALITY - MIN_QUALITY) + MIN_VP8QP;
154 if (quality < MIN_QUALITY || quality > MAX_QUALITY) {
155 php_gd_error("Wrong quality value %d.", quality);
156 return -1;
157 }
158
159 return (int)(vp8qp + 0.5);
160 }
161
162 /* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
163 * and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
164 * (http://www.cdrom.com/pub/png/pngbook.html).
165 */
gdImageWebpCtx(gdImagePtr im,gdIOCtx * outfile,int quantization)166 void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
167 {
168 int width = im->sx;
169 int height = im->sy;
170 int colors = im->colorsTotal;
171 int *open = im->open;
172
173 int yuv_width, yuv_height, yuv_nbytes, ret;
174 int vp8_quality;
175 unsigned char *Y = NULL,
176 *U = NULL,
177 *V = NULL;
178 unsigned char *filedata = NULL;
179
180 /* Conversion to Y,U,V buffer */
181 yuv_width = (width + 1) >> 1;
182 yuv_height = (height + 1) >> 1;
183
184 if (overflow2(width, height)) {
185 return;
186 }
187 /* simplification possible, because WebP must not be larger than 16384**2 */
188 if (overflow2(width * height, 2 * sizeof(unsigned char))) {
189 return;
190 }
191
192 yuv_nbytes = width * height + 2 * yuv_width * yuv_height;
193
194 if ((Y = (unsigned char *)gdCalloc(yuv_nbytes, sizeof(unsigned char))) == NULL) {
195 php_gd_error("gd-webp error: cannot allocate Y buffer");
196 return;
197 }
198 vp8_quality = mapQualityToVP8QP(quantization);
199
200 U = Y + width * height;
201 V = U + yuv_width * yuv_height;
202 gd_RGBAToYUV420(im, Y, U, V);
203
204 /* Encode Y,U,V and write data to file */
205 ret = WebPEncode(Y, U, V, width, height, width, yuv_width, yuv_height, yuv_width,
206 vp8_quality, &filedata, &yuv_nbytes, NULL);
207 gdFree(Y);
208
209 if (ret != webp_success) {
210 if (filedata) {
211 free(filedata);
212 }
213 php_gd_error("gd-webp error: WebP Encoder failed");
214 return;
215 }
216
217 gdPutBuf (filedata, yuv_nbytes, outfile);
218 free(filedata);
219 }
220
221 #endif /* HAVE_LIBVPX */
222