xref: /PHP-8.3/ext/gd/libgd/gd_gd.c (revision afdaa911)
1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 
7 #define TRUE 1
8 #define FALSE 0
9 
10 /* Exported functions: */
11 extern void gdImageGd (gdImagePtr im, FILE * out);
12 
13 
14 /* Use this for commenting out debug-print statements. */
15 /* Just use the first '#define' to allow all the prints... */
16 /*#define GD2_DBG(s) (s) */
17 #define GD2_DBG(s)
18 
19 /* */
20 /* Shared code to read color tables from gd file. */
21 /* */
_gdGetColors(gdIOCtx * in,gdImagePtr im,int gd2xFlag)22 int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag)
23 {
24 	int i;
25 	if (gd2xFlag) {
26 		int trueColorFlag;
27 		if (!gdGetByte(&trueColorFlag, in)) {
28 			goto fail1;
29 		}
30 		/* 2.0.12: detect bad truecolor .gd files created by pre-2.0.12.
31 		 * Beginning in 2.0.12 truecolor is indicated by the initial 2-byte
32 		 * signature.
33 		 */
34 		if (trueColorFlag != im->trueColor) {
35 			goto fail1;
36 		}
37 		/* This should have been a word all along */
38 		if (!im->trueColor) {
39 			if (!gdGetWord(&im->colorsTotal, in)) {
40 				goto fail1;
41 			}
42 			if (im->colorsTotal > gdMaxColors) {
43 				goto fail1;
44 			}
45 		}
46 		/* Int to accommodate truecolor single-color transparency */
47 		if (!gdGetInt(&im->transparent, in)) {
48 			goto fail1;
49 		}
50 	} else {
51 		if (!gdGetByte(&im->colorsTotal, in)) {
52 			goto fail1;
53 		}
54 		if (!gdGetWord(&im->transparent, in)) {
55 			goto fail1;
56 		}
57 		if (im->transparent == 257) {
58 			im->transparent = (-1);
59 		}
60 	}
61 
62 	GD2_DBG(printf("Palette had %d colours (T=%d)\n", im->colorsTotal, im->transparent));
63 
64 	if (im->trueColor) {
65 		return TRUE;
66 	}
67 
68 	for (i = 0; i < gdMaxColors; i++) {
69 		if (!gdGetByte(&im->red[i], in)) {
70 			goto fail1;
71 		}
72 		if (!gdGetByte(&im->green[i], in)) {
73 			goto fail1;
74 		}
75 		if (!gdGetByte(&im->blue[i], in)) {
76 			goto fail1;
77 		}
78 		if (gd2xFlag) {
79 			if (!gdGetByte(&im->alpha[i], in)) {
80 				goto fail1;
81 			}
82 		}
83 	}
84 
85 	for (i = 0; i < im->colorsTotal; i++) {
86 		im->open[i] = 0;
87 	}
88 
89 	return TRUE;
90 fail1:
91 	return FALSE;
92 }
93 
94 /* */
95 /* Use the common basic header info to make the image object. */
96 /* */
_gdCreateFromFile(gdIOCtx * in,int * sx,int * sy)97 static gdImagePtr _gdCreateFromFile (gdIOCtx * in, int *sx, int *sy)
98 {
99 	gdImagePtr im;
100 	int gd2xFlag = 0;
101 	int trueColorFlag = 0;
102 
103 	if (!gdGetWord(sx, in)) {
104 		goto fail1;
105 	}
106 	if (*sx == 65535 || *sx == 65534) {
107 		/* This is a gd 2.0 .gd file */
108 		gd2xFlag = 1;
109 		/* 2.0.12: 65534 signals a truecolor .gd file. There is a slight redundancy here but we can live with it. */
110 		if (*sx == 65534) {
111 			trueColorFlag = 1;
112 		}
113 		if (!gdGetWord(sx, in)) {
114 			goto fail1;
115 		}
116 	}
117 	if (!gdGetWord(sy, in)) {
118 		goto fail1;
119 	}
120 
121 	GD2_DBG(printf("Image is %dx%d\n", *sx, *sy));
122 
123 	if (trueColorFlag) {
124 		im = gdImageCreateTrueColor(*sx, *sy);
125 	} else {
126 		im = gdImageCreate(*sx, *sy);
127 	}
128 	if(!im) {
129 		goto fail1;
130 	}
131 	if (!_gdGetColors(in, im, gd2xFlag)) {
132 		goto fail2;
133 	}
134 
135 	return im;
136 fail2:
137 	gdImageDestroy(im);
138 fail1:
139 	return 0;
140 }
141 
gdImageCreateFromGd(FILE * inFile)142 gdImagePtr gdImageCreateFromGd (FILE * inFile)
143 {
144 	gdImagePtr im;
145 	gdIOCtx *in;
146 
147 	in = gdNewFileCtx(inFile);
148 	im = gdImageCreateFromGdCtx(in);
149 
150 	in->gd_free(in);
151 
152 	return im;
153 }
154 
gdImageCreateFromGdPtr(int size,void * data)155 gdImagePtr gdImageCreateFromGdPtr (int size, void *data)
156 {
157 	gdImagePtr im;
158 	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
159 	im = gdImageCreateFromGdCtx(in);
160 	in->gd_free(in);
161 
162 	return im;
163 }
164 
gdImageCreateFromGdCtx(gdIOCtxPtr in)165 gdImagePtr gdImageCreateFromGdCtx (gdIOCtxPtr in)
166 {
167 	int sx, sy;
168 	int x, y;
169 	gdImagePtr im;
170 
171 	/* Read the header */
172 	im = _gdCreateFromFile(in, &sx, &sy);
173 
174 	if (im == NULL) {
175 		goto fail1;
176 	}
177 
178 	/* Then the data... */
179 	/* 2.0.12: support truecolor properly in .gd as well as in .gd2. Problem reported by Andreas Pfaller. */
180 	if (im->trueColor) {
181 		for (y = 0; y < sy; y++) {
182 			for (x = 0; x < sx; x++) {
183 				int pix;
184 				if (!gdGetInt(&pix, in)) {
185 					goto fail2;
186 				}
187 				im->tpixels[y][x] = pix;
188 			}
189 		}
190 	} else {
191 		for (y = 0; y < sy; y++) {
192 			for (x = 0; x < sx; x++) {
193 				int ch;
194 				ch = gdGetC(in);
195 				if (ch == EOF) {
196 					goto fail2;
197 				}
198 				/* ROW-MAJOR IN GD 1.3 */
199 				im->pixels[y][x] = ch;
200 			}
201 		}
202 	}
203 
204 	return im;
205 
206 fail2:
207 	gdImageDestroy (im);
208 fail1:
209 	return 0;
210 }
211 
_gdPutColors(gdImagePtr im,gdIOCtx * out)212 void _gdPutColors (gdImagePtr im, gdIOCtx * out)
213 {
214 	int i;
215 
216 	gdPutC(im->trueColor, out);
217 	if (!im->trueColor) {
218 		gdPutWord(im->colorsTotal, out);
219 	}
220 	gdPutInt(im->transparent, out);
221 	if (!im->trueColor) {
222 		for (i = 0; i < gdMaxColors; i++) {
223 			gdPutC((unsigned char) im->red[i], out);
224 			gdPutC((unsigned char) im->green[i], out);
225 			gdPutC((unsigned char) im->blue[i], out);
226 			gdPutC((unsigned char) im->alpha[i], out);
227 		}
228 	}
229 }
230 
_gdPutHeader(gdImagePtr im,gdIOCtx * out)231 static void _gdPutHeader (gdImagePtr im, gdIOCtx * out)
232 {
233 	/* 65535 indicates this is a gd 2.x .gd file.
234 	 * 2.0.12: 65534 indicates truecolor.
235 	 */
236 	if (im->trueColor) {
237 		gdPutWord(65534, out);
238 	} else {
239 		gdPutWord(65535, out);
240 	}
241 	gdPutWord(im->sx, out);
242 	gdPutWord(im->sy, out);
243 
244 	_gdPutColors(im, out);
245 }
246 
_gdImageGd(gdImagePtr im,gdIOCtx * out)247 static void _gdImageGd (gdImagePtr im, gdIOCtx * out)
248 {
249 	int x, y;
250 
251 	_gdPutHeader(im, out);
252 
253 	for (y = 0; y < im->sy; y++) {
254 		for (x = 0; x < im->sx; x++) {
255 			/* ROW-MAJOR IN GD 1.3 */
256 			if (im->trueColor) {
257 				gdPutInt(im->tpixels[y][x], out);
258 			} else {
259 				gdPutC((unsigned char) im->pixels[y][x], out);
260 			}
261 		}
262 	}
263 }
264 
gdImageGd(gdImagePtr im,FILE * outFile)265 void gdImageGd (gdImagePtr im, FILE * outFile)
266 {
267 	gdIOCtx *out = gdNewFileCtx(outFile);
268 	_gdImageGd(im, out);
269 	out->gd_free(out);
270 }
271 
gdImageGdPtr(gdImagePtr im,int * size)272 void *gdImageGdPtr (gdImagePtr im, int *size)
273 {
274 	void *rv;
275 	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
276 	_gdImageGd(im, out);
277 	rv = gdDPExtractData(out, size);
278 	out->gd_free(out);
279 	return rv;
280 }
281