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
gdImageCreateFromWebpCtx(gdIOCtx * infile)61 gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
62 {
63 int width, height, ret;
64 unsigned char *filedata;
65 unsigned char dummy[1024];
66 unsigned char *Y = NULL;
67 unsigned char *U = NULL;
68 unsigned char *V = NULL;
69 size_t size = 0, n;
70 gdImagePtr im;
71
72 do {
73 n = gdGetBuf(dummy, 1024, infile);
74 size += n;
75 } while (n != EOF);
76
77 filedata = gdMalloc(size);
78 if (!filedata) {
79 php_gd_error("WebP decode: alloc failed");
80 return NULL;
81 }
82 gdGetBuf(filedata, size, infile);
83 ret = WebPDecode(filedata, size, &Y, &U, &V, &width, &height);
84 gdFree(filedata);
85 if (ret != webp_success) {
86 if (Y) free(Y);
87 if (U) free(U);
88 if (V) free(V);
89 php_gd_error("WebP decode: fail to decode input data");
90 return NULL;
91 }
92 im = gdImageCreateTrueColor(width, height);
93 gd_YUV420toRGBA(Y, U, V, im);
94 return im;
95 }
96
gdImageWebpEx(gdImagePtr im,FILE * outFile,int quantization)97 void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
98 {
99 gdIOCtx *out = gdNewFileCtx(outFile);
100 gdImageWebpCtx(im, out, quantization);
101 out->gd_free(out);
102 }
103
gdImageWebp(gdImagePtr im,FILE * outFile)104 void gdImageWebp (gdImagePtr im, FILE * outFile)
105 {
106 gdIOCtx *out = gdNewFileCtx(outFile);
107 gdImageWebpCtx(im, out, -1);
108 out->gd_free(out);
109 }
110
gdImageWebpPtr(gdImagePtr im,int * size)111 void * gdImageWebpPtr (gdImagePtr im, int *size)
112 {
113 void *rv;
114 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
115 gdImageWebpCtx(im, out, -1);
116 rv = gdDPExtractData(out, size);
117 out->gd_free(out);
118
119 return rv;
120 }
121
gdImageWebpPtrEx(gdImagePtr im,int * size,int quantization)122 void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization)
123 {
124 void *rv;
125 gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
126 gdImageWebpCtx(im, out, quantization);
127 rv = gdDPExtractData(out, size);
128 out->gd_free(out);
129 return rv;
130 }
131
132 /*
133 * Maps normalized QP (quality) to VP8 QP
134 */
mapQualityToVP8QP(int quality)135 int mapQualityToVP8QP(int quality) {
136 #define MIN_QUALITY 0
137 #define MAX_QUALITY 100
138 #define MIN_VP8QP 1
139 #define MAX_VP8QP 63
140 const float scale = MAX_VP8QP - MIN_VP8QP;
141 const float vp8qp =
142 scale * (MAX_QUALITY - quality) / (MAX_QUALITY - MIN_QUALITY) + MIN_VP8QP;
143 if (quality < MIN_QUALITY || quality > MAX_QUALITY) {
144 php_gd_error("Wrong quality value %d.", quality);
145 return -1;
146 }
147
148 return (int)(vp8qp + 0.5);
149 }
150
151 /* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
152 * and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
153 * (http://www.cdrom.com/pub/png/pngbook.html).
154 */
gdImageWebpCtx(gdImagePtr im,gdIOCtx * outfile,int quantization)155 void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
156 {
157 int width = im->sx;
158 int height = im->sy;
159 int colors = im->colorsTotal;
160 int *open = im->open;
161
162 int yuv_width, yuv_height, yuv_nbytes, ret;
163 int vp8_quality;
164 unsigned char *Y = NULL,
165 *U = NULL,
166 *V = NULL;
167 unsigned char *filedata = NULL;
168
169 /* Conversion to Y,U,V buffer */
170 yuv_width = (width + 1) >> 1;
171 yuv_height = (height + 1) >> 1;
172 yuv_nbytes = width * height + 2 * yuv_width * yuv_height;
173
174 if ((Y = (unsigned char *)gdCalloc(yuv_nbytes, sizeof(unsigned char))) == NULL) {
175 php_gd_error("gd-webp error: cannot allocate Y buffer");
176 return;
177 }
178 vp8_quality = mapQualityToVP8QP(quantization);
179
180 U = Y + width * height;
181 V = U + yuv_width * yuv_height;
182 gd_RGBAToYUV420(im, Y, U, V);
183
184 /* Encode Y,U,V and write data to file */
185 ret = WebPEncode(Y, U, V, width, height, width, yuv_width, yuv_height, yuv_width,
186 vp8_quality, &filedata, &yuv_nbytes, NULL);
187 gdFree(Y);
188
189 if (ret != webp_success) {
190 if (filedata) {
191 free(filedata);
192 }
193 php_gd_error("gd-webp error: WebP Encoder failed");
194 return;
195 }
196
197 gdPutBuf (filedata, yuv_nbytes, outfile);
198 free(filedata);
199 }
200
201 #endif /* HAVE_LIBVPX */
202