xref: /PHP-5.4/ext/gd/libgd/gd_webp.c (revision 7b2a2eb3)
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