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