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