xref: /PHP-8.4/ext/gd/libgd/gd.c (revision 4d7d01d1)
1 
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 #include "gdhelpers.h"
7 #include "gd_errors.h"
8 
9 #include "php.h"
10 
11 #ifdef _OSD_POSIX		/* BS2000 uses the EBCDIC char set instead of ASCII */
12 #define CHARSET_EBCDIC
13 #define __attribute__(any)	/*nothing */
14 #endif
15 /*_OSD_POSIX*/
16 
17 #ifndef CHARSET_EBCDIC
18 #define ASC(ch)  ch
19 #else /*CHARSET_EBCDIC */
20 #define ASC(ch) gd_toascii[(unsigned char)ch]
21 static const unsigned char gd_toascii[256] =
22 {
23 /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
24   0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,	/*................ */
25 /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
26   0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f,	/*................ */
27 /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
28   0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,	/*................ */
29 /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
30   0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,	/*................ */
31 /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
32   0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,	/* .........`.<(+| */
33 /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
34   0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f,	/*&.........!$*);. */
35 /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
36   0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
37 /*-/........^,%_>?*/
38 /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
39   0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,	/*..........:#@'=" */
40 /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
41   0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1,	/*.abcdefghi...... */
42 /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
43   0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4,	/*.jklmnopqr...... */
44 /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
45   0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae,	/*..stuvwxyz...... */
46 /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
47   0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7,	/*...........[\].. */
48 /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
49   0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5,	/*.ABCDEFGHI...... */
50 /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
51   0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff,	/*.JKLMNOPQR...... */
52 /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
53   0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5,	/*..STUVWXYZ...... */
54 /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
55   0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e	/*0123456789.{.}.~ */
56 };
57 #endif /*CHARSET_EBCDIC */
58 
59 /* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */
60 #define floor_cast(exp) ((long) exp)
61 
62 extern int gdCosT[];
63 extern int gdSinT[];
64 
65 /**
66  * Group: Error Handling
67  */
68 
gd_stderr_error(int priority,const char * format,va_list args)69 void gd_stderr_error(int priority, const char *format, va_list args)
70 {
71 	switch (priority) {
72 	case GD_ERROR:
73 		fputs("GD Error: ", stderr);
74 		break;
75 	case GD_WARNING:
76 		fputs("GD Warning: ", stderr);
77 		break;
78 	case GD_NOTICE:
79 		fputs("GD Notice: ", stderr);
80 		break;
81 #ifndef PHP_WIN32
82 	case GD_INFO:
83 		fputs("GD Info: ", stderr);
84 		break;
85 	case GD_DEBUG:
86 		fputs("GD Debug: ", stderr);
87 		break;
88 #endif
89 	}
90 	vfprintf(stderr, format, args);
91 	fflush(stderr);
92 }
93 
94 static gdErrorMethod gd_error_method = gd_stderr_error;
95 
_gd_error_ex(int priority,const char * format,va_list args)96 static void _gd_error_ex(int priority, const char *format, va_list args)
97 {
98 	if (gd_error_method) {
99 		gd_error_method(priority, format, args);
100 	}
101 }
102 
gd_error(const char * format,...)103 void gd_error(const char *format, ...)
104 {
105 	va_list args;
106 
107 	va_start(args, format);
108 	_gd_error_ex(GD_WARNING, format, args);
109 	va_end(args);
110 }
gd_error_ex(int priority,const char * format,...)111 void gd_error_ex(int priority, const char *format, ...)
112 {
113 	va_list args;
114 
115 	va_start(args, format);
116 	_gd_error_ex(priority, format, args);
117 	va_end(args);
118 }
119 
120 /*
121 	Function: gdSetErrorMethod
122 */
gdSetErrorMethod(gdErrorMethod error_method)123 void gdSetErrorMethod(gdErrorMethod error_method)
124 {
125 	gd_error_method = error_method;
126 }
127 
128 /*
129 	Function: gdClearErrorMethod
130 */
gdClearErrorMethod(void)131 void gdClearErrorMethod(void)
132 {
133 	gd_error_method = gd_stderr_error;
134 }
135 
136 static void gdImageBrushApply(gdImagePtr im, int x, int y);
137 static void gdImageTileApply(gdImagePtr im, int x, int y);
138 static int gdAlphaOverlayColor(int src, int dst, int max);
139 int gdImageGetTrueColorPixel(gdImagePtr im, int x, int y);
140 
gdImageCreate(int sx,int sy)141 gdImagePtr gdImageCreate (int sx, int sy)
142 {
143 	int i;
144 	gdImagePtr im;
145 
146 	if (overflow2(sx, sy)) {
147 		return NULL;
148 	}
149 	if (overflow2(sizeof(unsigned char *), sy)) {
150 		return NULL;
151 	}
152 	if (overflow2(sizeof(unsigned char), sx)) {
153 		return NULL;
154 	}
155 
156 	im = (gdImage *) gdCalloc(1, sizeof(gdImage));
157 
158 	/* Row-major ever since gd 1.3 */
159 	im->pixels = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
160 	im->polyInts = 0;
161 	im->polyAllocated = 0;
162 	im->brush = 0;
163 	im->tile = 0;
164 	im->style = 0;
165 	for (i = 0; i < sy; i++) {
166 		/* Row-major ever since gd 1.3 */
167 		im->pixels[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
168 	}
169 	im->sx = sx;
170 	im->sy = sy;
171 	im->colorsTotal = 0;
172 	im->transparent = (-1);
173 	im->interlace = 0;
174 	im->thick = 1;
175 	im->AA = 0;
176 	for (i = 0; i < gdMaxColors; i++) {
177 		im->open[i] = 1;
178 		im->red[i] = 0;
179 		im->green[i] = 0;
180 		im->blue[i] = 0;
181 	}
182 	im->trueColor = 0;
183 	im->tpixels = 0;
184 	im->cx1 = 0;
185 	im->cy1 = 0;
186 	im->cx2 = im->sx - 1;
187 	im->cy2 = im->sy - 1;
188 	im->res_x = GD_RESOLUTION;
189 	im->res_y = GD_RESOLUTION;
190 	im->interpolation = NULL;
191 	im->interpolation_id = GD_BILINEAR_FIXED;
192 	return im;
193 }
194 
gdImageCreateTrueColor(int sx,int sy)195 gdImagePtr gdImageCreateTrueColor (int sx, int sy)
196 {
197 	int i;
198 	gdImagePtr im;
199 
200 	if (overflow2(sx, sy)) {
201 		return NULL;
202 	}
203 	if (overflow2(sizeof(int *), sy)) {
204 		return NULL;
205 	}
206 	if (overflow2(sizeof(int), sx)) {
207 		return NULL;
208 	}
209 
210 	im = (gdImage *) gdMalloc(sizeof(gdImage));
211 	memset(im, 0, sizeof(gdImage));
212 	im->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
213 	im->polyInts = 0;
214 	im->polyAllocated = 0;
215 	im->brush = 0;
216 	im->tile = 0;
217 	im->style = 0;
218 	for (i = 0; i < sy; i++) {
219 		im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
220 	}
221 	im->sx = sx;
222 	im->sy = sy;
223 	im->transparent = (-1);
224 	im->interlace = 0;
225 	im->trueColor = 1;
226 	/* 2.0.2: alpha blending is now on by default, and saving of alpha is
227 	 * off by default. This allows font antialiasing to work as expected
228 	 * on the first try in JPEGs -- quite important -- and also allows
229 	 * for smaller PNGs when saving of alpha channel is not really
230 	 * desired, which it usually isn't!
231 	 */
232 	im->saveAlphaFlag = 0;
233 	im->alphaBlendingFlag = 1;
234 	im->thick = 1;
235 	im->AA = 0;
236 	im->cx1 = 0;
237 	im->cy1 = 0;
238 	im->cx2 = im->sx - 1;
239 	im->cy2 = im->sy - 1;
240 	im->res_x = GD_RESOLUTION;
241 	im->res_y = GD_RESOLUTION;
242 	im->interpolation = NULL;
243 	im->interpolation_id = GD_BILINEAR_FIXED;
244 	return im;
245 }
246 
gdImageDestroy(gdImagePtr im)247 void gdImageDestroy (gdImagePtr im)
248 {
249 	int i;
250 	if (im->pixels) {
251 		for (i = 0; i < im->sy; i++) {
252 			gdFree(im->pixels[i]);
253 		}
254 		gdFree(im->pixels);
255 	}
256 	if (im->tpixels) {
257 		for (i = 0; i < im->sy; i++) {
258 			gdFree(im->tpixels[i]);
259 		}
260 		gdFree(im->tpixels);
261 	}
262 	if (im->polyInts) {
263 		gdFree(im->polyInts);
264 	}
265 	if (im->style) {
266 		gdFree(im->style);
267 	}
268 	gdFree(im);
269 }
270 
gdImageColorClosest(gdImagePtr im,int r,int g,int b)271 int gdImageColorClosest (gdImagePtr im, int r, int g, int b)
272 {
273 	return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
274 }
275 
gdImageColorClosestAlpha(gdImagePtr im,int r,int g,int b,int a)276 int gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
277 {
278 	int i;
279 	long rd, gd, bd, ad;
280 	int ct = (-1);
281 	int first = 1;
282 	long mindist = 0;
283 
284 	if (im->trueColor) {
285 		return gdTrueColorAlpha(r, g, b, a);
286 	}
287 	for (i = 0; i < im->colorsTotal; i++) {
288 		long dist;
289 		if (im->open[i]) {
290 			continue;
291 		}
292 		rd = im->red[i] - r;
293 		gd = im->green[i] - g;
294 		bd = im->blue[i] - b;
295 		/* gd 2.02: whoops, was - b (thanks to David Marwood) */
296 		ad = im->alpha[i] - a;
297 		dist = rd * rd + gd * gd + bd * bd + ad * ad;
298 		if (first || (dist < mindist)) {
299 			mindist = dist;
300 			ct = i;
301 			first = 0;
302 		}
303 	}
304 	return ct;
305 }
306 
307 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
308  * on colour conversion to/from RBG and HWB colour systems.
309  * It has been modified to return the converted value as a * parameter.
310  */
311 
312 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
313 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
314 #define HWB_UNDEFINED -1
315 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0f; s.G = g/255.0f; s.B = b/255.0f;}
316 
317 #ifndef MIN
318 #define MIN(a,b) ((a)<(b)?(a):(b))
319 #endif
320 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
321 #ifndef MAX
322 #define MAX(a,b) ((a)<(b)?(b):(a))
323 #endif
324 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
325 
326 
327 /*
328  * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
329  * red always maps to 6 in this implementation. Therefore UNDEFINED can be
330  * defined as 0 in situations where only unsigned numbers are desired.
331  */
332 typedef struct
333 {
334 	float R, G, B;
335 }
336 RGBType;
337 typedef struct
338 {
339 	float H, W, B;
340 }
341 HWBType;
342 
RGB_to_HWB(RGBType RGB,HWBType * HWB)343 static HWBType * RGB_to_HWB (RGBType RGB, HWBType * HWB)
344 {
345 	/*
346 	 * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
347 	 * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
348 	 */
349 
350 	float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
351 	int i;
352 
353 	w = MIN3 (R, G, B);
354 	v = MAX3 (R, G, B);
355 	b = 1 - v;
356 	if (v == w) {
357 		RETURN_HWB(HWB_UNDEFINED, w, b);
358 	}
359 	f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
360 	i = (R == w) ? 3 : ((G == w) ? 5 : 1);
361 
362 	RETURN_HWB(i - f / (v - w), w, b);
363 }
364 
HWB_Diff(int r1,int g1,int b1,int r2,int g2,int b2)365 static float HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
366 {
367 	RGBType RGB1, RGB2;
368 	HWBType HWB1, HWB2;
369 	float diff;
370 
371 	SETUP_RGB(RGB1, r1, g1, b1);
372 	SETUP_RGB(RGB2, r2, g2, b2);
373 
374 	RGB_to_HWB(RGB1, &HWB1);
375 	RGB_to_HWB(RGB2, &HWB2);
376 
377 	/*
378 	 * I made this bit up; it seems to produce OK results, and it is certainly
379 	 * more visually correct than the current RGB metric. (PJW)
380 	 */
381 
382 	if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
383 		diff = 0.0f;	/* Undefined hues always match... */
384 	} else {
385 		diff = fabsf(HWB1.H - HWB2.H);
386 		if (diff > 3.0f) {
387 			diff = 6.0f - diff;	/* Remember, it's a colour circle */
388 		}
389 	}
390 
391 	diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
392 
393 	return diff;
394 }
395 
396 
397 #if 0
398 /*
399  * This is not actually used, but is here for completeness, in case someone wants to
400  * use the HWB stuff for anything else...
401  */
402 static RGBType * HWB_to_RGB (HWBType HWB, RGBType * RGB)
403 {
404 	/*
405 	 * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
406 	 * RGB are each returned on [0, 1].
407 	 */
408 
409 	float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
410 	int i;
411 
412 	v = 1 - b;
413 	if (h == HWB_UNDEFINED) {
414 		RETURN_RGB(v, v, v);
415 	}
416 	i = floor(h);
417 	f = h - i;
418 	if (i & 1) {
419 		f = 1 - f; /* if i is odd */
420 	}
421 	n = w + f * (v - w);		/* linear interpolation between w and v */
422 	switch (i) {
423 		case 6:
424 		case 0:
425 			RETURN_RGB(v, n, w);
426 		case 1:
427 			RETURN_RGB(n, v, w);
428 		case 2:
429 			RETURN_RGB(w, v, n);
430 		case 3:
431 			RETURN_RGB(w, n, v);
432 		case 4:
433 			RETURN_RGB(n, w, v);
434 		case 5:
435 			RETURN_RGB(v, w, n);
436 	}
437 
438 	return RGB;
439 }
440 #endif
441 
gdImageColorClosestHWB(gdImagePtr im,int r,int g,int b)442 int gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
443 {
444 	int i;
445 	/* long rd, gd, bd; */
446 	int ct = (-1);
447 	int first = 1;
448 	float mindist = 0;
449 	if (im->trueColor) {
450 		return gdTrueColor(r, g, b);
451 	}
452 	for (i = 0; i < im->colorsTotal; i++) {
453 		float dist;
454 		if (im->open[i]) {
455 			continue;
456 		}
457 		dist = HWB_Diff(im->red[i], im->green[i], im->blue[i], r, g, b);
458 		if (first || (dist < mindist)) {
459 			mindist = dist;
460 			ct = i;
461 			first = 0;
462 		}
463 	}
464 	return ct;
465 }
466 
gdImageColorExact(gdImagePtr im,int r,int g,int b)467 int gdImageColorExact (gdImagePtr im, int r, int g, int b)
468 {
469 	return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
470 }
471 
gdImageColorExactAlpha(gdImagePtr im,int r,int g,int b,int a)472 int gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
473 {
474 	int i;
475 	if (im->trueColor) {
476 		return gdTrueColorAlpha(r, g, b, a);
477 	}
478 	for (i = 0; i < im->colorsTotal; i++) {
479 		if (im->open[i]) {
480 			continue;
481 		}
482 		if ((im->red[i] == r) && (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
483 			return i;
484 		}
485 	}
486 	return -1;
487 }
488 
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)489 int gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
490 {
491 	return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
492 }
493 
gdImageColorAllocateAlpha(gdImagePtr im,int r,int g,int b,int a)494 int gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
495 {
496 	int i;
497 	int ct = (-1);
498 	if (im->trueColor) {
499 		return gdTrueColorAlpha(r, g, b, a);
500 	}
501 	for (i = 0; i < im->colorsTotal; i++) {
502 		if (im->open[i]) {
503 			ct = i;
504 			break;
505 		}
506 	}
507 	if (ct == (-1)) {
508 		ct = im->colorsTotal;
509 		if (ct == gdMaxColors) {
510 			return -1;
511 		}
512 		im->colorsTotal++;
513 	}
514 	im->red[ct] = r;
515 	im->green[ct] = g;
516 	im->blue[ct] = b;
517 	im->alpha[ct] = a;
518 	im->open[ct] = 0;
519 
520 	return ct;
521 }
522 
523 /*
524  * gdImageColorResolve is an alternative for the code fragment:
525  *
526  *      if ((color=gdImageColorExact(im,R,G,B)) < 0)
527  *        if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
528  *          color=gdImageColorClosest(im,R,G,B);
529  *
530  * in a single function.    Its advantage is that it is guaranteed to
531  * return a color index in one search over the color table.
532  */
533 
gdImageColorResolve(gdImagePtr im,int r,int g,int b)534 int gdImageColorResolve (gdImagePtr im, int r, int g, int b)
535 {
536 	return gdImageColorResolveAlpha(im, r, g, b, gdAlphaOpaque);
537 }
538 
gdImageColorResolveAlpha(gdImagePtr im,int r,int g,int b,int a)539 int gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
540 {
541   int c;
542   int ct = -1;
543   int op = -1;
544   long rd, gd, bd, ad, dist;
545   long mindist = 4 * 255 * 255;	/* init to max poss dist */
546   if (im->trueColor)
547     {
548       return gdTrueColorAlpha (r, g, b, a);
549     }
550 
551   for (c = 0; c < im->colorsTotal; c++)
552     {
553       if (im->open[c])
554 	{
555 	  op = c;		/* Save open slot */
556 	  continue;		/* Color not in use */
557 	}
558       if (c == im->transparent)
559         {
560           /* don't ever resolve to the color that has
561            * been designated as the transparent color */
562           continue;
563 	}
564       rd = (long) (im->red[c] - r);
565       gd = (long) (im->green[c] - g);
566       bd = (long) (im->blue[c] - b);
567       ad = (long) (im->alpha[c] - a);
568       dist = rd * rd + gd * gd + bd * bd + ad * ad;
569       if (dist < mindist)
570 	{
571 	  if (dist == 0)
572 	    {
573 	      return c;		/* Return exact match color */
574 	    }
575 	  mindist = dist;
576 	  ct = c;
577 	}
578     }
579   /* no exact match.  We now know closest, but first try to allocate exact */
580   if (op == -1)
581     {
582       op = im->colorsTotal;
583       if (op == gdMaxColors)
584 	{			/* No room for more colors */
585 	  return ct;		/* Return closest available color */
586 	}
587       im->colorsTotal++;
588     }
589   im->red[op] = r;
590   im->green[op] = g;
591   im->blue[op] = b;
592   im->alpha[op] = a;
593   im->open[op] = 0;
594   return op;			/* Return newly allocated color */
595 }
596 
gdImageColorDeallocate(gdImagePtr im,int color)597 void gdImageColorDeallocate (gdImagePtr im, int color)
598 {
599 	if (im->trueColor) {
600 		return;
601 	}
602 	/* Mark it open. */
603 	im->open[color] = 1;
604 }
605 
gdImageColorTransparent(gdImagePtr im,int color)606 void gdImageColorTransparent (gdImagePtr im, int color)
607 {
608 	if (color < 0) {
609 		return;
610 	}
611 	if (!im->trueColor) {
612 		if((color >= im->colorsTotal)) {
613 			return;
614 		}
615 		/* Make the old transparent color opaque again */
616 		if (im->transparent != -1) {
617 			im->alpha[im->transparent] = gdAlphaOpaque;
618 		}
619 		im->alpha[color] = gdAlphaTransparent;
620 	}
621 	im->transparent = color;
622 }
623 
gdImagePaletteCopy(gdImagePtr to,gdImagePtr from)624 void gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
625 {
626 	int i;
627 	int x, y, p;
628 	int xlate[256];
629 	if (to->trueColor || from->trueColor) {
630 		return;
631 	}
632 
633 	for (i = 0; i < 256; i++) {
634 		xlate[i] = -1;
635 	}
636 
637 	for (y = 0; y < to->sy; y++) {
638 		for (x = 0; x < to->sx; x++) {
639 			p = gdImageGetPixel(to, x, y);
640 			if (xlate[p] == -1) {
641 				/* This ought to use HWB, but we don't have an alpha-aware version of that yet. */
642 				xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
643 			}
644 			gdImageSetPixel(to, x, y, xlate[p]);
645 		}
646 	}
647 
648 	for (i = 0; i < from->colorsTotal; i++) {
649 		to->red[i] = from->red[i];
650 		to->blue[i] = from->blue[i];
651 		to->green[i] = from->green[i];
652 		to->alpha[i] = from->alpha[i];
653 		to->open[i] = 0;
654 	}
655 
656 	for (i = from->colorsTotal; i < to->colorsTotal; i++) {
657 		to->open[i] = 1;
658 	}
659 
660 	to->colorsTotal = from->colorsTotal;
661 }
662 
663 /* 2.0.10: before the drawing routines, some code to clip points that are
664  * outside the drawing window.  Nick Atty (nick@canalplan.org.uk)
665  *
666  * This is the Sutherland Hodgman Algorithm, as implemented by
667  * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short.  See Dr Dobb's
668  * Journal, January 1996, pp107-110 and 116-117
669  *
670  * Given the end points of a line, and a bounding rectangle (which we
671  * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
672  * the edges of the rectangle if the line should be drawn at all,
673  * otherwise return a failure code
674  */
675 
676 /* this does "one-dimensional" clipping: note that the second time it
677  *  is called, all the x parameters refer to height and the y to width
678  *  - the comments ignore this (if you can understand it when it's
679  *  looking at the X parameters, it should become clear what happens on
680  *  the second call!)  The code is simplified from that in the article,
681  *  as we know that gd images always start at (0,0)
682  */
683 
clip_1d(int * x0,int * y0,int * x1,int * y1,int maxdim)684 static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) {
685 	double m;      /* gradient of line */
686 
687 	if (*x0 < 0) {  /* start of line is left of window */
688 		if(*x1 < 0) { /* as is the end, so the line never cuts the window */
689 			return 0;
690 		}
691 		m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
692 		/* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
693 		*y0 -= (int)(m * *x0);
694 		*x0 = 0;
695 		/* now, perhaps, adjust the far end of the line as well */
696 		if (*x1 > maxdim) {
697 			*y1 += (int)(m * (maxdim - *x1));
698 			*x1 = maxdim;
699 		}
700 		return 1;
701 	}
702 	if (*x0 > maxdim) { /* start of line is right of window - complement of above */
703 		if (*x1 > maxdim) { /* as is the end, so the line misses the window */
704 			return 0;
705 		}
706 		m = (*y1 - *y0)/(double)(*x1 - *x0);  /* calculate the slope of the line */
707 		*y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right boundary */
708 		*x0 = maxdim;
709 		/* now, perhaps, adjust the end of the line */
710 		if (*x1 < 0) {
711 			*y1 -= (int)(m * *x1);
712 			*x1 = 0;
713 		}
714 		return 1;
715 	}
716 	/* the final case - the start of the line is inside the window */
717 	if (*x1 > maxdim) { /* other end is outside to the right */
718 		m = (*y1 - *y0)/(double)(*x1 - *x0);  /* calculate the slope of the line */
719 		*y1 += (int)(m * (maxdim - *x1));
720 		*x1 = maxdim;
721 		return 1;
722 	}
723 	if (*x1 < 0) { /* other end is outside to the left */
724 		m = (*y1 - *y0)/(double)(*x1 - *x0);  /* calculate the slope of the line */
725 		*y1 -= (int)(m * *x1);
726 		*x1 = 0;
727 		return 1;
728 	}
729 	/* only get here if both points are inside the window */
730 	return 1;
731 }
732 
gdImageSetPixel(gdImagePtr im,int x,int y,int color)733 void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
734 {
735 	int p;
736 	switch (color) {
737 		case gdStyled:
738 			if (!im->style) {
739 				/* Refuse to draw if no style is set. */
740 				return;
741 			} else {
742 				p = im->style[im->stylePos++];
743 			}
744 			if (p != gdTransparent) {
745 				gdImageSetPixel(im, x, y, p);
746 			}
747 			im->stylePos = im->stylePos % im->styleLength;
748 			break;
749 		case gdStyledBrushed:
750 			if (!im->style) {
751 				/* Refuse to draw if no style is set. */
752 				return;
753 			}
754 			p = im->style[im->stylePos++];
755 			if (p != gdTransparent && p != 0) {
756 				gdImageSetPixel(im, x, y, gdBrushed);
757 			}
758 			im->stylePos = im->stylePos % im->styleLength;
759 			break;
760 		case gdBrushed:
761 			gdImageBrushApply(im, x, y);
762 			break;
763 		case gdTiled:
764 			gdImageTileApply(im, x, y);
765 			break;
766 		case gdAntiAliased:
767 			/* This shouldn't happen (2.0.26) because we just call
768 			  gdImageAALine now, but do something sane. */
769 			gdImageSetPixel(im, x, y, im->AA_color);
770 			break;
771 		default:
772 			if (gdImageBoundsSafe(im, x, y)) {
773 				if (im->trueColor) {
774 					switch (im->alphaBlendingFlag) {
775 						default:
776 						case gdEffectReplace:
777 							im->tpixels[y][x] = color;
778 							break;
779 						case gdEffectAlphaBlend:
780 						case gdEffectNormal:
781 							im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
782 							break;
783 						case gdEffectOverlay :
784 							im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
785 							break;
786 						case gdEffectMultiply :
787 							im->tpixels[y][x] = gdLayerMultiply(im->tpixels[y][x], color);
788 							break;
789 					}
790 				} else {
791 					im->pixels[y][x] = color;
792 				}
793 			}
794 			break;
795 	}
796 }
797 
gdImageGetTrueColorPixel(gdImagePtr im,int x,int y)798 int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
799 {
800 	int p = gdImageGetPixel(im, x, y);
801 
802 	if (!im->trueColor)  {
803 		return gdTrueColorAlpha(im->red[p], im->green[p], im->blue[p], (im->transparent == p) ? gdAlphaTransparent : im->alpha[p]);
804 	} else {
805 		return p;
806 	}
807 }
808 
gdImageBrushApply(gdImagePtr im,int x,int y)809 static void gdImageBrushApply (gdImagePtr im, int x, int y)
810 {
811 	int lx, ly;
812 	int hy, hx;
813 	int x1, y1, x2, y2;
814 	int srcx, srcy;
815 
816 	if (!im->brush) {
817 		return;
818 	}
819 
820 	hy = gdImageSY(im->brush) / 2;
821 	y1 = y - hy;
822 	y2 = y1 + gdImageSY(im->brush);
823 	hx = gdImageSX(im->brush) / 2;
824 	x1 = x - hx;
825 	x2 = x1 + gdImageSX(im->brush);
826 	srcy = 0;
827 
828 	if (im->trueColor) {
829 		if (im->brush->trueColor) {
830 			for (ly = y1; ly < y2; ly++) {
831 				srcx = 0;
832 				for (lx = x1; (lx < x2); lx++) {
833 					int p;
834 					p = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
835 					/* 2.0.9, Thomas Winzig: apply simple full transparency */
836 					if (p != gdImageGetTransparent(im->brush)) {
837 						gdImageSetPixel(im, lx, ly, p);
838 					}
839 					srcx++;
840 				}
841 				srcy++;
842 			}
843 		} else {
844 			/* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger for pointing out the issue) */
845 			for (ly = y1; ly < y2; ly++) {
846 				srcx = 0;
847 				for (lx = x1; lx < x2; lx++) {
848 					int p, tc;
849 					p = gdImageGetPixel(im->brush, srcx, srcy);
850 					tc = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
851 					/* 2.0.9, Thomas Winzig: apply simple full transparency */
852 					if (p != gdImageGetTransparent(im->brush)) {
853 						gdImageSetPixel(im, lx, ly, tc);
854 					}
855 					srcx++;
856 				}
857 				srcy++;
858 			}
859 		}
860 	} else {
861 		for (ly = y1; ly < y2; ly++) {
862 			srcx = 0;
863 			for (lx = x1; lx < x2; lx++) {
864 				int p;
865 				p = gdImageGetPixel(im->brush, srcx, srcy);
866 				/* Allow for non-square brushes! */
867 				if (p != gdImageGetTransparent(im->brush)) {
868 					/* Truecolor brush. Very slow on a palette destination. */
869 					if (im->brush->trueColor) {
870 						gdImageSetPixel(im, lx, ly, gdImageColorResolveAlpha(im, gdTrueColorGetRed(p),
871 													 gdTrueColorGetGreen(p),
872 													 gdTrueColorGetBlue(p),
873 													 gdTrueColorGetAlpha(p)));
874 					} else {
875 						gdImageSetPixel(im, lx, ly, im->brushColorMap[p]);
876 					}
877 				}
878 				srcx++;
879 			}
880 			srcy++;
881 		}
882 	}
883 }
884 
gdImageTileApply(gdImagePtr im,int x,int y)885 static void gdImageTileApply (gdImagePtr im, int x, int y)
886 {
887 	gdImagePtr tile = im->tile;
888 	int srcx, srcy;
889 	int p;
890 	if (!tile) {
891 		return;
892 	}
893 	srcx = x % gdImageSX(tile);
894 	srcy = y % gdImageSY(tile);
895 	if (im->trueColor) {
896 		p = gdImageGetPixel(tile, srcx, srcy);
897 		if (p != gdImageGetTransparent (tile)) {
898 			if (!tile->trueColor) {
899 				p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]);
900 			}
901 			gdImageSetPixel(im, x, y, p);
902 		}
903 	} else {
904 		p = gdImageGetPixel(tile, srcx, srcy);
905 		/* Allow for transparency */
906 		if (p != gdImageGetTransparent(tile)) {
907 			if (tile->trueColor) {
908 				/* Truecolor tile. Very slow on a palette destination. */
909 				gdImageSetPixel(im, x, y, gdImageColorResolveAlpha(im,
910 											gdTrueColorGetRed(p),
911 											gdTrueColorGetGreen(p),
912 											gdTrueColorGetBlue(p),
913 											gdTrueColorGetAlpha(p)));
914 			} else {
915 				gdImageSetPixel(im, x, y, im->tileColorMap[p]);
916 			}
917 		}
918 	}
919 }
920 
921 
gdImageTileGet(gdImagePtr im,int x,int y)922 static int gdImageTileGet (gdImagePtr im, int x, int y)
923 {
924 	int srcx, srcy;
925 	int tileColor,p;
926 	if (!im->tile) {
927 		return -1;
928 	}
929 	srcx = x % gdImageSX(im->tile);
930 	srcy = y % gdImageSY(im->tile);
931 	p = gdImageGetPixel(im->tile, srcx, srcy);
932 
933 	if (p == im->tile->transparent) {
934 		tileColor = im->transparent;
935 	} else if (im->trueColor) {
936 		if (im->tile->trueColor) {
937 			tileColor = p;
938 		} else {
939 			tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
940 		}
941 	} else {
942 		if (im->tile->trueColor) {
943 			tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
944 		} else {
945 			tileColor = p;
946 			tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
947 		}
948 	}
949 	return tileColor;
950 }
951 
952 
gdImageGetPixel(gdImagePtr im,int x,int y)953 int gdImageGetPixel (gdImagePtr im, int x, int y)
954 {
955 	if (gdImageBoundsSafe(im, x, y)) {
956 		if (im->trueColor) {
957 			return im->tpixels[y][x];
958 		} else {
959 			return im->pixels[y][x];
960 		}
961 	} else {
962 		return 0;
963 	}
964 }
965 
gdImageAABlend(gdImagePtr im)966 void gdImageAABlend (gdImagePtr im)
967 {
968 	(void)im;
969 }
970 
971 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color);
972 
gdImageClone(gdImagePtr src)973 gdImagePtr gdImageClone (gdImagePtr src) {
974 	gdImagePtr dst;
975 	register int i, x;
976 
977 	if (src->trueColor) {
978 		dst = gdImageCreateTrueColor(src->sx , src->sy);
979 	} else {
980 		dst = gdImageCreate(src->sx , src->sy);
981 	}
982 
983 	if (dst == NULL) {
984 		return NULL;
985 	}
986 
987 	if (src->trueColor == 0) {
988 		dst->colorsTotal = src->colorsTotal;
989 		for (i = 0; i < gdMaxColors; i++) {
990 			dst->red[i]   = src->red[i];
991 			dst->green[i] = src->green[i];
992 			dst->blue[i]  = src->blue[i];
993 			dst->alpha[i] = src->alpha[i];
994 			dst->open[i]  = src->open[i];
995 		}
996 		for (i = 0; i < src->sy; i++) {
997 			for (x = 0; x < src->sx; x++) {
998 				dst->pixels[i][x] = src->pixels[i][x];
999 			}
1000 		}
1001 	} else {
1002 		for (i = 0; i < src->sy; i++) {
1003 			for (x = 0; x < src->sx; x++) {
1004 				dst->tpixels[i][x] = src->tpixels[i][x];
1005 			}
1006 		}
1007 	}
1008 
1009 	dst->interlace   = src->interlace;
1010 
1011 	dst->alphaBlendingFlag = src->alphaBlendingFlag;
1012 	dst->saveAlphaFlag     = src->saveAlphaFlag;
1013 	dst->AA                = src->AA;
1014 	dst->AA_color          = src->AA_color;
1015 	dst->AA_dont_blend     = src->AA_dont_blend;
1016 
1017 	dst->cx1 = src->cx1;
1018 	dst->cy1 = src->cy1;
1019 	dst->cx2 = src->cx2;
1020 	dst->cy2 = src->cy2;
1021 
1022 	dst->res_x = src->res_x;
1023 	dst->res_y = src->res_y;
1024 
1025 	dst->interpolation_id = src->interpolation_id;
1026 	dst->interpolation    = src->interpolation;
1027 
1028 	if (src->brush) {
1029 		dst->brush = gdImageClone(src->brush);
1030 	}
1031 
1032 	if (src->tile) {
1033 		dst->tile = gdImageClone(src->tile);
1034 	}
1035 
1036 	if (src->style) {
1037 		gdImageSetStyle(dst, src->style, src->styleLength);
1038 		dst->stylePos = src->stylePos;
1039 	}
1040 
1041 	for (i = 0; i < gdMaxColors; i++) {
1042 		dst->brushColorMap[i] = src->brushColorMap[i];
1043 		dst->tileColorMap[i] = src->tileColorMap[i];
1044 	}
1045 
1046 	if (src->polyAllocated > 0 && overflow2(sizeof(int), src->polyAllocated) == 0) {
1047 		dst->polyInts = gdMalloc (sizeof (int) * src->polyAllocated);
1048 		dst->polyAllocated = src->polyAllocated;
1049 		for (i = 0; i < src->polyAllocated; i++) {
1050 			dst->polyInts[i] = src->polyInts[i];
1051 		}
1052 	}
1053 
1054 	return dst;
1055 }
1056 
gdImageHLine(gdImagePtr im,int y,int x1,int x2,int col)1057 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
1058 {
1059 	if (im->thick > 1) {
1060 		int thickhalf = im->thick >> 1;
1061 		_gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
1062 	} else {
1063 		if (x2 < x1) {
1064 			int t = x2;
1065 			x2 = x1;
1066 			x1 = t;
1067 		}
1068 
1069 		for (;x1 <= x2; x1++) {
1070 			gdImageSetPixel(im, x1, y, col);
1071 		}
1072 	}
1073 	return;
1074 }
1075 
gdImageVLine(gdImagePtr im,int x,int y1,int y2,int col)1076 static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
1077 {
1078 	if (im->thick > 1) {
1079 		int thickhalf = im->thick >> 1;
1080 		gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
1081 	} else {
1082 		if (y2 < y1) {
1083 			int t = y1;
1084 			y1 = y2;
1085 			y2 = t;
1086 		}
1087 
1088 		for (;y1 <= y2; y1++) {
1089 			gdImageSetPixel(im, x, y1, col);
1090 		}
1091 	}
1092 	return;
1093 }
1094 
1095 /* Bresenham as presented in Foley & Van Dam */
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1096 void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1097 {
1098 	int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1099 	int wid;
1100 	int w, wstart;
1101 	int thick = im->thick;
1102 
1103 	if (color == gdAntiAliased) {
1104 		/*
1105 		   gdAntiAliased passed as color: use the much faster, much cheaper
1106 		   and equally attractive gdImageAALine implementation. That
1107 		   clips too, so don't clip twice.
1108 		   */
1109 		gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
1110 		return;
1111 	}
1112 
1113 	/* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
1114 	if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)-1) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im)-1)) {
1115 		return;
1116 	}
1117 
1118 	dx = abs (x2 - x1);
1119 	dy = abs (y2 - y1);
1120 
1121 	if (dx == 0) {
1122 		gdImageVLine(im, x1, y1, y2, color);
1123 		return;
1124 	} else if (dy == 0) {
1125 		gdImageHLine(im, y1, x1, x2, color);
1126 		return;
1127 	}
1128 
1129 	if (dy <= dx) {
1130 		/* More-or-less horizontal. use wid for vertical stroke */
1131 		/* Doug Claar: watch out for NaN in atan2 (2.0.5) */
1132 		if ((dx == 0) && (dy == 0)) {
1133 			wid = 1;
1134 		} else {
1135 			/* 2.0.12: Michael Schwartz: divide rather than multiply;
1136 TBB: but watch out for /0! */
1137 			double ac = cos (atan2 (dy, dx));
1138 			if (ac != 0) {
1139 				wid = thick / ac;
1140 			} else {
1141 				wid = 1;
1142 			}
1143 			if (wid == 0) {
1144 				wid = 1;
1145 			}
1146 		}
1147 		d = 2 * dy - dx;
1148 		incr1 = 2 * dy;
1149 		incr2 = 2 * (dy - dx);
1150 		if (x1 > x2) {
1151 			x = x2;
1152 			y = y2;
1153 			ydirflag = (-1);
1154 			xend = x1;
1155 		} else {
1156 			x = x1;
1157 			y = y1;
1158 			ydirflag = 1;
1159 			xend = x2;
1160 		}
1161 
1162 		/* Set up line thickness */
1163 		wstart = y - wid / 2;
1164 		for (w = wstart; w < wstart + wid; w++) {
1165 			gdImageSetPixel(im, x, w, color);
1166 		}
1167 
1168 		if (((y2 - y1) * ydirflag) > 0) {
1169 			while (x < xend) {
1170 				x++;
1171 				if (d < 0) {
1172 					d += incr1;
1173 				} else {
1174 					y++;
1175 					d += incr2;
1176 				}
1177 				wstart = y - wid / 2;
1178 				for (w = wstart; w < wstart + wid; w++) {
1179 					gdImageSetPixel (im, x, w, color);
1180 				}
1181 			}
1182 		} else {
1183 			while (x < xend) {
1184 				x++;
1185 				if (d < 0) {
1186 					d += incr1;
1187 				} else {
1188 					y--;
1189 					d += incr2;
1190 				}
1191 				wstart = y - wid / 2;
1192 				for (w = wstart; w < wstart + wid; w++) {
1193 					gdImageSetPixel (im, x, w, color);
1194 				}
1195 			}
1196 		}
1197 	} else {
1198 		/* More-or-less vertical. use wid for horizontal stroke */
1199 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1200 		   TBB: but watch out for /0! */
1201 		double as = sin (atan2 (dy, dx));
1202 		if (as != 0) {
1203 			wid = thick / as;
1204 		} else {
1205 			wid = 1;
1206 		}
1207 		if (wid == 0) {
1208 			wid = 1;
1209 		}
1210 
1211 		d = 2 * dx - dy;
1212 		incr1 = 2 * dx;
1213 		incr2 = 2 * (dx - dy);
1214 		if (y1 > y2) {
1215 			y = y2;
1216 			x = x2;
1217 			yend = y1;
1218 			xdirflag = (-1);
1219 		} else {
1220 			y = y1;
1221 			x = x1;
1222 			yend = y2;
1223 			xdirflag = 1;
1224 		}
1225 
1226 		/* Set up line thickness */
1227 		wstart = x - wid / 2;
1228 		for (w = wstart; w < wstart + wid; w++) {
1229 			gdImageSetPixel (im, w, y, color);
1230 		}
1231 
1232 		if (((x2 - x1) * xdirflag) > 0) {
1233 			while (y < yend) {
1234 				y++;
1235 				if (d < 0) {
1236 					d += incr1;
1237 				} else {
1238 					x++;
1239 					d += incr2;
1240 				}
1241 				wstart = x - wid / 2;
1242 				for (w = wstart; w < wstart + wid; w++) {
1243 					gdImageSetPixel (im, w, y, color);
1244 				}
1245 			}
1246 		} else {
1247 			while (y < yend) {
1248 				y++;
1249 				if (d < 0) {
1250 					d += incr1;
1251 				} else {
1252 					x--;
1253 					d += incr2;
1254 				}
1255 				wstart = x - wid / 2;
1256 				for (w = wstart; w < wstart + wid; w++) {
1257 					gdImageSetPixel (im, w, y, color);
1258 				}
1259 			}
1260 		}
1261 	}
1262 }
1263 
1264 
1265 /*
1266  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
1267  * */
1268 #define BLEND_COLOR(a, nc, c, cc) \
1269 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
1270 
gdImageSetAAPixelColor(gdImagePtr im,int x,int y,int color,int t)1271 inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
1272 {
1273 	int dr,dg,db,p,r,g,b;
1274 	dr = gdTrueColorGetRed(color);
1275 	dg = gdTrueColorGetGreen(color);
1276 	db = gdTrueColorGetBlue(color);
1277 
1278 	p = gdImageGetPixel(im,x,y);
1279 	r = gdTrueColorGetRed(p);
1280 	g = gdTrueColorGetGreen(p);
1281 	b = gdTrueColorGetBlue(p);
1282 
1283 	BLEND_COLOR(t, dr, r, dr);
1284 	BLEND_COLOR(t, dg, g, dg);
1285 	BLEND_COLOR(t, db, b, db);
1286 	im->tpixels[y][x]=gdTrueColorAlpha(dr, dg, db,  gdAlphaOpaque);
1287 }
1288 
1289 /*
1290  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
1291  **/
gdImageAALine(gdImagePtr im,int x1,int y1,int x2,int y2,int col)1292 void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
1293 {
1294 	/* keep them as 32bits */
1295 	long x, y, inc, frac;
1296 	long dx, dy,tmp;
1297 
1298 	if (!im->trueColor) {
1299 		/* TBB: don't crash when the image is of the wrong type */
1300 		gdImageLine(im, x1, y1, x2, y2, col);
1301 		return;
1302 	}
1303 
1304 	/* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
1305 	if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)-1) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im)-1)) {
1306 		return;
1307 	}
1308 
1309 	dx = x2 - x1;
1310 	dy = y2 - y1;
1311 
1312 	if (dx == 0 && dy == 0) {
1313 		return;
1314 	}
1315 	if (abs((int)dx) > abs((int)dy)) {
1316 		if (dx < 0) {
1317 			tmp = x1;
1318 			x1 = x2;
1319 			x2 = tmp;
1320 			tmp = y1;
1321 			y1 = y2;
1322 			y2 = tmp;
1323 			dx = x2 - x1;
1324 			dy = y2 - y1;
1325 		}
1326 		y = y1;
1327 		inc = (dy * 65536) / dx;
1328 		frac = 0;
1329 		for (x = x1; x <= x2; x++) {
1330 			gdImageSetAAPixelColor(im, x, y, col, (frac >> 8) & 0xFF);
1331 			if (y + 1 < im->sy) {
1332 				gdImageSetAAPixelColor(im, x, y + 1, col, (~frac >> 8) & 0xFF);
1333 			}
1334 			frac += inc;
1335 			if (frac >= 65536) {
1336 				frac -= 65536;
1337 				y++;
1338 			} else if (frac < 0) {
1339 				frac += 65536;
1340 				y--;
1341 			}
1342 		}
1343 	} else {
1344 		if (dy < 0) {
1345 			tmp = x1;
1346 			x1 = x2;
1347 			x2 = tmp;
1348 			tmp = y1;
1349 			y1 = y2;
1350 			y2 = tmp;
1351 			dx = x2 - x1;
1352 			dy = y2 - y1;
1353 		}
1354 		x = x1;
1355 		inc = (dx * 65536) / dy;
1356 		frac = 0;
1357 		for (y = y1; y <= y2; y++) {
1358 			gdImageSetAAPixelColor(im, x, y, col, (frac >> 8) & 0xFF);
1359 			if (x + 1 < im->sx) {
1360 				gdImageSetAAPixelColor(im, x + 1, y, col, (~frac >> 8) & 0xFF);
1361 			}
1362 			frac += inc;
1363 			if (frac >= 65536) {
1364 				frac -= 65536;
1365 				x++;
1366 			} else if (frac < 0) {
1367 				frac += 65536;
1368 				x--;
1369 			}
1370 		}
1371 	}
1372 }
1373 
1374 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert);
1375 
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1376 void gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1377 {
1378 	int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1379 	int dashStep = 0;
1380 	int on = 1;
1381 	int wid;
1382 	int vert;
1383 	int thick = im->thick;
1384 
1385 	dx = abs(x2 - x1);
1386 	dy = abs(y2 - y1);
1387 	if (dy <= dx) {
1388 		/* More-or-less horizontal. use wid for vertical stroke */
1389 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1390 		TBB: but watch out for /0! */
1391 		double as = sin(atan2(dy, dx));
1392 		if (as != 0) {
1393 			wid = thick / as;
1394 		} else {
1395 			wid = 1;
1396 		}
1397 		vert = 1;
1398 
1399 		d = 2 * dy - dx;
1400 		incr1 = 2 * dy;
1401 		incr2 = 2 * (dy - dx);
1402 		if (x1 > x2) {
1403 			x = x2;
1404 			y = y2;
1405 			ydirflag = (-1);
1406 			xend = x1;
1407 		} else {
1408 			x = x1;
1409 			y = y1;
1410 			ydirflag = 1;
1411 			xend = x2;
1412 		}
1413 		dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1414 		if (((y2 - y1) * ydirflag) > 0) {
1415 			while (x < xend) {
1416 				x++;
1417 				if (d < 0) {
1418 					d += incr1;
1419 				} else {
1420 					y++;
1421 					d += incr2;
1422 				}
1423 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1424 			}
1425 		} else {
1426 			while (x < xend) {
1427 				x++;
1428 				if (d < 0) {
1429 					d += incr1;
1430 				} else {
1431 					y--;
1432 					d += incr2;
1433 				}
1434 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1435 			}
1436 		}
1437 	} else {
1438 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1439 		TBB: but watch out for /0! */
1440 		double as = sin (atan2 (dy, dx));
1441 		if (as != 0) {
1442 			wid = thick / as;
1443 		} else {
1444 			wid = 1;
1445 		}
1446 		vert = 0;
1447 
1448 		d = 2 * dx - dy;
1449 		incr1 = 2 * dx;
1450 		incr2 = 2 * (dx - dy);
1451 		if (y1 > y2) {
1452 			y = y2;
1453 			x = x2;
1454 			yend = y1;
1455 			xdirflag = (-1);
1456 		} else {
1457 			y = y1;
1458 			x = x1;
1459 			yend = y2;
1460 			xdirflag = 1;
1461 		}
1462 		dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1463 		if (((x2 - x1) * xdirflag) > 0) {
1464 			while (y < yend) {
1465 				y++;
1466 				if (d < 0) {
1467 					d += incr1;
1468 				} else {
1469 					x++;
1470 					d += incr2;
1471 				}
1472 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1473 			}
1474 		} else {
1475 			while (y < yend) {
1476 				y++;
1477 				if (d < 0) {
1478 					d += incr1;
1479 				} else {
1480 					x--;
1481 					d += incr2;
1482 				}
1483 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1484 			}
1485 		}
1486 	}
1487 }
1488 
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1489 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert)
1490 {
1491 	int dashStep = *dashStepP;
1492 	int on = *onP;
1493 	int w, wstart;
1494 
1495 	dashStep++;
1496 	if (dashStep == gdDashSize) {
1497 		dashStep = 0;
1498 		on = !on;
1499 	}
1500 	if (on) {
1501 		if (vert) {
1502 			wstart = y - wid / 2;
1503 			for (w = wstart; w < wstart + wid; w++) {
1504 				gdImageSetPixel(im, x, w, color);
1505 			}
1506 		} else {
1507 			wstart = x - wid / 2;
1508 			for (w = wstart; w < wstart + wid; w++) {
1509 				gdImageSetPixel(im, w, y, color);
1510 			}
1511 		}
1512 	}
1513 	*dashStepP = dashStep;
1514 	*onP = on;
1515 }
1516 
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1517 void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1518 {
1519 	int cx, cy;
1520 	int px, py;
1521 	int fline;
1522 	const int xuppper = (x > INT_MAX - f->w) ? INT_MAX : x + f->w;
1523 	const int yuppper = (y > INT_MAX - f->h) ? INT_MAX : y + f->h;
1524 	cx = 0;
1525 	cy = 0;
1526 #ifdef CHARSET_EBCDIC
1527 	c = ASC (c);
1528 #endif /*CHARSET_EBCDIC */
1529 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1530 		return;
1531 	}
1532 	fline = (c - f->offset) * f->h * f->w;
1533 	for (py = y; py < yuppper; py++) {
1534 		for (px = x; px < xuppper; px++) {
1535 			if (f->data[fline + cy * f->w + cx]) {
1536 				gdImageSetPixel(im, px, py, color);
1537 			}
1538 			cx++;
1539 		}
1540 		cx = 0;
1541 		cy++;
1542 	}
1543 }
1544 
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1545 void gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1546 {
1547 	int cx, cy;
1548 	int px, py;
1549 	int fline;
1550 	const int xuppper = (x > INT_MAX - f->h) ? INT_MAX : x + f->h;
1551 	const int ylower = (y < INT_MIN + f->w) ? INT_MIN : y - f->w;
1552 	cx = 0;
1553 	cy = 0;
1554 #ifdef CHARSET_EBCDIC
1555 	c = ASC (c);
1556 #endif /*CHARSET_EBCDIC */
1557 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1558 		return;
1559 	}
1560 	fline = (c - f->offset) * f->h * f->w;
1561 	for (py = y; py > ylower; py--) {
1562 		for (px = x; px < xuppper; px++) {
1563 			if (f->data[fline + cy * f->w + cx]) {
1564 				gdImageSetPixel(im, px, py, color);
1565 			}
1566 			cy++;
1567 		}
1568 		cy = 0;
1569 		cx++;
1570 	}
1571 }
1572 
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1573 void gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1574 {
1575 	int i;
1576 	int l;
1577 	l = strlen ((char *) s);
1578 	for (i = 0; (i < l); i++) {
1579 		gdImageChar(im, f, x, y, s[i], color);
1580 		x += f->w;
1581 	}
1582 }
1583 
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1584 void gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1585 {
1586 	int i;
1587 	int l;
1588 	l = strlen ((char *) s);
1589 	for (i = 0; (i < l); i++) {
1590 		gdImageCharUp(im, f, x, y, s[i], color);
1591 		y -= f->w;
1592 	}
1593 }
1594 
1595 static int strlen16 (unsigned short *s);
1596 
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1597 void gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1598 {
1599 	int i;
1600 	int l;
1601 	l = strlen16(s);
1602 	for (i = 0; (i < l); i++) {
1603 		gdImageChar(im, f, x, y, s[i], color);
1604 		x += f->w;
1605 	}
1606 }
1607 
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1608 void gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1609 {
1610 	int i;
1611 	int l;
1612 	l = strlen16(s);
1613 	for (i = 0; i < l; i++) {
1614 		gdImageCharUp(im, f, x, y, s[i], color);
1615 		y -= f->w;
1616 	}
1617 }
1618 
strlen16(unsigned short * s)1619 static int strlen16 (unsigned short *s)
1620 {
1621 	int len = 0;
1622 	while (*s) {
1623 		s++;
1624 		len++;
1625 	}
1626 	return len;
1627 }
1628 
1629 #ifndef HAVE_LSQRT
1630 /* If you don't have a nice square root function for longs, you can use
1631    ** this hack
1632  */
lsqrt(long n)1633 long lsqrt (long n)
1634 {
1635  	long result = (long) sqrt ((double) n);
1636 	return result;
1637 }
1638 #endif
1639 
1640 /* s and e are integers modulo 360 (degrees), with 0 degrees
1641    being the rightmost extreme and degrees changing clockwise.
1642    cx and cy are the center in pixels; w and h are the horizontal
1643    and vertical diameter in pixels. */
1644 
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)1645 void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
1646 {
1647 	gdImageFilledArc(im, cx, cy, w, h, s, e, color, gdNoFill);
1648 }
1649 
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)1650 void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
1651 {
1652 	gdPoint pts[363];
1653 	int i, pti;
1654 	int lx = 0, ly = 0;
1655 	int fx = 0, fy = 0;
1656 	int startx = -1, starty = -1, endx = -1, endy = -1;
1657 
1658     if ((s % 360)  == (e % 360)) {
1659 		s = 0; e = 360;
1660 	} else {
1661 		if (s > 360) {
1662 			s = s % 360;
1663 		}
1664 
1665 		if (e > 360) {
1666 			e = e % 360;
1667 		}
1668 
1669 		while (s < 0) {
1670 			s += 360;
1671 		}
1672 
1673 		while (e < s) {
1674 			e += 360;
1675 		}
1676 		if (s == e) {
1677 			s = 0; e = 360;
1678 		}
1679 	}
1680 
1681 	for (i = s, pti = 1; i <= e; i++, pti++) {
1682 		int x, y;
1683 		x = endx = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
1684 		y = endy = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
1685 		if (i != s) {
1686 			if (!(style & gdChord)) {
1687 				if (style & gdNoFill) {
1688 					gdImageLine(im, lx, ly, x, y, color);
1689 				} else {
1690 					if (y == ly) {
1691 						pti--; /* don't add this point */
1692 						if (((i > 270 || i < 90) && x > lx) || ((i >  90 && i < 270) && x < lx)) {
1693 							/* replace the old x coord, if increasing on the
1694 							   right side or decreasing on the left side */
1695 							pts[pti].x = x;
1696 						}
1697 					} else {
1698 						pts[pti].x = x;
1699 						pts[pti].y = y;
1700 					}
1701   				}
1702 			}
1703 		} else {
1704 			fx = x;
1705 			fy = y;
1706 			if (!(style & (gdChord | gdNoFill))) {
1707 				pts[0].x = cx;
1708 				pts[0].y = cy;
1709 				pts[pti].x = startx = x;
1710 				pts[pti].y = starty = y;
1711 			}
1712 		}
1713 		lx = x;
1714 		ly = y;
1715 	}
1716 	if (style & gdChord) {
1717 		if (style & gdNoFill) {
1718 			if (style & gdEdged) {
1719 				gdImageLine(im, cx, cy, lx, ly, color);
1720 				gdImageLine(im, cx, cy, fx, fy, color);
1721 			}
1722 			gdImageLine(im, fx, fy, lx, ly, color);
1723 		} else {
1724 			pts[0].x = fx;
1725 			pts[0].y = fy;
1726 			pts[1].x = lx;
1727 			pts[1].y = ly;
1728 			pts[2].x = cx;
1729 			pts[2].y = cy;
1730 			gdImageFilledPolygon(im, pts, 3, color);
1731 		}
1732 	} else {
1733 		if (style & gdNoFill) {
1734 			if (style & gdEdged) {
1735 				gdImageLine(im, cx, cy, lx, ly, color);
1736 				gdImageLine(im, cx, cy, fx, fy, color);
1737 			}
1738 		} else {
1739 			if (e - s < 360) {
1740 				if (pts[1].x != startx && pts[1].y == starty) {
1741 					/* start point has been removed due to y-coord fix => insert it */
1742 					for (i = pti; i > 1; i--) {
1743 						pts[i].x = pts[i-1].x;
1744 						pts[i].y = pts[i-1].y;
1745 					}
1746 					pts[1].x = startx;
1747 					pts[1].y = starty;
1748 					pti++;
1749 				}
1750 				if (pts[pti-1].x != endx && pts[pti-1].y == endy) {
1751 					/* end point has been removed due to y-coord fix => insert it */
1752 					pts[pti].x = endx;
1753 					pts[pti].y = endy;
1754 					pti++;
1755 				}
1756 			}
1757 			pts[pti].x = cx;
1758 			pts[pti].y = cy;
1759 			gdImageFilledPolygon(im, pts, pti+1, color);
1760 		}
1761 	}
1762 }
1763 
1764 /**
1765  * Integer Ellipse functions (gdImageEllipse and gdImageFilledEllipse)
1766  * Function added by Pierre-Alain Joye 02/08/2003 (paj@pearfr.org)
1767  * See the ellipse function simplification for the equation
1768  * as well as the midpoint algorithm.
1769  */
1770 
gdImageEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1771 void gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c)
1772 {
1773 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
1774 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
1775 
1776 	a=w>>1;
1777 	b=h>>1;
1778 	gdImageSetPixel(im,mx+a, my, c);
1779 	gdImageSetPixel(im,mx-a, my, c);
1780 	mx1 = mx-a;my1 = my;
1781 	mx2 = mx+a;my2 = my;
1782 
1783 	aq = a * a;
1784 	bq = b * b;
1785 	dx = aq << 1;
1786 	dy = bq << 1;
1787 	r  = a * bq;
1788 	rx = r << 1;
1789 	ry = 0;
1790 	x = a;
1791 	while (x > 0){
1792 		if (r > 0) {
1793 			my1++;my2--;
1794 			ry +=dx;
1795 			r  -=ry;
1796 		}
1797 		if (r <= 0){
1798 			x--;
1799 			mx1++;mx2--;
1800 			rx -=dy;
1801 			r  +=rx;
1802 		}
1803 		gdImageSetPixel(im,mx1, my1, c);
1804 		gdImageSetPixel(im,mx1, my2, c);
1805 		gdImageSetPixel(im,mx2, my1, c);
1806 		gdImageSetPixel(im,mx2, my2, c);
1807 	}
1808 }
1809 
gdImageFilledEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1810 void gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
1811 {
1812 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
1813 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
1814 	int i;
1815 	int old_y2;
1816 
1817 	a=w>>1;
1818 	b=h>>1;
1819 
1820 	for (x = mx-a; x <= mx+a; x++) {
1821 		gdImageSetPixel(im, x, my, c);
1822 	}
1823 
1824 	mx1 = mx-a;my1 = my;
1825 	mx2 = mx+a;my2 = my;
1826 
1827 	aq = a * a;
1828 	bq = b * b;
1829 	dx = aq << 1;
1830 	dy = bq << 1;
1831 	r  = a * bq;
1832 	rx = r << 1;
1833 	ry = 0;
1834 	x = a;
1835 	old_y2=-2;
1836 	while (x > 0){
1837 		if (r > 0) {
1838 			my1++;my2--;
1839 			ry +=dx;
1840 			r  -=ry;
1841 		}
1842 		if (r <= 0){
1843 			x--;
1844 			mx1++;mx2--;
1845 			rx -=dy;
1846 			r  +=rx;
1847 		}
1848 		if(old_y2!=my2){
1849 			for(i=mx1;i<=mx2;i++){
1850 				gdImageSetPixel(im,i,my1,c);
1851 				gdImageSetPixel(im,i,my2,c);
1852 			}
1853 		}
1854 		old_y2 = my2;
1855 	}
1856 }
1857 
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)1858 void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
1859 {
1860 	int lastBorder;
1861 	/* Seek left */
1862 	int leftLimit = -1, rightLimit;
1863 	int i, restoreAlphaBlending = 0;
1864 
1865 	if (border < 0 || color < 0) {
1866 		/* Refuse to fill to a non-solid border */
1867 		return;
1868 	}
1869 
1870 	if (!im->trueColor) {
1871 		if ((color > (im->colorsTotal - 1)) || (border > (im->colorsTotal - 1)) || (color < 0)) {
1872 			return;
1873 		}
1874 	}
1875 
1876 	restoreAlphaBlending = im->alphaBlendingFlag;
1877 	im->alphaBlendingFlag = 0;
1878 
1879 	if (x >= im->sx) {
1880 		x = im->sx - 1;
1881 	} else if (x < 0) {
1882 		x = 0;
1883 	}
1884 	if (y >= im->sy) {
1885 		y = im->sy - 1;
1886 	} else if (y < 0) {
1887 		y = 0;
1888 	}
1889 
1890 	for (i = x; i >= 0; i--) {
1891 		if (gdImageGetPixel(im, i, y) == border) {
1892 			break;
1893 		}
1894 		gdImageSetPixel(im, i, y, color);
1895 		leftLimit = i;
1896 	}
1897 	if (leftLimit == -1) {
1898 		im->alphaBlendingFlag = restoreAlphaBlending;
1899 		return;
1900 	}
1901 	/* Seek right */
1902 	rightLimit = x;
1903 	for (i = (x + 1); i < im->sx; i++) {
1904 		if (gdImageGetPixel(im, i, y) == border) {
1905 			break;
1906 		}
1907 		gdImageSetPixel(im, i, y, color);
1908 		rightLimit = i;
1909 	}
1910 	/* Look at lines above and below and start paints */
1911 	/* Above */
1912 	if (y > 0) {
1913 		lastBorder = 1;
1914 		for (i = leftLimit; i <= rightLimit; i++) {
1915 			int c = gdImageGetPixel(im, i, y - 1);
1916 			if (lastBorder) {
1917 				if ((c != border) && (c != color)) {
1918 					gdImageFillToBorder(im, i, y - 1, border, color);
1919 					lastBorder = 0;
1920 				}
1921 			} else if ((c == border) || (c == color)) {
1922 				lastBorder = 1;
1923 			}
1924 		}
1925 	}
1926 
1927 	/* Below */
1928 	if (y < ((im->sy) - 1)) {
1929 		lastBorder = 1;
1930 		for (i = leftLimit; i <= rightLimit; i++) {
1931 			int c = gdImageGetPixel(im, i, y + 1);
1932 
1933 			if (lastBorder) {
1934 				if ((c != border) && (c != color)) {
1935 					gdImageFillToBorder(im, i, y + 1, border, color);
1936 					lastBorder = 0;
1937 				}
1938 			} else if ((c == border) || (c == color)) {
1939 				lastBorder = 1;
1940 			}
1941 		}
1942 	}
1943 	im->alphaBlendingFlag = restoreAlphaBlending;
1944 }
1945 
1946 /*
1947  * set the pixel at (x,y) and its 4-connected neighbors
1948  * with the same pixel value to the new pixel value nc (new color).
1949  * A 4-connected neighbor:  pixel above, below, left, or right of a pixel.
1950  * ideas from comp.graphics discussions.
1951  * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
1952  * contain the same color as the color to fill. To do not bloat normal filling
1953  * code I added a 2nd private function.
1954  */
1955 
1956 /* horizontal segment of scan line y */
1957 struct seg {int y, xl, xr, dy;};
1958 
1959 /* max depth of stack */
1960 #define FILL_MAX ((int)(im->sy*im->sx)/4)
1961 #define FILL_PUSH(Y, XL, XR, DY) \
1962     if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
1963     {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
1964 
1965 #define FILL_POP(Y, XL, XR, DY) \
1966     {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
1967 
1968 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
1969 
gdImageFill(gdImagePtr im,int x,int y,int nc)1970 void gdImageFill(gdImagePtr im, int x, int y, int nc)
1971 {
1972 	int l, x1, x2, dy;
1973 	int oc;   /* old pixel value */
1974 	int wx2,wy2;
1975 
1976 	int alphablending_bak;
1977 
1978 	/* stack of filled segments */
1979 	/* struct seg stack[FILL_MAX],*sp = stack; */
1980 	struct seg *stack = NULL;
1981 	struct seg *sp;
1982 
1983 	if (!im->trueColor && nc > (im->colorsTotal -1)) {
1984 		return;
1985 	}
1986 
1987 	alphablending_bak = im->alphaBlendingFlag;
1988 	im->alphaBlendingFlag = 0;
1989 
1990 	if (nc==gdTiled){
1991 		_gdImageFillTiled(im,x,y,nc);
1992 		im->alphaBlendingFlag = alphablending_bak;
1993 		return;
1994 	}
1995 
1996 	wx2=im->sx;wy2=im->sy;
1997 	oc = gdImageGetPixel(im, x, y);
1998 	if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
1999 		im->alphaBlendingFlag = alphablending_bak;
2000 		return;
2001 	}
2002 
2003 	/* Do not use the 4 neighbors implementation with
2004 	 * small images
2005 	 */
2006 	if (im->sx < 4) {
2007 		int ix = x, iy = y, c;
2008 		do {
2009 			do {
2010 				c = gdImageGetPixel(im, ix, iy);
2011 				if (c != oc) {
2012 					goto done;
2013 				}
2014 				gdImageSetPixel(im, ix, iy, nc);
2015 			} while(ix++ < (im->sx -1));
2016 			ix = x;
2017 		} while(iy++ < (im->sy -1));
2018 		goto done;
2019 	}
2020 
2021 	stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
2022 	sp = stack;
2023 
2024 	/* required! */
2025 	FILL_PUSH(y,x,x,1);
2026 	/* seed segment (popped 1st) */
2027  	FILL_PUSH(y+1, x, x, -1);
2028 	while (sp>stack) {
2029 		FILL_POP(y, x1, x2, dy);
2030 
2031 		for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
2032 			gdImageSetPixel(im,x, y, nc);
2033 		}
2034 		if (x>=x1) {
2035 			goto skip;
2036 		}
2037 		l = x+1;
2038 
2039                 /* leak on left? */
2040 		if (l<x1) {
2041 			FILL_PUSH(y, l, x1-1, -dy);
2042 		}
2043 		x = x1+1;
2044 		do {
2045 			for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
2046 				gdImageSetPixel(im, x, y, nc);
2047 			}
2048 			FILL_PUSH(y, l, x-1, dy);
2049 			/* leak on right? */
2050 			if (x>x2+1) {
2051 				FILL_PUSH(y, x2+1, x-1, -dy);
2052 			}
2053 skip:
2054 			for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
2055 
2056 			l = x;
2057 		} while (x<=x2);
2058 	}
2059 
2060 	efree(stack);
2061 
2062 done:
2063 	im->alphaBlendingFlag = alphablending_bak;
2064 }
2065 
_gdImageFillTiled(gdImagePtr im,int x,int y,int nc)2066 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
2067 {
2068 	int i, l, x1, x2, dy;
2069 	int oc;   /* old pixel value */
2070 	int wx2,wy2;
2071 	/* stack of filled segments */
2072 	struct seg *stack;
2073 	struct seg *sp;
2074 	char **pts;
2075 
2076 	if (!im->tile) {
2077 		return;
2078 	}
2079 
2080 	wx2=im->sx;wy2=im->sy;
2081 
2082 	nc =  gdImageTileGet(im,x,y);
2083 
2084 	pts = (char **) ecalloc(im->sy + 1, sizeof(char *));
2085 	for (i = 0; i < im->sy + 1; i++) {
2086 		pts[i] = (char *) ecalloc(im->sx + 1, sizeof(char));
2087 	}
2088 
2089 	stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
2090 	sp = stack;
2091 
2092 	oc = gdImageGetPixel(im, x, y);
2093 
2094 	/* required! */
2095 	FILL_PUSH(y,x,x,1);
2096 	/* seed segment (popped 1st) */
2097  	FILL_PUSH(y+1, x, x, -1);
2098 	while (sp>stack) {
2099 		FILL_POP(y, x1, x2, dy);
2100 		for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) {
2101 			nc = gdImageTileGet(im,x,y);
2102 			pts[y][x] = 1;
2103 			gdImageSetPixel(im,x, y, nc);
2104 		}
2105 		if (x>=x1) {
2106 			goto skip;
2107 		}
2108 		l = x+1;
2109 
2110 		/* leak on left? */
2111 		if (l<x1) {
2112 			FILL_PUSH(y, l, x1-1, -dy);
2113 		}
2114 		x = x1+1;
2115 		do {
2116 			for(; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc); x++) {
2117 				nc = gdImageTileGet(im,x,y);
2118 				pts[y][x] = 1;
2119 				gdImageSetPixel(im, x, y, nc);
2120 			}
2121 			FILL_PUSH(y, l, x-1, dy);
2122 			/* leak on right? */
2123 			if (x>x2+1) {
2124 				FILL_PUSH(y, x2+1, x-1, -dy);
2125 			}
2126 skip:
2127 			for(x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++);
2128 			l = x;
2129 		} while (x<=x2);
2130 	}
2131 
2132 	for(i = 0; i < im->sy + 1; i++) {
2133 		efree(pts[i]);
2134 	}
2135 
2136 	efree(pts);
2137 	efree(stack);
2138 }
2139 
2140 
2141 
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2142 void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2143 {
2144 	int thick = im->thick;
2145 	int t;
2146 
2147 	if (x1 == x2 && y1 == y2 && thick == 1) {
2148 		gdImageSetPixel(im, x1, y1, color);
2149 		return;
2150 	}
2151 
2152 	if (y2 < y1) {
2153 		t=y1;
2154 		y1 = y2;
2155 		y2 = t;
2156 	}
2157 
2158 	if (x2 < x1) {
2159 		t = x1;
2160 		x1 = x2;
2161 		x2 = t;
2162 	}
2163 
2164 	if (thick > 1) {
2165 		int cx, cy, x1ul, y1ul, x2lr, y2lr;
2166 		int half = thick >> 1;
2167 
2168 		x1ul = x1 - half;
2169 		y1ul = y1 - half;
2170 
2171 		x2lr = x2 + half;
2172 		y2lr = y2 + half;
2173 
2174 		cy = y1ul + thick;
2175 		while (cy-- > y1ul) {
2176 			cx = x1ul - 1;
2177 			while (cx++ < x2lr) {
2178 				gdImageSetPixel(im, cx, cy, color);
2179 			}
2180 		}
2181 
2182 		cy = y2lr - thick;
2183 		while (cy++ < y2lr) {
2184 			cx = x1ul - 1;
2185 			while (cx++ < x2lr) {
2186 				gdImageSetPixel(im, cx, cy, color);
2187 			}
2188 		}
2189 
2190 		cy = y1ul + thick - 1;
2191 		while (cy++ < y2lr -thick) {
2192 			cx = x1ul - 1;
2193 			while (cx++ < x1ul + thick) {
2194 				gdImageSetPixel(im, cx, cy, color);
2195 			}
2196 		}
2197 
2198 		cy = y1ul + thick - 1;
2199 		while (cy++ < y2lr -thick) {
2200 			cx = x2lr - thick - 1;
2201 			while (cx++ < x2lr) {
2202 				gdImageSetPixel(im, cx, cy, color);
2203 			}
2204 		}
2205 
2206 		return;
2207 	} else {
2208 		if (x1 == x2 || y1 == y2) {
2209 			gdImageLine(im, x1, y1, x2, y2, color);
2210 		} else {
2211 			gdImageLine(im, x1, y1, x2, y1, color);
2212 			gdImageLine(im, x1, y2, x2, y2, color);
2213 			gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color);
2214 			gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color);
2215 		}
2216 	}
2217 }
2218 
_gdImageFilledHRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2219 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2220 {
2221 	int x, y;
2222 
2223 	if (x1 == x2 && y1 == y2) {
2224 		gdImageSetPixel(im, x1, y1, color);
2225 		return;
2226 	}
2227 
2228 	if (x1 > x2) {
2229 		x = x1;
2230 		x1 = x2;
2231 		x2 = x;
2232 	}
2233 
2234 	if (y1 > y2) {
2235 		y = y1;
2236 		y1 = y2;
2237 		y2 = y;
2238 	}
2239 
2240 	if (x1 < 0) {
2241 		x1 = 0;
2242 	}
2243 
2244 	if (x2 >= gdImageSX(im)) {
2245 		x2 = gdImageSX(im) - 1;
2246 	}
2247 
2248 	if (y1 < 0) {
2249 		y1 = 0;
2250 	}
2251 
2252 	if (y2 >= gdImageSY(im)) {
2253 		y2 = gdImageSY(im) - 1;
2254 	}
2255 
2256 	for (x = x1; (x <= x2); x++) {
2257 		for (y = y1; (y <= y2); y++) {
2258 			gdImageSetPixel (im, x, y, color);
2259 		}
2260 	}
2261 }
2262 
_gdImageFilledVRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2263 static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2264 {
2265 	int x, y;
2266 
2267 	if (x1 == x2 && y1 == y2) {
2268 		gdImageSetPixel(im, x1, y1, color);
2269 		return;
2270 	}
2271 
2272 	if (x1 > x2) {
2273 		x = x1;
2274 		x1 = x2;
2275 		x2 = x;
2276 	}
2277 
2278 	if (y1 > y2) {
2279 		y = y1;
2280 		y1 = y2;
2281 		y2 = y;
2282 	}
2283 
2284 	if (x1 < 0) {
2285 		x1 = 0;
2286 	}
2287 
2288 	if (x2 >= gdImageSX(im)) {
2289 		x2 = gdImageSX(im) - 1;
2290 	}
2291 
2292 	if (y1 < 0) {
2293 		y1 = 0;
2294 	}
2295 
2296 	if (y2 >= gdImageSY(im)) {
2297 		y2 = gdImageSY(im) - 1;
2298 	}
2299 
2300 	for (y = y1; (y <= y2); y++) {
2301 		for (x = x1; (x <= x2); x++) {
2302 			gdImageSetPixel (im, x, y, color);
2303 		}
2304 	}
2305 }
2306 
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2307 void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2308 {
2309 	_gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
2310 }
2311 
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)2312 void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
2313 {
2314 	int c;
2315 	int x, y;
2316 	int tox, toy;
2317 	int i;
2318 	int colorMap[gdMaxColors];
2319 
2320 	if (dst->trueColor) {
2321 		/* 2.0: much easier when the destination is truecolor. */
2322 		/* 2.0.10: needs a transparent-index check that is still valid if
2323 		 * the source is not truecolor. Thanks to Frank Warmerdam.
2324 		 */
2325 
2326 		if (src->trueColor) {
2327 			for (y = 0; (y < h); y++) {
2328 				for (x = 0; (x < w); x++) {
2329 					int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
2330 					if (c != src->transparent) {
2331 						gdImageSetPixel (dst, dstX + x, dstY + y, c);
2332 					}
2333 				}
2334 			}
2335 		} else {
2336 			/* source is palette based */
2337 			for (y = 0; (y < h); y++) {
2338 				for (x = 0; (x < w); x++) {
2339 					int c = gdImageGetPixel (src, srcX + x, srcY + y);
2340 					if (c != src->transparent) {
2341 						gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
2342 					}
2343 				}
2344 			}
2345 		}
2346 		return;
2347 	}
2348 
2349 	/* Palette based to palette based */
2350 	for (i = 0; i < gdMaxColors; i++) {
2351 		colorMap[i] = (-1);
2352 	}
2353 	toy = dstY;
2354 	for (y = srcY; y < (srcY + h); y++) {
2355 		tox = dstX;
2356 		for (x = srcX; x < (srcX + w); x++) {
2357 			int nc;
2358 			int mapTo;
2359 			c = gdImageGetPixel (src, x, y);
2360 			/* Added 7/24/95: support transparent copies */
2361 			if (gdImageGetTransparent (src) == c) {
2362 				tox++;
2363 				continue;
2364 			}
2365 			/* Have we established a mapping for this color? */
2366 			if (src->trueColor) {
2367 				/* 2.05: remap to the palette available in the destination image. This is slow and
2368 				 * works badly, but it beats crashing! Thanks to Padhrig McCarthy.
2369 				 */
2370 				mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c));
2371 			} else if (colorMap[c] == (-1)) {
2372 				/* If it's the same image, mapping is trivial */
2373 				if (dst == src) {
2374 					nc = c;
2375 				} else {
2376 					/* Get best match possible. This function never returns error. */
2377 					nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]);
2378 				}
2379 				colorMap[c] = nc;
2380 				mapTo = colorMap[c];
2381 			} else {
2382 				mapTo = colorMap[c];
2383 			}
2384 			gdImageSetPixel (dst, tox, toy, mapTo);
2385 			tox++;
2386 		}
2387 		toy++;
2388 	}
2389 }
2390 
2391 /* This function is a substitute for real alpha channel operations,
2392    so it doesn't pay attention to the alpha channel. */
gdImageCopyMerge(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)2393 void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2394 {
2395 	int c, dc;
2396 	int x, y;
2397 	int tox, toy;
2398 	int ncR, ncG, ncB;
2399 	toy = dstY;
2400 
2401 	for (y = srcY; y < (srcY + h); y++) {
2402 		tox = dstX;
2403 		for (x = srcX; x < (srcX + w); x++) {
2404 			int nc;
2405 			c = gdImageGetPixel(src, x, y);
2406 			/* Added 7/24/95: support transparent copies */
2407 			if (gdImageGetTransparent(src) == c) {
2408 				tox++;
2409 				continue;
2410 			}
2411 			/* If it's the same image, mapping is trivial */
2412 			if (dst == src) {
2413 				nc = c;
2414 			} else {
2415 				dc = gdImageGetPixel(dst, tox, toy);
2416 
2417  				ncR = (int)(gdImageRed (src, c) * (pct / 100.0) + gdImageRed (dst, dc) * ((100 - pct) / 100.0));
2418  				ncG = (int)(gdImageGreen (src, c) * (pct / 100.0) + gdImageGreen (dst, dc) * ((100 - pct) / 100.0));
2419  				ncB = (int)(gdImageBlue (src, c) * (pct / 100.0) + gdImageBlue (dst, dc) * ((100 - pct) / 100.0));
2420 
2421 				/* Find a reasonable color */
2422 				nc = gdImageColorResolve (dst, ncR, ncG, ncB);
2423 			}
2424 			gdImageSetPixel (dst, tox, toy, nc);
2425 			tox++;
2426 		}
2427 		toy++;
2428 	}
2429 }
2430 
2431 /* This function is a substitute for real alpha channel operations,
2432    so it doesn't pay attention to the alpha channel. */
gdImageCopyMergeGray(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)2433 void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2434 {
2435 	int c, dc;
2436 	int x, y;
2437 	int tox, toy;
2438 	int ncR, ncG, ncB;
2439 	float g;
2440 	toy = dstY;
2441 
2442 	for (y = srcY; (y < (srcY + h)); y++) {
2443 		tox = dstX;
2444 		for (x = srcX; (x < (srcX + w)); x++) {
2445 			int nc;
2446 			c = gdImageGetPixel (src, x, y);
2447 			/* Added 7/24/95: support transparent copies */
2448 			if (gdImageGetTransparent(src) == c) {
2449 				tox++;
2450 				continue;
2451 			}
2452 
2453 			/*
2454 			 * If it's the same image, mapping is NOT trivial since we
2455 			 * merge with greyscale target, but if pct is 100, the grey
2456 			 * value is not used, so it becomes trivial. pjw 2.0.12.
2457 			 */
2458 			if (dst == src && pct == 100) {
2459 				nc = c;
2460 			} else {
2461 				dc = gdImageGetPixel(dst, tox, toy);
2462 				g = (0.29900f * gdImageRed(dst, dc)) + (0.58700f * gdImageGreen(dst, dc)) + (0.11400f * gdImageBlue(dst, dc));
2463 
2464 				ncR = (int)(gdImageRed (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2465 				ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2466 				ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2467 
2468 
2469 				/* First look for an exact match */
2470 				nc = gdImageColorExact(dst, ncR, ncG, ncB);
2471 				if (nc == (-1)) {
2472 					/* No, so try to allocate it */
2473 					nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
2474 					/* If we're out of colors, go for the closest color */
2475 					if (nc == (-1)) {
2476 						nc = gdImageColorClosest(dst, ncR, ncG, ncB);
2477 					}
2478 				}
2479 			}
2480 			gdImageSetPixel(dst, tox, toy, nc);
2481 			tox++;
2482 		}
2483 		toy++;
2484 	}
2485 }
2486 
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2487 void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2488 {
2489 	int c;
2490 	int x, y;
2491 	int tox, toy;
2492 	int ydest;
2493 	int i;
2494 	int colorMap[gdMaxColors];
2495 	/* Stretch vectors */
2496 	int *stx, *sty;
2497 
2498 	if (overflow2(sizeof(int), srcW)) {
2499 		return;
2500 	}
2501 	if (overflow2(sizeof(int), srcH)) {
2502 		return;
2503 	}
2504 
2505 	stx = (int *) gdMalloc (sizeof (int) * srcW);
2506 	sty = (int *) gdMalloc (sizeof (int) * srcH);
2507 
2508 	/* Fixed by Mao Morimoto 2.0.16 */
2509 	for (i = 0; (i < srcW); i++) {
2510 		stx[i] = dstW * (i+1) / srcW - dstW * i / srcW ;
2511 	}
2512 	for (i = 0; (i < srcH); i++) {
2513 		sty[i] = dstH * (i+1) / srcH - dstH * i / srcH ;
2514 	}
2515 	for (i = 0; (i < gdMaxColors); i++) {
2516 		colorMap[i] = (-1);
2517 	}
2518 	toy = dstY;
2519 	for (y = srcY; (y < (srcY + srcH)); y++) {
2520 		for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
2521 			tox = dstX;
2522 			for (x = srcX; (x < (srcX + srcW)); x++) {
2523 				int nc = 0;
2524 				int mapTo;
2525 				if (!stx[x - srcX]) {
2526 					continue;
2527 				}
2528 				if (dst->trueColor) {
2529 					/* 2.0.9: Thorben Kundinger: Maybe the source image is not a truecolor image */
2530 					if (!src->trueColor) {
2531 					  	int tmp = gdImageGetPixel (src, x, y);
2532 		  				mapTo = gdImageGetTrueColorPixel (src, x, y);
2533 					  	if (gdImageGetTransparent (src) == tmp) {
2534 							/* 2.0.21, TK: not tox++ */
2535 							tox += stx[x - srcX];
2536 					  		continue;
2537 					  	}
2538 					} else {
2539 						/* TK: old code follows */
2540 					  	mapTo = gdImageGetTrueColorPixel (src, x, y);
2541 						/* Added 7/24/95: support transparent copies */
2542 						if (gdImageGetTransparent (src) == mapTo) {
2543 							/* 2.0.21, TK: not tox++ */
2544 							tox += stx[x - srcX];
2545 							continue;
2546 						}
2547 					}
2548 				} else {
2549 					c = gdImageGetPixel (src, x, y);
2550 					/* Added 7/24/95: support transparent copies */
2551 					if (gdImageGetTransparent (src) == c) {
2552 					      tox += stx[x - srcX];
2553 					      continue;
2554 					}
2555 					if (src->trueColor) {
2556 					      /* Remap to the palette available in the destination image. This is slow and works badly. */
2557 					      mapTo = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c),
2558 					      					    gdTrueColorGetGreen(c),
2559 					      					    gdTrueColorGetBlue(c),
2560 					      					    gdTrueColorGetAlpha (c));
2561 					} else {
2562 						/* Have we established a mapping for this color? */
2563 						if (colorMap[c] == (-1)) {
2564 							/* If it's the same image, mapping is trivial */
2565 							if (dst == src) {
2566 								nc = c;
2567 							} else {
2568 								/* Find or create the best match */
2569 								/* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
2570 								nc = gdImageColorResolveAlpha(dst, gdImageRed(src, c),
2571 												   gdImageGreen(src, c),
2572 												   gdImageBlue(src, c),
2573 												   gdImageAlpha(src, c));
2574 							}
2575 							colorMap[c] = nc;
2576 						}
2577 						mapTo = colorMap[c];
2578 					}
2579 				}
2580 				for (i = 0; (i < stx[x - srcX]); i++) {
2581 					gdImageSetPixel (dst, tox, toy, mapTo);
2582 					tox++;
2583 				}
2584 			}
2585 			toy++;
2586 		}
2587 	}
2588 	gdFree (stx);
2589 	gdFree (sty);
2590 }
2591 
2592 /* When gd 1.x was first created, floating point was to be avoided.
2593    These days it is often faster than table lookups or integer
2594    arithmetic. The routine below is shamelessly, gloriously
2595    floating point. TBB */
2596 
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2597 void gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2598 {
2599 	int x, y;
2600 	double sy1, sy2, sx1, sx2;
2601 
2602 	if (!dst->trueColor) {
2603 		gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
2604 		return;
2605 	}
2606 	for (y = dstY; (y < dstY + dstH); y++) {
2607 		sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
2608 		sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
2609 		for (x = dstX; (x < dstX + dstW); x++) {
2610 			double sx, sy;
2611 			double spixels = 0;
2612 			double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
2613 			double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
2614 			sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
2615 			sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
2616 			sy = sy1;
2617 			do {
2618 				double yportion;
2619 				if (floor_cast(sy) == floor_cast(sy1)) {
2620 					yportion = 1.0f - (sy - floor_cast(sy));
2621 					if (yportion > sy2 - sy1) {
2622 						yportion = sy2 - sy1;
2623 					}
2624 					sy = floor_cast(sy);
2625 				} else if (sy == floorf(sy2)) {
2626 					yportion = sy2 - floor_cast(sy2);
2627 				} else {
2628 					yportion = 1.0f;
2629 				}
2630 				sx = sx1;
2631 				do {
2632 					double xportion;
2633 					double pcontribution;
2634 					int p;
2635 					if (floorf(sx) == floor_cast(sx1)) {
2636 						xportion = 1.0f - (sx - floor_cast(sx));
2637 						if (xportion > sx2 - sx1) {
2638 							xportion = sx2 - sx1;
2639 						}
2640 						sx = floor_cast(sx);
2641 					} else if (sx == floorf(sx2)) {
2642 						xportion = sx2 - floor_cast(sx2);
2643 					} else {
2644 						xportion = 1.0f;
2645 					}
2646 					pcontribution = xportion * yportion;
2647 					p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
2648 
2649 					alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
2650 					red += gdTrueColorGetRed (p) * alpha_factor;
2651 					green += gdTrueColorGetGreen (p) * alpha_factor;
2652 					blue += gdTrueColorGetBlue (p) * alpha_factor;
2653 					alpha += gdTrueColorGetAlpha (p) * pcontribution;
2654 					alpha_sum += alpha_factor;
2655 					contrib_sum += pcontribution;
2656 					spixels += xportion * yportion;
2657 					sx += 1.0f;
2658 				}
2659 				while (sx < sx2);
2660 
2661 				sy += 1.0f;
2662 			}
2663 
2664 			while (sy < sy2);
2665 
2666 			if (spixels != 0.0f) {
2667 				red /= spixels;
2668 				green /= spixels;
2669 				blue /= spixels;
2670 				alpha /= spixels;
2671 			}
2672 			if ( alpha_sum != 0.0f) {
2673 				if( contrib_sum != 0.0f) {
2674 					alpha_sum /= contrib_sum;
2675 				}
2676 				red /= alpha_sum;
2677 				green /= alpha_sum;
2678 				blue /= alpha_sum;
2679 			}
2680 			/* Round up closest next channel value and clamp to max channel value */
2681 			red = red >= 255.5 ? 255 : red+0.5;
2682 			blue = blue >= 255.5 ? 255 : blue+0.5;
2683 			green = green >= 255.5 ? 255 : green+0.5;
2684 			alpha = alpha >= gdAlphaMax+0.5 ? gdAlphaMax : alpha+0.5;
2685 			gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int)red, (int)green, (int)blue, (int)alpha));
2686 		}
2687 	}
2688 }
2689 
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)2690 void gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2691 {
2692 	if (n <= 0) {
2693 		return;
2694 	}
2695 
2696 
2697 	gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
2698 	gdImageOpenPolygon (im, p, n, c);
2699 }
2700 
gdImageOpenPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2701 void gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2702 {
2703 	int i;
2704 	int lx, ly;
2705 
2706 	if (n <= 0) {
2707 		return;
2708 	}
2709 
2710 	lx = p->x;
2711 	ly = p->y;
2712 	for (i = 1; i < n; i++) {
2713 		p++;
2714 		gdImageLine(im, lx, ly, p->x, p->y, c);
2715 		lx = p->x;
2716 		ly = p->y;
2717 	}
2718 }
2719 
2720 int gdCompareInt (const void *a, const void *b);
2721 
2722 /* THANKS to Kirsten Schulz for the polygon fixes! */
2723 
2724 /* The intersection finding technique of this code could be improved
2725  * by remembering the previous intertersection, and by using the slope.
2726  * That could help to adjust intersections  to produce a nice
2727  * interior_extrema.
2728  */
2729 
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2730 void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2731 {
2732 	int i;
2733 	int y;
2734 	int miny, maxy, pmaxy;
2735 	int x1, y1;
2736 	int x2, y2;
2737 	int ind1, ind2;
2738 	int ints;
2739 	int fill_color;
2740 
2741 	if (n <= 0) {
2742 		return;
2743 	}
2744 
2745 	if (overflow2(sizeof(int), n)) {
2746 		return;
2747 	}
2748 
2749 	if (c == gdAntiAliased) {
2750 		fill_color = im->AA_color;
2751 	} else {
2752 		fill_color = c;
2753 	}
2754 
2755 	if (!im->polyAllocated) {
2756 		im->polyInts = (int *) gdMalloc(sizeof(int) * n);
2757 		im->polyAllocated = n;
2758 	}
2759 	if (im->polyAllocated < n) {
2760 		while (im->polyAllocated < n) {
2761 			im->polyAllocated *= 2;
2762 		}
2763 		if (overflow2(sizeof(int), im->polyAllocated)) {
2764 			return;
2765 		}
2766 		im->polyInts = (int *) gdRealloc(im->polyInts, sizeof(int) * im->polyAllocated);
2767 	}
2768 	miny = p[0].y;
2769 	maxy = p[0].y;
2770 	for (i = 1; i < n; i++) {
2771 		if (p[i].y < miny) {
2772 			miny = p[i].y;
2773 		}
2774 		if (p[i].y > maxy) {
2775 			maxy = p[i].y;
2776 		}
2777 	}
2778 	/* necessary special case: horizontal line */
2779 	if (n > 1 && miny == maxy) {
2780 		x1 = x2 = p[0].x;
2781 		for (i = 1; (i < n); i++) {
2782 			if (p[i].x < x1) {
2783 				x1 = p[i].x;
2784 			} else if (p[i].x > x2) {
2785 				x2 = p[i].x;
2786 			}
2787 		}
2788 		gdImageLine(im, x1, miny, x2, miny, c);
2789 		return;
2790 	}
2791 	pmaxy = maxy;
2792 	/* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
2793 	if (miny < 0) {
2794 		miny = 0;
2795 	}
2796 	if (maxy >= gdImageSY(im)) {
2797 		maxy = gdImageSY(im) - 1;
2798 	}
2799 
2800 	/* Fix in 1.3: count a vertex only once */
2801 	for (y = miny; y <= maxy; y++) {
2802 		/*1.4           int interLast = 0; */
2803 		/*              int dirLast = 0; */
2804 		/*              int interFirst = 1; */
2805 		ints = 0;
2806 		for (i = 0; i < n; i++) {
2807 			if (!i) {
2808 				ind1 = n - 1;
2809 				ind2 = 0;
2810 			} else {
2811 				ind1 = i - 1;
2812 				ind2 = i;
2813 			}
2814 			y1 = p[ind1].y;
2815 			y2 = p[ind2].y;
2816 			if (y1 < y2) {
2817 				x1 = p[ind1].x;
2818 				x2 = p[ind2].x;
2819 			} else if (y1 > y2) {
2820 				y2 = p[ind1].y;
2821 				y1 = p[ind2].y;
2822 				x2 = p[ind1].x;
2823 				x1 = p[ind2].x;
2824 			} else {
2825 				continue;
2826 			}
2827 			/* Do the following math as float intermediately, and round to ensure
2828 			 * that Polygon and FilledPolygon for the same set of points have the
2829 			 * same footprint.
2830 			 */
2831 			if (y >= y1 && y < y2) {
2832 				im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
2833 			} else if (y == pmaxy && y == y2) {
2834 				im->polyInts[ints++] = x2;
2835 			}
2836 		}
2837 		qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2838 
2839 		for (i = 0; i < ints - 1; i += 2) {
2840 			gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, fill_color);
2841 		}
2842 	}
2843 
2844 	/* If we are drawing this AA, then redraw the border with AA lines. */
2845 	if (c == gdAntiAliased) {
2846 		gdImagePolygon(im, p, n, c);
2847 	}
2848 }
2849 
gdCompareInt(const void * a,const void * b)2850 int gdCompareInt (const void *a, const void *b)
2851 {
2852 	return (*(const int *) a) - (*(const int *) b);
2853 }
2854 
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)2855 void gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
2856 {
2857 	if (im->style) {
2858 		gdFree(im->style);
2859 	}
2860 	if (overflow2(sizeof (int), noOfPixels)) {
2861 		return;
2862 	}
2863 	im->style = (int *) gdMalloc(sizeof(int) * noOfPixels);
2864 	memcpy(im->style, style, sizeof(int) * noOfPixels);
2865 	im->styleLength = noOfPixels;
2866 	im->stylePos = 0;
2867 }
2868 
gdImageSetThickness(gdImagePtr im,int thickness)2869 void gdImageSetThickness (gdImagePtr im, int thickness)
2870 {
2871 	im->thick = thickness;
2872 }
2873 
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)2874 void gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
2875 {
2876 	int i;
2877 	im->brush = brush;
2878 	if (!im->trueColor && !im->brush->trueColor) {
2879 		for (i = 0; i < gdImageColorsTotal(brush); i++) {
2880 			int index;
2881 			index = gdImageColorResolveAlpha(im, gdImageRed(brush, i), gdImageGreen(brush, i), gdImageBlue(brush, i), gdImageAlpha(brush, i));
2882 			im->brushColorMap[i] = index;
2883 		}
2884 	}
2885 }
2886 
gdImageSetTile(gdImagePtr im,gdImagePtr tile)2887 void gdImageSetTile (gdImagePtr im, gdImagePtr tile)
2888 {
2889 	int i;
2890 	im->tile = tile;
2891 	if (!im->trueColor && !im->tile->trueColor) {
2892 		for (i = 0; i < gdImageColorsTotal(tile); i++) {
2893 			int index;
2894 			index = gdImageColorResolveAlpha(im, gdImageRed(tile, i), gdImageGreen(tile, i), gdImageBlue(tile, i), gdImageAlpha(tile, i));
2895 			im->tileColorMap[i] = index;
2896 		}
2897 	}
2898 }
2899 
gdImageSetAntiAliased(gdImagePtr im,int c)2900 void gdImageSetAntiAliased (gdImagePtr im, int c)
2901 {
2902 	im->AA = 1;
2903 	im->AA_color = c;
2904 	im->AA_dont_blend = -1;
2905 }
2906 
gdImageSetAntiAliasedDontBlend(gdImagePtr im,int c,int dont_blend)2907 void gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
2908 {
2909 	im->AA = 1;
2910 	im->AA_color = c;
2911 	im->AA_dont_blend = dont_blend;
2912 }
2913 
2914 
gdImageInterlace(gdImagePtr im,int interlaceArg)2915 void gdImageInterlace (gdImagePtr im, int interlaceArg)
2916 {
2917 	im->interlace = interlaceArg;
2918 }
2919 
gdImageCompare(gdImagePtr im1,gdImagePtr im2)2920 int gdImageCompare (gdImagePtr im1, gdImagePtr im2)
2921 {
2922 	int x, y;
2923 	int p1, p2;
2924 	int cmpStatus = 0;
2925 	int sx, sy;
2926 
2927 	if (im1->interlace != im2->interlace) {
2928 		cmpStatus |= GD_CMP_INTERLACE;
2929 	}
2930 
2931 	if (im1->transparent != im2->transparent) {
2932 		cmpStatus |= GD_CMP_TRANSPARENT;
2933 	}
2934 
2935 	if (im1->trueColor != im2->trueColor) {
2936 		cmpStatus |= GD_CMP_TRUECOLOR;
2937 	}
2938 
2939 	sx = im1->sx;
2940 	if (im1->sx != im2->sx) {
2941 		cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
2942 		if (im2->sx < im1->sx) {
2943 			sx = im2->sx;
2944 		}
2945 	}
2946 
2947 	sy = im1->sy;
2948 	if (im1->sy != im2->sy) {
2949 		cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
2950 		if (im2->sy < im1->sy) {
2951 			sy = im2->sy;
2952 		}
2953 	}
2954 
2955 	if (im1->colorsTotal != im2->colorsTotal) {
2956 		cmpStatus |= GD_CMP_NUM_COLORS;
2957 	}
2958 
2959 	for (y = 0; y < sy; y++) {
2960 		for (x = 0; x < sx; x++) {
2961 			p1 = im1->trueColor ? gdImageTrueColorPixel(im1, x, y) : gdImagePalettePixel(im1, x, y);
2962 			p2 = im2->trueColor ? gdImageTrueColorPixel(im2, x, y) : gdImagePalettePixel(im2, x, y);
2963 
2964 			if (gdImageRed(im1, p1) != gdImageRed(im2, p2)) {
2965 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2966 				break;
2967 			}
2968 			if (gdImageGreen(im1, p1) != gdImageGreen(im2, p2)) {
2969 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2970 				break;
2971 			}
2972 			if (gdImageBlue(im1, p1) != gdImageBlue(im2, p2)) {
2973 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2974 				break;
2975 			}
2976 #if 0
2977 			/* Soon we'll add alpha channel to palettes */
2978 			if (gdImageAlpha(im1, p1) != gdImageAlpha(im2, p2)) {
2979 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2980 				break;
2981 			}
2982 #endif
2983 		}
2984 		if (cmpStatus & GD_CMP_COLOR) {
2985 			break;
2986 		}
2987 	}
2988 
2989 	return cmpStatus;
2990 }
2991 
gdAlphaBlend(int dst,int src)2992 int gdAlphaBlend (int dst, int src) {
2993     int src_alpha = gdTrueColorGetAlpha(src);
2994     int dst_alpha, alpha, red, green, blue;
2995     int src_weight, dst_weight, tot_weight;
2996 
2997 /* -------------------------------------------------------------------- */
2998 /*      Simple cases we want to handle fast.                            */
2999 /* -------------------------------------------------------------------- */
3000     if( src_alpha == gdAlphaOpaque )
3001         return src;
3002 
3003     dst_alpha = gdTrueColorGetAlpha(dst);
3004     if( src_alpha == gdAlphaTransparent )
3005         return dst;
3006     if( dst_alpha == gdAlphaTransparent )
3007         return src;
3008 
3009 /* -------------------------------------------------------------------- */
3010 /*      What will the source and destination alphas be?  Note that      */
3011 /*      the destination weighting is substantially reduced as the       */
3012 /*      overlay becomes quite opaque.                                   */
3013 /* -------------------------------------------------------------------- */
3014     src_weight = gdAlphaTransparent - src_alpha;
3015     dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
3016     tot_weight = src_weight + dst_weight;
3017 
3018 /* -------------------------------------------------------------------- */
3019 /*      What red, green and blue result values will we use?             */
3020 /* -------------------------------------------------------------------- */
3021     alpha = src_alpha * dst_alpha / gdAlphaMax;
3022 
3023     red = (gdTrueColorGetRed(src) * src_weight
3024            + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
3025     green = (gdTrueColorGetGreen(src) * src_weight
3026            + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
3027     blue = (gdTrueColorGetBlue(src) * src_weight
3028            + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
3029 
3030 /* -------------------------------------------------------------------- */
3031 /*      Return merged result.                                           */
3032 /* -------------------------------------------------------------------- */
3033     return ((alpha << 24) + (red << 16) + (green << 8) + blue);
3034 
3035 }
3036 
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)3037 void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
3038 {
3039 	im->alphaBlendingFlag = alphaBlendingArg;
3040 }
3041 
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)3042 void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
3043 {
3044 	im->saveAlphaFlag = saveAlphaArg;
3045 }
3046 
gdLayerOverlay(int dst,int src)3047 int gdLayerOverlay (int dst, int src)
3048 {
3049 	int a1, a2;
3050 	a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
3051 	a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
3052 	return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
3053 		(gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
3054 		(gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
3055 		(gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
3056 		);
3057 }
3058 
gdAlphaOverlayColor(int src,int dst,int max)3059 static int gdAlphaOverlayColor (int src, int dst, int max )
3060 {
3061 	/* this function implements the algorithm
3062 	 *
3063 	 * for dst[rgb] < 0.5,
3064 	 *   c[rgb] = 2.src[rgb].dst[rgb]
3065 	 * and for dst[rgb] > 0.5,
3066 	 *   c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
3067 	 *
3068 	 */
3069 
3070 	dst = dst << 1;
3071 	if( dst > max ) {
3072 		/* in the "light" zone */
3073 		return dst + (src << 1) - (dst * src / max) - max;
3074 	} else {
3075 		/* in the "dark" zone */
3076 		return dst * src / max;
3077 	}
3078 }
3079 
gdLayerMultiply(int dst,int src)3080 int gdLayerMultiply (int dst, int src)
3081 {
3082 	int a1, a2, r1, r2, g1, g2, b1, b2;
3083 	a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
3084 	a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
3085 
3086 	r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
3087 	r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
3088 	g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
3089 	g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
3090 	b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
3091 	b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
3092 
3093 	a1 = gdAlphaMax - a1;
3094 	a2 = gdAlphaMax - a2;
3095 	return ( ((a1*a2/gdAlphaMax) << 24) +
3096 			 ((r1*r2/gdRedMax) << 16) +
3097 			 ((g1*g2/gdGreenMax) << 8) +
3098 			 ((b1*b2/gdBlueMax))
3099 		);
3100 }
3101 
gdImageSetClip(gdImagePtr im,int x1,int y1,int x2,int y2)3102 void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
3103 {
3104 	if (x1 < 0) {
3105 		x1 = 0;
3106 	}
3107 	if (x1 >= im->sx) {
3108 		x1 = im->sx - 1;
3109 	}
3110 	if (x2 < 0) {
3111 		x2 = 0;
3112 	}
3113 	if (x2 >= im->sx) {
3114 		x2 = im->sx - 1;
3115 	}
3116 	if (y1 < 0) {
3117 		y1 = 0;
3118 	}
3119 	if (y1 >= im->sy) {
3120 		y1 = im->sy - 1;
3121 	}
3122 	if (y2 < 0) {
3123 		y2 = 0;
3124 	}
3125 	if (y2 >= im->sy) {
3126 		y2 = im->sy - 1;
3127 	}
3128 	im->cx1 = x1;
3129 	im->cy1 = y1;
3130 	im->cx2 = x2;
3131 	im->cy2 = y2;
3132 }
3133 
gdImageGetClip(gdImagePtr im,int * x1P,int * y1P,int * x2P,int * y2P)3134 void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
3135 {
3136 	*x1P = im->cx1;
3137 	*y1P = im->cy1;
3138 	*x2P = im->cx2;
3139 	*y2P = im->cy2;
3140 }
3141 
gdImageSetResolution(gdImagePtr im,const unsigned int res_x,const unsigned int res_y)3142 void gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
3143 {
3144 	if (res_x > 0) im->res_x = res_x;
3145 	if (res_y > 0) im->res_y = res_y;
3146 }
3147 
3148 /* convert a palette image to true color */
gdImagePaletteToTrueColor(gdImagePtr src)3149 int gdImagePaletteToTrueColor(gdImagePtr src)
3150 {
3151 	unsigned int y;
3152 	unsigned int yy;
3153 
3154 	if (src == NULL) {
3155 		return 0;
3156 	}
3157 
3158 	if (src->trueColor == 1) {
3159 		return 1;
3160 	} else {
3161 		unsigned int x;
3162 		const unsigned int sy = gdImageSY(src);
3163 		const unsigned int sx = gdImageSX(src);
3164 
3165 		// Note: do not revert back to gdMalloc() below ; reason here,
3166 		// due to a bug with a certain memory_limit INI value treshold,
3167 		// imagepalettetotruecolor crashes with even unrelated ZendMM allocations.
3168 		// See GH-17772 for an use case.
3169 		src->tpixels = (int **) gdCalloc(sizeof(int *), sy);
3170 		if (src->tpixels == NULL) {
3171 			return 0;
3172 		}
3173 
3174 		for (y = 0; y < sy; y++) {
3175 			const unsigned char *src_row = src->pixels[y];
3176 			int * dst_row;
3177 
3178 			/* no need to calloc it, we overwrite all pxl anyway */
3179 			src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int));
3180 			if (src->tpixels[y] == NULL) {
3181 				goto clean_on_error;
3182 			}
3183 
3184 			dst_row = src->tpixels[y];
3185 			for (x = 0; x < sx; x++) {
3186 				const unsigned char c = *(src_row + x);
3187 				if (c == src->transparent) {
3188 					*(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
3189 				} else {
3190 					*(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3191 				}
3192 			}
3193 		}
3194 	}
3195 
3196 	/* free old palette buffer (y is sy) */
3197 	for (yy = 0; yy < y; yy++) {
3198 		gdFree(src->pixels[yy]);
3199 	}
3200 	gdFree(src->pixels);
3201 	src->trueColor = 1;
3202 	src->pixels = NULL;
3203 	src->alphaBlendingFlag = 0;
3204 	src->saveAlphaFlag = 1;
3205 
3206 	if (src->transparent >= 0) {
3207 		const unsigned char c = src->transparent;
3208 		src->transparent =  gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3209 	}
3210 
3211 	return 1;
3212 
3213 clean_on_error:
3214 	/* free new true color buffer (y is not allocated, have failed) */
3215 	for (yy = 0; yy < y; yy++) {
3216 		gdFree(src->tpixels[yy]);
3217 	}
3218 	gdFree(src->tpixels);
3219 	return 0;
3220 }
3221