xref: /php-src/ext/gd/libgd/gd.c (revision 307565d5)
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 (im->trueColor) {
934 		if (im->tile->trueColor) {
935 			tileColor = p;
936 		} else {
937 			tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
938 		}
939 	} else {
940 		if (im->tile->trueColor) {
941 			tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
942 		} else {
943 			tileColor = p;
944 			tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
945 		}
946 	}
947 	return tileColor;
948 }
949 
950 
gdImageGetPixel(gdImagePtr im,int x,int y)951 int gdImageGetPixel (gdImagePtr im, int x, int y)
952 {
953 	if (gdImageBoundsSafe(im, x, y)) {
954 		if (im->trueColor) {
955 			return im->tpixels[y][x];
956 		} else {
957 			return im->pixels[y][x];
958 		}
959 	} else {
960 		return 0;
961 	}
962 }
963 
gdImageAABlend(gdImagePtr im)964 void gdImageAABlend (gdImagePtr im)
965 {
966 	(void)im;
967 }
968 
969 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color);
970 
gdImageClone(gdImagePtr src)971 gdImagePtr gdImageClone (gdImagePtr src) {
972 	gdImagePtr dst;
973 	register int i, x;
974 
975 	if (src->trueColor) {
976 		dst = gdImageCreateTrueColor(src->sx , src->sy);
977 	} else {
978 		dst = gdImageCreate(src->sx , src->sy);
979 	}
980 
981 	if (dst == NULL) {
982 		return NULL;
983 	}
984 
985 	if (src->trueColor == 0) {
986 		dst->colorsTotal = src->colorsTotal;
987 		for (i = 0; i < gdMaxColors; i++) {
988 			dst->red[i]   = src->red[i];
989 			dst->green[i] = src->green[i];
990 			dst->blue[i]  = src->blue[i];
991 			dst->alpha[i] = src->alpha[i];
992 			dst->open[i]  = src->open[i];
993 		}
994 		for (i = 0; i < src->sy; i++) {
995 			for (x = 0; x < src->sx; x++) {
996 				dst->pixels[i][x] = src->pixels[i][x];
997 			}
998 		}
999 	} else {
1000 		for (i = 0; i < src->sy; i++) {
1001 			for (x = 0; x < src->sx; x++) {
1002 				dst->tpixels[i][x] = src->tpixels[i][x];
1003 			}
1004 		}
1005 	}
1006 
1007 	dst->interlace   = src->interlace;
1008 
1009 	dst->alphaBlendingFlag = src->alphaBlendingFlag;
1010 	dst->saveAlphaFlag     = src->saveAlphaFlag;
1011 	dst->AA                = src->AA;
1012 	dst->AA_color          = src->AA_color;
1013 	dst->AA_dont_blend     = src->AA_dont_blend;
1014 
1015 	dst->cx1 = src->cx1;
1016 	dst->cy1 = src->cy1;
1017 	dst->cx2 = src->cx2;
1018 	dst->cy2 = src->cy2;
1019 
1020 	dst->res_x = src->res_x;
1021 	dst->res_y = src->res_y;
1022 
1023 	dst->interpolation_id = src->interpolation_id;
1024 	dst->interpolation    = src->interpolation;
1025 
1026 	if (src->brush) {
1027 		dst->brush = gdImageClone(src->brush);
1028 	}
1029 
1030 	if (src->tile) {
1031 		dst->tile = gdImageClone(src->tile);
1032 	}
1033 
1034 	if (src->style) {
1035 		gdImageSetStyle(dst, src->style, src->styleLength);
1036 		dst->stylePos = src->stylePos;
1037 	}
1038 
1039 	for (i = 0; i < gdMaxColors; i++) {
1040 		dst->brushColorMap[i] = src->brushColorMap[i];
1041 		dst->tileColorMap[i] = src->tileColorMap[i];
1042 	}
1043 
1044 	if (src->polyAllocated > 0 && overflow2(sizeof(int), src->polyAllocated) == 0) {
1045 		dst->polyInts = gdMalloc (sizeof (int) * src->polyAllocated);
1046 		dst->polyAllocated = src->polyAllocated;
1047 		for (i = 0; i < src->polyAllocated; i++) {
1048 			dst->polyInts[i] = src->polyInts[i];
1049 		}
1050 	}
1051 
1052 	return dst;
1053 }
1054 
gdImageHLine(gdImagePtr im,int y,int x1,int x2,int col)1055 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
1056 {
1057 	if (im->thick > 1) {
1058 		int thickhalf = im->thick >> 1;
1059 		_gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
1060 	} else {
1061 		if (x2 < x1) {
1062 			int t = x2;
1063 			x2 = x1;
1064 			x1 = t;
1065 		}
1066 
1067 		for (;x1 <= x2; x1++) {
1068 			gdImageSetPixel(im, x1, y, col);
1069 		}
1070 	}
1071 	return;
1072 }
1073 
gdImageVLine(gdImagePtr im,int x,int y1,int y2,int col)1074 static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
1075 {
1076 	if (im->thick > 1) {
1077 		int thickhalf = im->thick >> 1;
1078 		gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
1079 	} else {
1080 		if (y2 < y1) {
1081 			int t = y1;
1082 			y1 = y2;
1083 			y2 = t;
1084 		}
1085 
1086 		for (;y1 <= y2; y1++) {
1087 			gdImageSetPixel(im, x, y1, col);
1088 		}
1089 	}
1090 	return;
1091 }
1092 
1093 /* Bresenham as presented in Foley & Van Dam */
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1094 void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1095 {
1096 	int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1097 	int wid;
1098 	int w, wstart;
1099 	int thick = im->thick;
1100 
1101 	if (color == gdAntiAliased) {
1102 		/*
1103 		   gdAntiAliased passed as color: use the much faster, much cheaper
1104 		   and equally attractive gdImageAALine implementation. That
1105 		   clips too, so don't clip twice.
1106 		   */
1107 		gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
1108 		return;
1109 	}
1110 
1111 	/* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
1112 	if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)-1) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im)-1)) {
1113 		return;
1114 	}
1115 
1116 	dx = abs (x2 - x1);
1117 	dy = abs (y2 - y1);
1118 
1119 	if (dx == 0) {
1120 		gdImageVLine(im, x1, y1, y2, color);
1121 		return;
1122 	} else if (dy == 0) {
1123 		gdImageHLine(im, y1, x1, x2, color);
1124 		return;
1125 	}
1126 
1127 	if (dy <= dx) {
1128 		/* More-or-less horizontal. use wid for vertical stroke */
1129 		/* Doug Claar: watch out for NaN in atan2 (2.0.5) */
1130 		if ((dx == 0) && (dy == 0)) {
1131 			wid = 1;
1132 		} else {
1133 			/* 2.0.12: Michael Schwartz: divide rather than multiply;
1134 TBB: but watch out for /0! */
1135 			double ac = cos (atan2 (dy, dx));
1136 			if (ac != 0) {
1137 				wid = thick / ac;
1138 			} else {
1139 				wid = 1;
1140 			}
1141 			if (wid == 0) {
1142 				wid = 1;
1143 			}
1144 		}
1145 		d = 2 * dy - dx;
1146 		incr1 = 2 * dy;
1147 		incr2 = 2 * (dy - dx);
1148 		if (x1 > x2) {
1149 			x = x2;
1150 			y = y2;
1151 			ydirflag = (-1);
1152 			xend = x1;
1153 		} else {
1154 			x = x1;
1155 			y = y1;
1156 			ydirflag = 1;
1157 			xend = x2;
1158 		}
1159 
1160 		/* Set up line thickness */
1161 		wstart = y - wid / 2;
1162 		for (w = wstart; w < wstart + wid; w++) {
1163 			gdImageSetPixel(im, x, w, color);
1164 		}
1165 
1166 		if (((y2 - y1) * ydirflag) > 0) {
1167 			while (x < xend) {
1168 				x++;
1169 				if (d < 0) {
1170 					d += incr1;
1171 				} else {
1172 					y++;
1173 					d += incr2;
1174 				}
1175 				wstart = y - wid / 2;
1176 				for (w = wstart; w < wstart + wid; w++) {
1177 					gdImageSetPixel (im, x, w, color);
1178 				}
1179 			}
1180 		} else {
1181 			while (x < xend) {
1182 				x++;
1183 				if (d < 0) {
1184 					d += incr1;
1185 				} else {
1186 					y--;
1187 					d += incr2;
1188 				}
1189 				wstart = y - wid / 2;
1190 				for (w = wstart; w < wstart + wid; w++) {
1191 					gdImageSetPixel (im, x, w, color);
1192 				}
1193 			}
1194 		}
1195 	} else {
1196 		/* More-or-less vertical. use wid for horizontal stroke */
1197 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1198 		   TBB: but watch out for /0! */
1199 		double as = sin (atan2 (dy, dx));
1200 		if (as != 0) {
1201 			wid = thick / as;
1202 		} else {
1203 			wid = 1;
1204 		}
1205 		if (wid == 0) {
1206 			wid = 1;
1207 		}
1208 
1209 		d = 2 * dx - dy;
1210 		incr1 = 2 * dx;
1211 		incr2 = 2 * (dx - dy);
1212 		if (y1 > y2) {
1213 			y = y2;
1214 			x = x2;
1215 			yend = y1;
1216 			xdirflag = (-1);
1217 		} else {
1218 			y = y1;
1219 			x = x1;
1220 			yend = y2;
1221 			xdirflag = 1;
1222 		}
1223 
1224 		/* Set up line thickness */
1225 		wstart = x - wid / 2;
1226 		for (w = wstart; w < wstart + wid; w++) {
1227 			gdImageSetPixel (im, w, y, color);
1228 		}
1229 
1230 		if (((x2 - x1) * xdirflag) > 0) {
1231 			while (y < yend) {
1232 				y++;
1233 				if (d < 0) {
1234 					d += incr1;
1235 				} else {
1236 					x++;
1237 					d += incr2;
1238 				}
1239 				wstart = x - wid / 2;
1240 				for (w = wstart; w < wstart + wid; w++) {
1241 					gdImageSetPixel (im, w, y, color);
1242 				}
1243 			}
1244 		} else {
1245 			while (y < yend) {
1246 				y++;
1247 				if (d < 0) {
1248 					d += incr1;
1249 				} else {
1250 					x--;
1251 					d += incr2;
1252 				}
1253 				wstart = x - wid / 2;
1254 				for (w = wstart; w < wstart + wid; w++) {
1255 					gdImageSetPixel (im, w, y, color);
1256 				}
1257 			}
1258 		}
1259 	}
1260 }
1261 
1262 
1263 /*
1264  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
1265  * */
1266 #define BLEND_COLOR(a, nc, c, cc) \
1267 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
1268 
gdImageSetAAPixelColor(gdImagePtr im,int x,int y,int color,int t)1269 inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
1270 {
1271 	int dr,dg,db,p,r,g,b;
1272 	dr = gdTrueColorGetRed(color);
1273 	dg = gdTrueColorGetGreen(color);
1274 	db = gdTrueColorGetBlue(color);
1275 
1276 	p = gdImageGetPixel(im,x,y);
1277 	r = gdTrueColorGetRed(p);
1278 	g = gdTrueColorGetGreen(p);
1279 	b = gdTrueColorGetBlue(p);
1280 
1281 	BLEND_COLOR(t, dr, r, dr);
1282 	BLEND_COLOR(t, dg, g, dg);
1283 	BLEND_COLOR(t, db, b, db);
1284 	im->tpixels[y][x]=gdTrueColorAlpha(dr, dg, db,  gdAlphaOpaque);
1285 }
1286 
1287 /*
1288  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
1289  **/
gdImageAALine(gdImagePtr im,int x1,int y1,int x2,int y2,int col)1290 void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
1291 {
1292 	/* keep them as 32bits */
1293 	long x, y, inc, frac;
1294 	long dx, dy,tmp;
1295 
1296 	if (!im->trueColor) {
1297 		/* TBB: don't crash when the image is of the wrong type */
1298 		gdImageLine(im, x1, y1, x2, y2, col);
1299 		return;
1300 	}
1301 
1302 	/* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
1303 	if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)-1) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im)-1)) {
1304 		return;
1305 	}
1306 
1307 	dx = x2 - x1;
1308 	dy = y2 - y1;
1309 
1310 	if (dx == 0 && dy == 0) {
1311 		return;
1312 	}
1313 	if (abs((int)dx) > abs((int)dy)) {
1314 		if (dx < 0) {
1315 			tmp = x1;
1316 			x1 = x2;
1317 			x2 = tmp;
1318 			tmp = y1;
1319 			y1 = y2;
1320 			y2 = tmp;
1321 			dx = x2 - x1;
1322 			dy = y2 - y1;
1323 		}
1324 		y = y1;
1325 		inc = (dy * 65536) / dx;
1326 		frac = 0;
1327 		for (x = x1; x <= x2; x++) {
1328 			gdImageSetAAPixelColor(im, x, y, col, (frac >> 8) & 0xFF);
1329 			if (y + 1 < im->sy) {
1330 				gdImageSetAAPixelColor(im, x, y + 1, col, (~frac >> 8) & 0xFF);
1331 			}
1332 			frac += inc;
1333 			if (frac >= 65536) {
1334 				frac -= 65536;
1335 				y++;
1336 			} else if (frac < 0) {
1337 				frac += 65536;
1338 				y--;
1339 			}
1340 		}
1341 	} else {
1342 		if (dy < 0) {
1343 			tmp = x1;
1344 			x1 = x2;
1345 			x2 = tmp;
1346 			tmp = y1;
1347 			y1 = y2;
1348 			y2 = tmp;
1349 			dx = x2 - x1;
1350 			dy = y2 - y1;
1351 		}
1352 		x = x1;
1353 		inc = (dx * 65536) / dy;
1354 		frac = 0;
1355 		for (y = y1; y <= y2; y++) {
1356 			gdImageSetAAPixelColor(im, x, y, col, (frac >> 8) & 0xFF);
1357 			if (x + 1 < im->sx) {
1358 				gdImageSetAAPixelColor(im, x + 1, y, col, (~frac >> 8) & 0xFF);
1359 			}
1360 			frac += inc;
1361 			if (frac >= 65536) {
1362 				frac -= 65536;
1363 				x++;
1364 			} else if (frac < 0) {
1365 				frac += 65536;
1366 				x--;
1367 			}
1368 		}
1369 	}
1370 }
1371 
1372 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert);
1373 
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1374 void gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1375 {
1376 	int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1377 	int dashStep = 0;
1378 	int on = 1;
1379 	int wid;
1380 	int vert;
1381 	int thick = im->thick;
1382 
1383 	dx = abs(x2 - x1);
1384 	dy = abs(y2 - y1);
1385 	if (dy <= dx) {
1386 		/* More-or-less horizontal. use wid for vertical stroke */
1387 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1388 		TBB: but watch out for /0! */
1389 		double as = sin(atan2(dy, dx));
1390 		if (as != 0) {
1391 			wid = thick / as;
1392 		} else {
1393 			wid = 1;
1394 		}
1395 		vert = 1;
1396 
1397 		d = 2 * dy - dx;
1398 		incr1 = 2 * dy;
1399 		incr2 = 2 * (dy - dx);
1400 		if (x1 > x2) {
1401 			x = x2;
1402 			y = y2;
1403 			ydirflag = (-1);
1404 			xend = x1;
1405 		} else {
1406 			x = x1;
1407 			y = y1;
1408 			ydirflag = 1;
1409 			xend = x2;
1410 		}
1411 		dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1412 		if (((y2 - y1) * ydirflag) > 0) {
1413 			while (x < xend) {
1414 				x++;
1415 				if (d < 0) {
1416 					d += incr1;
1417 				} else {
1418 					y++;
1419 					d += incr2;
1420 				}
1421 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1422 			}
1423 		} else {
1424 			while (x < xend) {
1425 				x++;
1426 				if (d < 0) {
1427 					d += incr1;
1428 				} else {
1429 					y--;
1430 					d += incr2;
1431 				}
1432 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1433 			}
1434 		}
1435 	} else {
1436 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1437 		TBB: but watch out for /0! */
1438 		double as = sin (atan2 (dy, dx));
1439 		if (as != 0) {
1440 			wid = thick / as;
1441 		} else {
1442 			wid = 1;
1443 		}
1444 		vert = 0;
1445 
1446 		d = 2 * dx - dy;
1447 		incr1 = 2 * dx;
1448 		incr2 = 2 * (dx - dy);
1449 		if (y1 > y2) {
1450 			y = y2;
1451 			x = x2;
1452 			yend = y1;
1453 			xdirflag = (-1);
1454 		} else {
1455 			y = y1;
1456 			x = x1;
1457 			yend = y2;
1458 			xdirflag = 1;
1459 		}
1460 		dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1461 		if (((x2 - x1) * xdirflag) > 0) {
1462 			while (y < yend) {
1463 				y++;
1464 				if (d < 0) {
1465 					d += incr1;
1466 				} else {
1467 					x++;
1468 					d += incr2;
1469 				}
1470 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1471 			}
1472 		} else {
1473 			while (y < yend) {
1474 				y++;
1475 				if (d < 0) {
1476 					d += incr1;
1477 				} else {
1478 					x--;
1479 					d += incr2;
1480 				}
1481 				dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
1482 			}
1483 		}
1484 	}
1485 }
1486 
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1487 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert)
1488 {
1489 	int dashStep = *dashStepP;
1490 	int on = *onP;
1491 	int w, wstart;
1492 
1493 	dashStep++;
1494 	if (dashStep == gdDashSize) {
1495 		dashStep = 0;
1496 		on = !on;
1497 	}
1498 	if (on) {
1499 		if (vert) {
1500 			wstart = y - wid / 2;
1501 			for (w = wstart; w < wstart + wid; w++) {
1502 				gdImageSetPixel(im, x, w, color);
1503 			}
1504 		} else {
1505 			wstart = x - wid / 2;
1506 			for (w = wstart; w < wstart + wid; w++) {
1507 				gdImageSetPixel(im, w, y, color);
1508 			}
1509 		}
1510 	}
1511 	*dashStepP = dashStep;
1512 	*onP = on;
1513 }
1514 
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1515 void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1516 {
1517 	int cx, cy;
1518 	int px, py;
1519 	int fline;
1520 	const int xuppper = (x > INT_MAX - f->w) ? INT_MAX : x + f->w;
1521 	const int yuppper = (y > INT_MAX - f->h) ? INT_MAX : y + f->h;
1522 	cx = 0;
1523 	cy = 0;
1524 #ifdef CHARSET_EBCDIC
1525 	c = ASC (c);
1526 #endif /*CHARSET_EBCDIC */
1527 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1528 		return;
1529 	}
1530 	fline = (c - f->offset) * f->h * f->w;
1531 	for (py = y; py < yuppper; py++) {
1532 		for (px = x; px < xuppper; px++) {
1533 			if (f->data[fline + cy * f->w + cx]) {
1534 				gdImageSetPixel(im, px, py, color);
1535 			}
1536 			cx++;
1537 		}
1538 		cx = 0;
1539 		cy++;
1540 	}
1541 }
1542 
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1543 void gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1544 {
1545 	int cx, cy;
1546 	int px, py;
1547 	int fline;
1548 	const int xuppper = (x > INT_MAX - f->h) ? INT_MAX : x + f->h;
1549 	const int ylower = (y < INT_MIN + f->w) ? INT_MIN : y - f->w;
1550 	cx = 0;
1551 	cy = 0;
1552 #ifdef CHARSET_EBCDIC
1553 	c = ASC (c);
1554 #endif /*CHARSET_EBCDIC */
1555 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1556 		return;
1557 	}
1558 	fline = (c - f->offset) * f->h * f->w;
1559 	for (py = y; py > ylower; py--) {
1560 		for (px = x; px < xuppper; px++) {
1561 			if (f->data[fline + cy * f->w + cx]) {
1562 				gdImageSetPixel(im, px, py, color);
1563 			}
1564 			cy++;
1565 		}
1566 		cy = 0;
1567 		cx++;
1568 	}
1569 }
1570 
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1571 void gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1572 {
1573 	int i;
1574 	int l;
1575 	l = strlen ((char *) s);
1576 	for (i = 0; (i < l); i++) {
1577 		gdImageChar(im, f, x, y, s[i], color);
1578 		x += f->w;
1579 	}
1580 }
1581 
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1582 void gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1583 {
1584 	int i;
1585 	int l;
1586 	l = strlen ((char *) s);
1587 	for (i = 0; (i < l); i++) {
1588 		gdImageCharUp(im, f, x, y, s[i], color);
1589 		y -= f->w;
1590 	}
1591 }
1592 
1593 static int strlen16 (unsigned short *s);
1594 
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1595 void gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1596 {
1597 	int i;
1598 	int l;
1599 	l = strlen16(s);
1600 	for (i = 0; (i < l); i++) {
1601 		gdImageChar(im, f, x, y, s[i], color);
1602 		x += f->w;
1603 	}
1604 }
1605 
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1606 void gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1607 {
1608 	int i;
1609 	int l;
1610 	l = strlen16(s);
1611 	for (i = 0; i < l; i++) {
1612 		gdImageCharUp(im, f, x, y, s[i], color);
1613 		y -= f->w;
1614 	}
1615 }
1616 
strlen16(unsigned short * s)1617 static int strlen16 (unsigned short *s)
1618 {
1619 	int len = 0;
1620 	while (*s) {
1621 		s++;
1622 		len++;
1623 	}
1624 	return len;
1625 }
1626 
1627 #ifndef HAVE_LSQRT
1628 /* If you don't have a nice square root function for longs, you can use
1629    ** this hack
1630  */
lsqrt(long n)1631 long lsqrt (long n)
1632 {
1633  	long result = (long) sqrt ((double) n);
1634 	return result;
1635 }
1636 #endif
1637 
1638 /* s and e are integers modulo 360 (degrees), with 0 degrees
1639    being the rightmost extreme and degrees changing clockwise.
1640    cx and cy are the center in pixels; w and h are the horizontal
1641    and vertical diameter in pixels. */
1642 
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)1643 void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
1644 {
1645 	gdImageFilledArc(im, cx, cy, w, h, s, e, color, gdNoFill);
1646 }
1647 
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)1648 void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
1649 {
1650 	gdPoint pts[363];
1651 	int i, pti;
1652 	int lx = 0, ly = 0;
1653 	int fx = 0, fy = 0;
1654 	int startx = -1, starty = -1, endx = -1, endy = -1;
1655 
1656     if ((s % 360)  == (e % 360)) {
1657 		s = 0; e = 360;
1658 	} else {
1659 		if (s > 360) {
1660 			s = s % 360;
1661 		}
1662 
1663 		if (e > 360) {
1664 			e = e % 360;
1665 		}
1666 
1667 		while (s < 0) {
1668 			s += 360;
1669 		}
1670 
1671 		while (e < s) {
1672 			e += 360;
1673 		}
1674 		if (s == e) {
1675 			s = 0; e = 360;
1676 		}
1677 	}
1678 
1679 	for (i = s, pti = 1; i <= e; i++, pti++) {
1680 		int x, y;
1681 		x = endx = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
1682 		y = endy = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
1683 		if (i != s) {
1684 			if (!(style & gdChord)) {
1685 				if (style & gdNoFill) {
1686 					gdImageLine(im, lx, ly, x, y, color);
1687 				} else {
1688 					if (y == ly) {
1689 						pti--; /* don't add this point */
1690 						if (((i > 270 || i < 90) && x > lx) || ((i >  90 && i < 270) && x < lx)) {
1691 							/* replace the old x coord, if increasing on the
1692 							   right side or decreasing on the left side */
1693 							pts[pti].x = x;
1694 						}
1695 					} else {
1696 						pts[pti].x = x;
1697 						pts[pti].y = y;
1698 					}
1699   				}
1700 			}
1701 		} else {
1702 			fx = x;
1703 			fy = y;
1704 			if (!(style & (gdChord | gdNoFill))) {
1705 				pts[0].x = cx;
1706 				pts[0].y = cy;
1707 				pts[pti].x = startx = x;
1708 				pts[pti].y = starty = y;
1709 			}
1710 		}
1711 		lx = x;
1712 		ly = y;
1713 	}
1714 	if (style & gdChord) {
1715 		if (style & gdNoFill) {
1716 			if (style & gdEdged) {
1717 				gdImageLine(im, cx, cy, lx, ly, color);
1718 				gdImageLine(im, cx, cy, fx, fy, color);
1719 			}
1720 			gdImageLine(im, fx, fy, lx, ly, color);
1721 		} else {
1722 			pts[0].x = fx;
1723 			pts[0].y = fy;
1724 			pts[1].x = lx;
1725 			pts[1].y = ly;
1726 			pts[2].x = cx;
1727 			pts[2].y = cy;
1728 			gdImageFilledPolygon(im, pts, 3, color);
1729 		}
1730 	} else {
1731 		if (style & gdNoFill) {
1732 			if (style & gdEdged) {
1733 				gdImageLine(im, cx, cy, lx, ly, color);
1734 				gdImageLine(im, cx, cy, fx, fy, color);
1735 			}
1736 		} else {
1737 			if (e - s < 360) {
1738 				if (pts[1].x != startx && pts[1].y == starty) {
1739 					/* start point has been removed due to y-coord fix => insert it */
1740 					for (i = pti; i > 1; i--) {
1741 						pts[i].x = pts[i-1].x;
1742 						pts[i].y = pts[i-1].y;
1743 					}
1744 					pts[1].x = startx;
1745 					pts[1].y = starty;
1746 					pti++;
1747 				}
1748 				if (pts[pti-1].x != endx && pts[pti-1].y == endy) {
1749 					/* end point has been removed due to y-coord fix => insert it */
1750 					pts[pti].x = endx;
1751 					pts[pti].y = endy;
1752 					pti++;
1753 				}
1754 			}
1755 			pts[pti].x = cx;
1756 			pts[pti].y = cy;
1757 			gdImageFilledPolygon(im, pts, pti+1, color);
1758 		}
1759 	}
1760 }
1761 
1762 /**
1763  * Integer Ellipse functions (gdImageEllipse and gdImageFilledEllipse)
1764  * Function added by Pierre-Alain Joye 02/08/2003 (paj@pearfr.org)
1765  * See the ellipse function simplification for the equation
1766  * as well as the midpoint algorithm.
1767  */
1768 
gdImageEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1769 void gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c)
1770 {
1771 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
1772 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
1773 
1774 	a=w>>1;
1775 	b=h>>1;
1776 	gdImageSetPixel(im,mx+a, my, c);
1777 	gdImageSetPixel(im,mx-a, my, c);
1778 	mx1 = mx-a;my1 = my;
1779 	mx2 = mx+a;my2 = my;
1780 
1781 	aq = a * a;
1782 	bq = b * b;
1783 	dx = aq << 1;
1784 	dy = bq << 1;
1785 	r  = a * bq;
1786 	rx = r << 1;
1787 	ry = 0;
1788 	x = a;
1789 	while (x > 0){
1790 		if (r > 0) {
1791 			my1++;my2--;
1792 			ry +=dx;
1793 			r  -=ry;
1794 		}
1795 		if (r <= 0){
1796 			x--;
1797 			mx1++;mx2--;
1798 			rx -=dy;
1799 			r  +=rx;
1800 		}
1801 		gdImageSetPixel(im,mx1, my1, c);
1802 		gdImageSetPixel(im,mx1, my2, c);
1803 		gdImageSetPixel(im,mx2, my1, c);
1804 		gdImageSetPixel(im,mx2, my2, c);
1805 	}
1806 }
1807 
gdImageFilledEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1808 void gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
1809 {
1810 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
1811 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
1812 	int i;
1813 	int old_y2;
1814 
1815 	a=w>>1;
1816 	b=h>>1;
1817 
1818 	for (x = mx-a; x <= mx+a; x++) {
1819 		gdImageSetPixel(im, x, my, c);
1820 	}
1821 
1822 	mx1 = mx-a;my1 = my;
1823 	mx2 = mx+a;my2 = my;
1824 
1825 	aq = a * a;
1826 	bq = b * b;
1827 	dx = aq << 1;
1828 	dy = bq << 1;
1829 	r  = a * bq;
1830 	rx = r << 1;
1831 	ry = 0;
1832 	x = a;
1833 	old_y2=-2;
1834 	while (x > 0){
1835 		if (r > 0) {
1836 			my1++;my2--;
1837 			ry +=dx;
1838 			r  -=ry;
1839 		}
1840 		if (r <= 0){
1841 			x--;
1842 			mx1++;mx2--;
1843 			rx -=dy;
1844 			r  +=rx;
1845 		}
1846 		if(old_y2!=my2){
1847 			for(i=mx1;i<=mx2;i++){
1848 				gdImageSetPixel(im,i,my1,c);
1849 				gdImageSetPixel(im,i,my2,c);
1850 			}
1851 		}
1852 		old_y2 = my2;
1853 	}
1854 }
1855 
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)1856 void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
1857 {
1858 	int lastBorder;
1859 	/* Seek left */
1860 	int leftLimit = -1, rightLimit;
1861 	int i, restoreAlphaBlending = 0;
1862 
1863 	if (border < 0 || color < 0) {
1864 		/* Refuse to fill to a non-solid border */
1865 		return;
1866 	}
1867 
1868 	if (!im->trueColor) {
1869 		if ((color > (im->colorsTotal - 1)) || (border > (im->colorsTotal - 1)) || (color < 0)) {
1870 			return;
1871 		}
1872 	}
1873 
1874 	restoreAlphaBlending = im->alphaBlendingFlag;
1875 	im->alphaBlendingFlag = 0;
1876 
1877 	if (x >= im->sx) {
1878 		x = im->sx - 1;
1879 	} else if (x < 0) {
1880 		x = 0;
1881 	}
1882 	if (y >= im->sy) {
1883 		y = im->sy - 1;
1884 	} else if (y < 0) {
1885 		y = 0;
1886 	}
1887 
1888 	for (i = x; i >= 0; i--) {
1889 		if (gdImageGetPixel(im, i, y) == border) {
1890 			break;
1891 		}
1892 		gdImageSetPixel(im, i, y, color);
1893 		leftLimit = i;
1894 	}
1895 	if (leftLimit == -1) {
1896 		im->alphaBlendingFlag = restoreAlphaBlending;
1897 		return;
1898 	}
1899 	/* Seek right */
1900 	rightLimit = x;
1901 	for (i = (x + 1); i < im->sx; i++) {
1902 		if (gdImageGetPixel(im, i, y) == border) {
1903 			break;
1904 		}
1905 		gdImageSetPixel(im, i, y, color);
1906 		rightLimit = i;
1907 	}
1908 	/* Look at lines above and below and start paints */
1909 	/* Above */
1910 	if (y > 0) {
1911 		lastBorder = 1;
1912 		for (i = leftLimit; i <= rightLimit; i++) {
1913 			int c = gdImageGetPixel(im, i, y - 1);
1914 			if (lastBorder) {
1915 				if ((c != border) && (c != color)) {
1916 					gdImageFillToBorder(im, i, y - 1, border, color);
1917 					lastBorder = 0;
1918 				}
1919 			} else if ((c == border) || (c == color)) {
1920 				lastBorder = 1;
1921 			}
1922 		}
1923 	}
1924 
1925 	/* Below */
1926 	if (y < ((im->sy) - 1)) {
1927 		lastBorder = 1;
1928 		for (i = leftLimit; i <= rightLimit; i++) {
1929 			int c = gdImageGetPixel(im, i, y + 1);
1930 
1931 			if (lastBorder) {
1932 				if ((c != border) && (c != color)) {
1933 					gdImageFillToBorder(im, i, y + 1, border, color);
1934 					lastBorder = 0;
1935 				}
1936 			} else if ((c == border) || (c == color)) {
1937 				lastBorder = 1;
1938 			}
1939 		}
1940 	}
1941 	im->alphaBlendingFlag = restoreAlphaBlending;
1942 }
1943 
1944 /*
1945  * set the pixel at (x,y) and its 4-connected neighbors
1946  * with the same pixel value to the new pixel value nc (new color).
1947  * A 4-connected neighbor:  pixel above, below, left, or right of a pixel.
1948  * ideas from comp.graphics discussions.
1949  * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
1950  * contain the same color as the color to fill. To do not bloat normal filling
1951  * code I added a 2nd private function.
1952  */
1953 
1954 /* horizontal segment of scan line y */
1955 struct seg {int y, xl, xr, dy;};
1956 
1957 /* max depth of stack */
1958 #define FILL_MAX ((int)(im->sy*im->sx)/4)
1959 #define FILL_PUSH(Y, XL, XR, DY) \
1960     if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
1961     {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
1962 
1963 #define FILL_POP(Y, XL, XR, DY) \
1964     {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
1965 
1966 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
1967 
gdImageFill(gdImagePtr im,int x,int y,int nc)1968 void gdImageFill(gdImagePtr im, int x, int y, int nc)
1969 {
1970 	int l, x1, x2, dy;
1971 	int oc;   /* old pixel value */
1972 	int wx2,wy2;
1973 
1974 	int alphablending_bak;
1975 
1976 	/* stack of filled segments */
1977 	/* struct seg stack[FILL_MAX],*sp = stack; */
1978 	struct seg *stack = NULL;
1979 	struct seg *sp;
1980 
1981 	if (!im->trueColor && nc > (im->colorsTotal -1)) {
1982 		return;
1983 	}
1984 
1985 	alphablending_bak = im->alphaBlendingFlag;
1986 	im->alphaBlendingFlag = 0;
1987 
1988 	if (nc==gdTiled){
1989 		_gdImageFillTiled(im,x,y,nc);
1990 		im->alphaBlendingFlag = alphablending_bak;
1991 		return;
1992 	}
1993 
1994 	wx2=im->sx;wy2=im->sy;
1995 	oc = gdImageGetPixel(im, x, y);
1996 	if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
1997 		im->alphaBlendingFlag = alphablending_bak;
1998 		return;
1999 	}
2000 
2001 	/* Do not use the 4 neighbors implementation with
2002 	 * small images
2003 	 */
2004 	if (im->sx < 4) {
2005 		int ix = x, iy = y, c;
2006 		do {
2007 			do {
2008 				c = gdImageGetPixel(im, ix, iy);
2009 				if (c != oc) {
2010 					goto done;
2011 				}
2012 				gdImageSetPixel(im, ix, iy, nc);
2013 			} while(ix++ < (im->sx -1));
2014 			ix = x;
2015 		} while(iy++ < (im->sy -1));
2016 		goto done;
2017 	}
2018 
2019 	stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
2020 	sp = stack;
2021 
2022 	/* required! */
2023 	FILL_PUSH(y,x,x,1);
2024 	/* seed segment (popped 1st) */
2025  	FILL_PUSH(y+1, x, x, -1);
2026 	while (sp>stack) {
2027 		FILL_POP(y, x1, x2, dy);
2028 
2029 		for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
2030 			gdImageSetPixel(im,x, y, nc);
2031 		}
2032 		if (x>=x1) {
2033 			goto skip;
2034 		}
2035 		l = x+1;
2036 
2037                 /* leak on left? */
2038 		if (l<x1) {
2039 			FILL_PUSH(y, l, x1-1, -dy);
2040 		}
2041 		x = x1+1;
2042 		do {
2043 			for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
2044 				gdImageSetPixel(im, x, y, nc);
2045 			}
2046 			FILL_PUSH(y, l, x-1, dy);
2047 			/* leak on right? */
2048 			if (x>x2+1) {
2049 				FILL_PUSH(y, x2+1, x-1, -dy);
2050 			}
2051 skip:
2052 			for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
2053 
2054 			l = x;
2055 		} while (x<=x2);
2056 	}
2057 
2058 	efree(stack);
2059 
2060 done:
2061 	im->alphaBlendingFlag = alphablending_bak;
2062 }
2063 
_gdImageFillTiled(gdImagePtr im,int x,int y,int nc)2064 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
2065 {
2066 	int i, l, x1, x2, dy;
2067 	int oc;   /* old pixel value */
2068 	int wx2,wy2;
2069 	/* stack of filled segments */
2070 	struct seg *stack;
2071 	struct seg *sp;
2072 	char **pts;
2073 
2074 	if (!im->tile) {
2075 		return;
2076 	}
2077 
2078 	wx2=im->sx;wy2=im->sy;
2079 
2080 	nc =  gdImageTileGet(im,x,y);
2081 
2082 	pts = (char **) ecalloc(im->sy + 1, sizeof(char *));
2083 	for (i = 0; i < im->sy + 1; i++) {
2084 		pts[i] = (char *) ecalloc(im->sx + 1, sizeof(char));
2085 	}
2086 
2087 	stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
2088 	sp = stack;
2089 
2090 	oc = gdImageGetPixel(im, x, y);
2091 
2092 	/* required! */
2093 	FILL_PUSH(y,x,x,1);
2094 	/* seed segment (popped 1st) */
2095  	FILL_PUSH(y+1, x, x, -1);
2096 	while (sp>stack) {
2097 		FILL_POP(y, x1, x2, dy);
2098 		for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) {
2099 			nc = gdImageTileGet(im,x,y);
2100 			pts[y][x] = 1;
2101 			gdImageSetPixel(im,x, y, nc);
2102 		}
2103 		if (x>=x1) {
2104 			goto skip;
2105 		}
2106 		l = x+1;
2107 
2108 		/* leak on left? */
2109 		if (l<x1) {
2110 			FILL_PUSH(y, l, x1-1, -dy);
2111 		}
2112 		x = x1+1;
2113 		do {
2114 			for(; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc); x++) {
2115 				nc = gdImageTileGet(im,x,y);
2116 				pts[y][x] = 1;
2117 				gdImageSetPixel(im, x, y, nc);
2118 			}
2119 			FILL_PUSH(y, l, x-1, dy);
2120 			/* leak on right? */
2121 			if (x>x2+1) {
2122 				FILL_PUSH(y, x2+1, x-1, -dy);
2123 			}
2124 skip:
2125 			for(x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++);
2126 			l = x;
2127 		} while (x<=x2);
2128 	}
2129 
2130 	for(i = 0; i < im->sy + 1; i++) {
2131 		efree(pts[i]);
2132 	}
2133 
2134 	efree(pts);
2135 	efree(stack);
2136 }
2137 
2138 
2139 
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2140 void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2141 {
2142 	int thick = im->thick;
2143 	int t;
2144 
2145 	if (x1 == x2 && y1 == y2 && thick == 1) {
2146 		gdImageSetPixel(im, x1, y1, color);
2147 		return;
2148 	}
2149 
2150 	if (y2 < y1) {
2151 		t=y1;
2152 		y1 = y2;
2153 		y2 = t;
2154 	}
2155 
2156 	if (x2 < x1) {
2157 		t = x1;
2158 		x1 = x2;
2159 		x2 = t;
2160 	}
2161 
2162 	if (thick > 1) {
2163 		int cx, cy, x1ul, y1ul, x2lr, y2lr;
2164 		int half = thick >> 1;
2165 
2166 		x1ul = x1 - half;
2167 		y1ul = y1 - half;
2168 
2169 		x2lr = x2 + half;
2170 		y2lr = y2 + half;
2171 
2172 		cy = y1ul + thick;
2173 		while (cy-- > y1ul) {
2174 			cx = x1ul - 1;
2175 			while (cx++ < x2lr) {
2176 				gdImageSetPixel(im, cx, cy, color);
2177 			}
2178 		}
2179 
2180 		cy = y2lr - thick;
2181 		while (cy++ < y2lr) {
2182 			cx = x1ul - 1;
2183 			while (cx++ < x2lr) {
2184 				gdImageSetPixel(im, cx, cy, color);
2185 			}
2186 		}
2187 
2188 		cy = y1ul + thick - 1;
2189 		while (cy++ < y2lr -thick) {
2190 			cx = x1ul - 1;
2191 			while (cx++ < x1ul + thick) {
2192 				gdImageSetPixel(im, cx, cy, color);
2193 			}
2194 		}
2195 
2196 		cy = y1ul + thick - 1;
2197 		while (cy++ < y2lr -thick) {
2198 			cx = x2lr - thick - 1;
2199 			while (cx++ < x2lr) {
2200 				gdImageSetPixel(im, cx, cy, color);
2201 			}
2202 		}
2203 
2204 		return;
2205 	} else {
2206 		if (x1 == x2 || y1 == y2) {
2207 			gdImageLine(im, x1, y1, x2, y2, color);
2208 		} else {
2209 			gdImageLine(im, x1, y1, x2, y1, color);
2210 			gdImageLine(im, x1, y2, x2, y2, color);
2211 			gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color);
2212 			gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color);
2213 		}
2214 	}
2215 }
2216 
_gdImageFilledHRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2217 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2218 {
2219 	int x, y;
2220 
2221 	if (x1 == x2 && y1 == y2) {
2222 		gdImageSetPixel(im, x1, y1, color);
2223 		return;
2224 	}
2225 
2226 	if (x1 > x2) {
2227 		x = x1;
2228 		x1 = x2;
2229 		x2 = x;
2230 	}
2231 
2232 	if (y1 > y2) {
2233 		y = y1;
2234 		y1 = y2;
2235 		y2 = y;
2236 	}
2237 
2238 	if (x1 < 0) {
2239 		x1 = 0;
2240 	}
2241 
2242 	if (x2 >= gdImageSX(im)) {
2243 		x2 = gdImageSX(im) - 1;
2244 	}
2245 
2246 	if (y1 < 0) {
2247 		y1 = 0;
2248 	}
2249 
2250 	if (y2 >= gdImageSY(im)) {
2251 		y2 = gdImageSY(im) - 1;
2252 	}
2253 
2254 	for (x = x1; (x <= x2); x++) {
2255 		for (y = y1; (y <= y2); y++) {
2256 			gdImageSetPixel (im, x, y, color);
2257 		}
2258 	}
2259 }
2260 
_gdImageFilledVRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2261 static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2262 {
2263 	int x, y;
2264 
2265 	if (x1 == x2 && y1 == y2) {
2266 		gdImageSetPixel(im, x1, y1, color);
2267 		return;
2268 	}
2269 
2270 	if (x1 > x2) {
2271 		x = x1;
2272 		x1 = x2;
2273 		x2 = x;
2274 	}
2275 
2276 	if (y1 > y2) {
2277 		y = y1;
2278 		y1 = y2;
2279 		y2 = y;
2280 	}
2281 
2282 	if (x1 < 0) {
2283 		x1 = 0;
2284 	}
2285 
2286 	if (x2 >= gdImageSX(im)) {
2287 		x2 = gdImageSX(im) - 1;
2288 	}
2289 
2290 	if (y1 < 0) {
2291 		y1 = 0;
2292 	}
2293 
2294 	if (y2 >= gdImageSY(im)) {
2295 		y2 = gdImageSY(im) - 1;
2296 	}
2297 
2298 	for (y = y1; (y <= y2); y++) {
2299 		for (x = x1; (x <= x2); x++) {
2300 			gdImageSetPixel (im, x, y, color);
2301 		}
2302 	}
2303 }
2304 
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2305 void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2306 {
2307 	_gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
2308 }
2309 
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)2310 void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
2311 {
2312 	int c;
2313 	int x, y;
2314 	int tox, toy;
2315 	int i;
2316 	int colorMap[gdMaxColors];
2317 
2318 	if (dst->trueColor) {
2319 		/* 2.0: much easier when the destination is truecolor. */
2320 		/* 2.0.10: needs a transparent-index check that is still valid if
2321 		 * the source is not truecolor. Thanks to Frank Warmerdam.
2322 		 */
2323 
2324 		if (src->trueColor) {
2325 			for (y = 0; (y < h); y++) {
2326 				for (x = 0; (x < w); x++) {
2327 					int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
2328 					if (c != src->transparent) {
2329 						gdImageSetPixel (dst, dstX + x, dstY + y, c);
2330 					}
2331 				}
2332 			}
2333 		} else {
2334 			/* source is palette based */
2335 			for (y = 0; (y < h); y++) {
2336 				for (x = 0; (x < w); x++) {
2337 					int c = gdImageGetPixel (src, srcX + x, srcY + y);
2338 					if (c != src->transparent) {
2339 						gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
2340 					}
2341 				}
2342 			}
2343 		}
2344 		return;
2345 	}
2346 
2347 	/* Palette based to palette based */
2348 	for (i = 0; i < gdMaxColors; i++) {
2349 		colorMap[i] = (-1);
2350 	}
2351 	toy = dstY;
2352 	for (y = srcY; y < (srcY + h); y++) {
2353 		tox = dstX;
2354 		for (x = srcX; x < (srcX + w); x++) {
2355 			int nc;
2356 			int mapTo;
2357 			c = gdImageGetPixel (src, x, y);
2358 			/* Added 7/24/95: support transparent copies */
2359 			if (gdImageGetTransparent (src) == c) {
2360 				tox++;
2361 				continue;
2362 			}
2363 			/* Have we established a mapping for this color? */
2364 			if (src->trueColor) {
2365 				/* 2.05: remap to the palette available in the destination image. This is slow and
2366 				 * works badly, but it beats crashing! Thanks to Padhrig McCarthy.
2367 				 */
2368 				mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c));
2369 			} else if (colorMap[c] == (-1)) {
2370 				/* If it's the same image, mapping is trivial */
2371 				if (dst == src) {
2372 					nc = c;
2373 				} else {
2374 					/* Get best match possible. This function never returns error. */
2375 					nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]);
2376 				}
2377 				colorMap[c] = nc;
2378 				mapTo = colorMap[c];
2379 			} else {
2380 				mapTo = colorMap[c];
2381 			}
2382 			gdImageSetPixel (dst, tox, toy, mapTo);
2383 			tox++;
2384 		}
2385 		toy++;
2386 	}
2387 }
2388 
2389 /* This function is a substitute for real alpha channel operations,
2390    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)2391 void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2392 {
2393 	int c, dc;
2394 	int x, y;
2395 	int tox, toy;
2396 	int ncR, ncG, ncB;
2397 	toy = dstY;
2398 
2399 	for (y = srcY; y < (srcY + h); y++) {
2400 		tox = dstX;
2401 		for (x = srcX; x < (srcX + w); x++) {
2402 			int nc;
2403 			c = gdImageGetPixel(src, x, y);
2404 			/* Added 7/24/95: support transparent copies */
2405 			if (gdImageGetTransparent(src) == c) {
2406 				tox++;
2407 				continue;
2408 			}
2409 			/* If it's the same image, mapping is trivial */
2410 			if (dst == src) {
2411 				nc = c;
2412 			} else {
2413 				dc = gdImageGetPixel(dst, tox, toy);
2414 
2415  				ncR = (int)(gdImageRed (src, c) * (pct / 100.0) + gdImageRed (dst, dc) * ((100 - pct) / 100.0));
2416  				ncG = (int)(gdImageGreen (src, c) * (pct / 100.0) + gdImageGreen (dst, dc) * ((100 - pct) / 100.0));
2417  				ncB = (int)(gdImageBlue (src, c) * (pct / 100.0) + gdImageBlue (dst, dc) * ((100 - pct) / 100.0));
2418 
2419 				/* Find a reasonable color */
2420 				nc = gdImageColorResolve (dst, ncR, ncG, ncB);
2421 			}
2422 			gdImageSetPixel (dst, tox, toy, nc);
2423 			tox++;
2424 		}
2425 		toy++;
2426 	}
2427 }
2428 
2429 /* This function is a substitute for real alpha channel operations,
2430    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)2431 void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2432 {
2433 	int c, dc;
2434 	int x, y;
2435 	int tox, toy;
2436 	int ncR, ncG, ncB;
2437 	float g;
2438 	toy = dstY;
2439 
2440 	for (y = srcY; (y < (srcY + h)); y++) {
2441 		tox = dstX;
2442 		for (x = srcX; (x < (srcX + w)); x++) {
2443 			int nc;
2444 			c = gdImageGetPixel (src, x, y);
2445 			/* Added 7/24/95: support transparent copies */
2446 			if (gdImageGetTransparent(src) == c) {
2447 				tox++;
2448 				continue;
2449 			}
2450 
2451 			/*
2452 			 * If it's the same image, mapping is NOT trivial since we
2453 			 * merge with greyscale target, but if pct is 100, the grey
2454 			 * value is not used, so it becomes trivial. pjw 2.0.12.
2455 			 */
2456 			if (dst == src && pct == 100) {
2457 				nc = c;
2458 			} else {
2459 				dc = gdImageGetPixel(dst, tox, toy);
2460 				g = (0.29900f * gdImageRed(dst, dc)) + (0.58700f * gdImageGreen(dst, dc)) + (0.11400f * gdImageBlue(dst, dc));
2461 
2462 				ncR = (int)(gdImageRed (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2463 				ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2464 				ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2465 
2466 
2467 				/* First look for an exact match */
2468 				nc = gdImageColorExact(dst, ncR, ncG, ncB);
2469 				if (nc == (-1)) {
2470 					/* No, so try to allocate it */
2471 					nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
2472 					/* If we're out of colors, go for the closest color */
2473 					if (nc == (-1)) {
2474 						nc = gdImageColorClosest(dst, ncR, ncG, ncB);
2475 					}
2476 				}
2477 			}
2478 			gdImageSetPixel(dst, tox, toy, nc);
2479 			tox++;
2480 		}
2481 		toy++;
2482 	}
2483 }
2484 
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2485 void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2486 {
2487 	int c;
2488 	int x, y;
2489 	int tox, toy;
2490 	int ydest;
2491 	int i;
2492 	int colorMap[gdMaxColors];
2493 	/* Stretch vectors */
2494 	int *stx, *sty;
2495 
2496 	if (overflow2(sizeof(int), srcW)) {
2497 		return;
2498 	}
2499 	if (overflow2(sizeof(int), srcH)) {
2500 		return;
2501 	}
2502 
2503 	stx = (int *) gdMalloc (sizeof (int) * srcW);
2504 	sty = (int *) gdMalloc (sizeof (int) * srcH);
2505 
2506 	/* Fixed by Mao Morimoto 2.0.16 */
2507 	for (i = 0; (i < srcW); i++) {
2508 		stx[i] = dstW * (i+1) / srcW - dstW * i / srcW ;
2509 	}
2510 	for (i = 0; (i < srcH); i++) {
2511 		sty[i] = dstH * (i+1) / srcH - dstH * i / srcH ;
2512 	}
2513 	for (i = 0; (i < gdMaxColors); i++) {
2514 		colorMap[i] = (-1);
2515 	}
2516 	toy = dstY;
2517 	for (y = srcY; (y < (srcY + srcH)); y++) {
2518 		for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
2519 			tox = dstX;
2520 			for (x = srcX; (x < (srcX + srcW)); x++) {
2521 				int nc = 0;
2522 				int mapTo;
2523 				if (!stx[x - srcX]) {
2524 					continue;
2525 				}
2526 				if (dst->trueColor) {
2527 					/* 2.0.9: Thorben Kundinger: Maybe the source image is not a truecolor image */
2528 					if (!src->trueColor) {
2529 					  	int tmp = gdImageGetPixel (src, x, y);
2530 		  				mapTo = gdImageGetTrueColorPixel (src, x, y);
2531 					  	if (gdImageGetTransparent (src) == tmp) {
2532 							/* 2.0.21, TK: not tox++ */
2533 							tox += stx[x - srcX];
2534 					  		continue;
2535 					  	}
2536 					} else {
2537 						/* TK: old code follows */
2538 					  	mapTo = gdImageGetTrueColorPixel (src, x, y);
2539 						/* Added 7/24/95: support transparent copies */
2540 						if (gdImageGetTransparent (src) == mapTo) {
2541 							/* 2.0.21, TK: not tox++ */
2542 							tox += stx[x - srcX];
2543 							continue;
2544 						}
2545 					}
2546 				} else {
2547 					c = gdImageGetPixel (src, x, y);
2548 					/* Added 7/24/95: support transparent copies */
2549 					if (gdImageGetTransparent (src) == c) {
2550 					      tox += stx[x - srcX];
2551 					      continue;
2552 					}
2553 					if (src->trueColor) {
2554 					      /* Remap to the palette available in the destination image. This is slow and works badly. */
2555 					      mapTo = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c),
2556 					      					    gdTrueColorGetGreen(c),
2557 					      					    gdTrueColorGetBlue(c),
2558 					      					    gdTrueColorGetAlpha (c));
2559 					} else {
2560 						/* Have we established a mapping for this color? */
2561 						if (colorMap[c] == (-1)) {
2562 							/* If it's the same image, mapping is trivial */
2563 							if (dst == src) {
2564 								nc = c;
2565 							} else {
2566 								/* Find or create the best match */
2567 								/* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
2568 								nc = gdImageColorResolveAlpha(dst, gdImageRed(src, c),
2569 												   gdImageGreen(src, c),
2570 												   gdImageBlue(src, c),
2571 												   gdImageAlpha(src, c));
2572 							}
2573 							colorMap[c] = nc;
2574 						}
2575 						mapTo = colorMap[c];
2576 					}
2577 				}
2578 				for (i = 0; (i < stx[x - srcX]); i++) {
2579 					gdImageSetPixel (dst, tox, toy, mapTo);
2580 					tox++;
2581 				}
2582 			}
2583 			toy++;
2584 		}
2585 	}
2586 	gdFree (stx);
2587 	gdFree (sty);
2588 }
2589 
2590 /* When gd 1.x was first created, floating point was to be avoided.
2591    These days it is often faster than table lookups or integer
2592    arithmetic. The routine below is shamelessly, gloriously
2593    floating point. TBB */
2594 
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2595 void gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2596 {
2597 	int x, y;
2598 	double sy1, sy2, sx1, sx2;
2599 
2600 	if (!dst->trueColor) {
2601 		gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
2602 		return;
2603 	}
2604 	for (y = dstY; (y < dstY + dstH); y++) {
2605 		sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
2606 		sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
2607 		for (x = dstX; (x < dstX + dstW); x++) {
2608 			double sx, sy;
2609 			double spixels = 0;
2610 			double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
2611 			double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
2612 			sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
2613 			sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
2614 			sy = sy1;
2615 			do {
2616 				double yportion;
2617 				if (floor_cast(sy) == floor_cast(sy1)) {
2618 					yportion = 1.0f - (sy - floor_cast(sy));
2619 					if (yportion > sy2 - sy1) {
2620 						yportion = sy2 - sy1;
2621 					}
2622 					sy = floor_cast(sy);
2623 				} else if (sy == floorf(sy2)) {
2624 					yportion = sy2 - floor_cast(sy2);
2625 				} else {
2626 					yportion = 1.0f;
2627 				}
2628 				sx = sx1;
2629 				do {
2630 					double xportion;
2631 					double pcontribution;
2632 					int p;
2633 					if (floorf(sx) == floor_cast(sx1)) {
2634 						xportion = 1.0f - (sx - floor_cast(sx));
2635 						if (xportion > sx2 - sx1) {
2636 							xportion = sx2 - sx1;
2637 						}
2638 						sx = floor_cast(sx);
2639 					} else if (sx == floorf(sx2)) {
2640 						xportion = sx2 - floor_cast(sx2);
2641 					} else {
2642 						xportion = 1.0f;
2643 					}
2644 					pcontribution = xportion * yportion;
2645 					p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
2646 
2647 					alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
2648 					red += gdTrueColorGetRed (p) * alpha_factor;
2649 					green += gdTrueColorGetGreen (p) * alpha_factor;
2650 					blue += gdTrueColorGetBlue (p) * alpha_factor;
2651 					alpha += gdTrueColorGetAlpha (p) * pcontribution;
2652 					alpha_sum += alpha_factor;
2653 					contrib_sum += pcontribution;
2654 					spixels += xportion * yportion;
2655 					sx += 1.0f;
2656 				}
2657 				while (sx < sx2);
2658 
2659 				sy += 1.0f;
2660 			}
2661 
2662 			while (sy < sy2);
2663 
2664 			if (spixels != 0.0f) {
2665 				red /= spixels;
2666 				green /= spixels;
2667 				blue /= spixels;
2668 				alpha /= spixels;
2669 			}
2670 			if ( alpha_sum != 0.0f) {
2671 				if( contrib_sum != 0.0f) {
2672 					alpha_sum /= contrib_sum;
2673 				}
2674 				red /= alpha_sum;
2675 				green /= alpha_sum;
2676 				blue /= alpha_sum;
2677 			}
2678 			/* Round up closest next channel value and clamp to max channel value */
2679 			red = red >= 255.5 ? 255 : red+0.5;
2680 			blue = blue >= 255.5 ? 255 : blue+0.5;
2681 			green = green >= 255.5 ? 255 : green+0.5;
2682 			alpha = alpha >= gdAlphaMax+0.5 ? gdAlphaMax : alpha+0.5;
2683 			gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int)red, (int)green, (int)blue, (int)alpha));
2684 		}
2685 	}
2686 }
2687 
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)2688 void gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2689 {
2690 	if (n <= 0) {
2691 		return;
2692 	}
2693 
2694 
2695 	gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
2696 	gdImageOpenPolygon (im, p, n, c);
2697 }
2698 
gdImageOpenPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2699 void gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2700 {
2701 	int i;
2702 	int lx, ly;
2703 
2704 	if (n <= 0) {
2705 		return;
2706 	}
2707 
2708 	lx = p->x;
2709 	ly = p->y;
2710 	for (i = 1; i < n; i++) {
2711 		p++;
2712 		gdImageLine(im, lx, ly, p->x, p->y, c);
2713 		lx = p->x;
2714 		ly = p->y;
2715 	}
2716 }
2717 
2718 int gdCompareInt (const void *a, const void *b);
2719 
2720 /* THANKS to Kirsten Schulz for the polygon fixes! */
2721 
2722 /* The intersection finding technique of this code could be improved
2723  * by remembering the previous intertersection, and by using the slope.
2724  * That could help to adjust intersections  to produce a nice
2725  * interior_extrema.
2726  */
2727 
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2728 void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2729 {
2730 	int i;
2731 	int y;
2732 	int miny, maxy, pmaxy;
2733 	int x1, y1;
2734 	int x2, y2;
2735 	int ind1, ind2;
2736 	int ints;
2737 	int fill_color;
2738 
2739 	if (n <= 0) {
2740 		return;
2741 	}
2742 
2743 	if (overflow2(sizeof(int), n)) {
2744 		return;
2745 	}
2746 
2747 	if (c == gdAntiAliased) {
2748 		fill_color = im->AA_color;
2749 	} else {
2750 		fill_color = c;
2751 	}
2752 
2753 	if (!im->polyAllocated) {
2754 		im->polyInts = (int *) gdMalloc(sizeof(int) * n);
2755 		im->polyAllocated = n;
2756 	}
2757 	if (im->polyAllocated < n) {
2758 		while (im->polyAllocated < n) {
2759 			im->polyAllocated *= 2;
2760 		}
2761 		if (overflow2(sizeof(int), im->polyAllocated)) {
2762 			return;
2763 		}
2764 		im->polyInts = (int *) gdRealloc(im->polyInts, sizeof(int) * im->polyAllocated);
2765 	}
2766 	miny = p[0].y;
2767 	maxy = p[0].y;
2768 	for (i = 1; i < n; i++) {
2769 		if (p[i].y < miny) {
2770 			miny = p[i].y;
2771 		}
2772 		if (p[i].y > maxy) {
2773 			maxy = p[i].y;
2774 		}
2775 	}
2776 	/* necessary special case: horizontal line */
2777 	if (n > 1 && miny == maxy) {
2778 		x1 = x2 = p[0].x;
2779 		for (i = 1; (i < n); i++) {
2780 			if (p[i].x < x1) {
2781 				x1 = p[i].x;
2782 			} else if (p[i].x > x2) {
2783 				x2 = p[i].x;
2784 			}
2785 		}
2786 		gdImageLine(im, x1, miny, x2, miny, c);
2787 		return;
2788 	}
2789 	pmaxy = maxy;
2790 	/* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
2791 	if (miny < 0) {
2792 		miny = 0;
2793 	}
2794 	if (maxy >= gdImageSY(im)) {
2795 		maxy = gdImageSY(im) - 1;
2796 	}
2797 
2798 	/* Fix in 1.3: count a vertex only once */
2799 	for (y = miny; y <= maxy; y++) {
2800 		/*1.4           int interLast = 0; */
2801 		/*              int dirLast = 0; */
2802 		/*              int interFirst = 1; */
2803 		ints = 0;
2804 		for (i = 0; i < n; i++) {
2805 			if (!i) {
2806 				ind1 = n - 1;
2807 				ind2 = 0;
2808 			} else {
2809 				ind1 = i - 1;
2810 				ind2 = i;
2811 			}
2812 			y1 = p[ind1].y;
2813 			y2 = p[ind2].y;
2814 			if (y1 < y2) {
2815 				x1 = p[ind1].x;
2816 				x2 = p[ind2].x;
2817 			} else if (y1 > y2) {
2818 				y2 = p[ind1].y;
2819 				y1 = p[ind2].y;
2820 				x2 = p[ind1].x;
2821 				x1 = p[ind2].x;
2822 			} else {
2823 				continue;
2824 			}
2825 			/* Do the following math as float intermediately, and round to ensure
2826 			 * that Polygon and FilledPolygon for the same set of points have the
2827 			 * same footprint.
2828 			 */
2829 			if (y >= y1 && y < y2) {
2830 				im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
2831 			} else if (y == pmaxy && y == y2) {
2832 				im->polyInts[ints++] = x2;
2833 			}
2834 		}
2835 		qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2836 
2837 		for (i = 0; i < ints - 1; i += 2) {
2838 			gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, fill_color);
2839 		}
2840 	}
2841 
2842 	/* If we are drawing this AA, then redraw the border with AA lines. */
2843 	if (c == gdAntiAliased) {
2844 		gdImagePolygon(im, p, n, c);
2845 	}
2846 }
2847 
gdCompareInt(const void * a,const void * b)2848 int gdCompareInt (const void *a, const void *b)
2849 {
2850 	return (*(const int *) a) - (*(const int *) b);
2851 }
2852 
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)2853 void gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
2854 {
2855 	if (im->style) {
2856 		gdFree(im->style);
2857 	}
2858 	if (overflow2(sizeof (int), noOfPixels)) {
2859 		return;
2860 	}
2861 	im->style = (int *) gdMalloc(sizeof(int) * noOfPixels);
2862 	memcpy(im->style, style, sizeof(int) * noOfPixels);
2863 	im->styleLength = noOfPixels;
2864 	im->stylePos = 0;
2865 }
2866 
gdImageSetThickness(gdImagePtr im,int thickness)2867 void gdImageSetThickness (gdImagePtr im, int thickness)
2868 {
2869 	im->thick = thickness;
2870 }
2871 
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)2872 void gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
2873 {
2874 	int i;
2875 	im->brush = brush;
2876 	if (!im->trueColor && !im->brush->trueColor) {
2877 		for (i = 0; i < gdImageColorsTotal(brush); i++) {
2878 			int index;
2879 			index = gdImageColorResolveAlpha(im, gdImageRed(brush, i), gdImageGreen(brush, i), gdImageBlue(brush, i), gdImageAlpha(brush, i));
2880 			im->brushColorMap[i] = index;
2881 		}
2882 	}
2883 }
2884 
gdImageSetTile(gdImagePtr im,gdImagePtr tile)2885 void gdImageSetTile (gdImagePtr im, gdImagePtr tile)
2886 {
2887 	int i;
2888 	im->tile = tile;
2889 	if (!im->trueColor && !im->tile->trueColor) {
2890 		for (i = 0; i < gdImageColorsTotal(tile); i++) {
2891 			int index;
2892 			index = gdImageColorResolveAlpha(im, gdImageRed(tile, i), gdImageGreen(tile, i), gdImageBlue(tile, i), gdImageAlpha(tile, i));
2893 			im->tileColorMap[i] = index;
2894 		}
2895 	}
2896 }
2897 
gdImageSetAntiAliased(gdImagePtr im,int c)2898 void gdImageSetAntiAliased (gdImagePtr im, int c)
2899 {
2900 	im->AA = 1;
2901 	im->AA_color = c;
2902 	im->AA_dont_blend = -1;
2903 }
2904 
gdImageSetAntiAliasedDontBlend(gdImagePtr im,int c,int dont_blend)2905 void gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
2906 {
2907 	im->AA = 1;
2908 	im->AA_color = c;
2909 	im->AA_dont_blend = dont_blend;
2910 }
2911 
2912 
gdImageInterlace(gdImagePtr im,int interlaceArg)2913 void gdImageInterlace (gdImagePtr im, int interlaceArg)
2914 {
2915 	im->interlace = interlaceArg;
2916 }
2917 
gdImageCompare(gdImagePtr im1,gdImagePtr im2)2918 int gdImageCompare (gdImagePtr im1, gdImagePtr im2)
2919 {
2920 	int x, y;
2921 	int p1, p2;
2922 	int cmpStatus = 0;
2923 	int sx, sy;
2924 
2925 	if (im1->interlace != im2->interlace) {
2926 		cmpStatus |= GD_CMP_INTERLACE;
2927 	}
2928 
2929 	if (im1->transparent != im2->transparent) {
2930 		cmpStatus |= GD_CMP_TRANSPARENT;
2931 	}
2932 
2933 	if (im1->trueColor != im2->trueColor) {
2934 		cmpStatus |= GD_CMP_TRUECOLOR;
2935 	}
2936 
2937 	sx = im1->sx;
2938 	if (im1->sx != im2->sx) {
2939 		cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
2940 		if (im2->sx < im1->sx) {
2941 			sx = im2->sx;
2942 		}
2943 	}
2944 
2945 	sy = im1->sy;
2946 	if (im1->sy != im2->sy) {
2947 		cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
2948 		if (im2->sy < im1->sy) {
2949 			sy = im2->sy;
2950 		}
2951 	}
2952 
2953 	if (im1->colorsTotal != im2->colorsTotal) {
2954 		cmpStatus |= GD_CMP_NUM_COLORS;
2955 	}
2956 
2957 	for (y = 0; y < sy; y++) {
2958 		for (x = 0; x < sx; x++) {
2959 			p1 = im1->trueColor ? gdImageTrueColorPixel(im1, x, y) : gdImagePalettePixel(im1, x, y);
2960 			p2 = im2->trueColor ? gdImageTrueColorPixel(im2, x, y) : gdImagePalettePixel(im2, x, y);
2961 
2962 			if (gdImageRed(im1, p1) != gdImageRed(im2, p2)) {
2963 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2964 				break;
2965 			}
2966 			if (gdImageGreen(im1, p1) != gdImageGreen(im2, p2)) {
2967 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2968 				break;
2969 			}
2970 			if (gdImageBlue(im1, p1) != gdImageBlue(im2, p2)) {
2971 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2972 				break;
2973 			}
2974 #if 0
2975 			/* Soon we'll add alpha channel to palettes */
2976 			if (gdImageAlpha(im1, p1) != gdImageAlpha(im2, p2)) {
2977 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2978 				break;
2979 			}
2980 #endif
2981 		}
2982 		if (cmpStatus & GD_CMP_COLOR) {
2983 			break;
2984 		}
2985 	}
2986 
2987 	return cmpStatus;
2988 }
2989 
gdAlphaBlend(int dst,int src)2990 int gdAlphaBlend (int dst, int src) {
2991     int src_alpha = gdTrueColorGetAlpha(src);
2992     int dst_alpha, alpha, red, green, blue;
2993     int src_weight, dst_weight, tot_weight;
2994 
2995 /* -------------------------------------------------------------------- */
2996 /*      Simple cases we want to handle fast.                            */
2997 /* -------------------------------------------------------------------- */
2998     if( src_alpha == gdAlphaOpaque )
2999         return src;
3000 
3001     dst_alpha = gdTrueColorGetAlpha(dst);
3002     if( src_alpha == gdAlphaTransparent )
3003         return dst;
3004     if( dst_alpha == gdAlphaTransparent )
3005         return src;
3006 
3007 /* -------------------------------------------------------------------- */
3008 /*      What will the source and destination alphas be?  Note that      */
3009 /*      the destination weighting is substantially reduced as the       */
3010 /*      overlay becomes quite opaque.                                   */
3011 /* -------------------------------------------------------------------- */
3012     src_weight = gdAlphaTransparent - src_alpha;
3013     dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
3014     tot_weight = src_weight + dst_weight;
3015 
3016 /* -------------------------------------------------------------------- */
3017 /*      What red, green and blue result values will we use?             */
3018 /* -------------------------------------------------------------------- */
3019     alpha = src_alpha * dst_alpha / gdAlphaMax;
3020 
3021     red = (gdTrueColorGetRed(src) * src_weight
3022            + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
3023     green = (gdTrueColorGetGreen(src) * src_weight
3024            + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
3025     blue = (gdTrueColorGetBlue(src) * src_weight
3026            + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
3027 
3028 /* -------------------------------------------------------------------- */
3029 /*      Return merged result.                                           */
3030 /* -------------------------------------------------------------------- */
3031     return ((alpha << 24) + (red << 16) + (green << 8) + blue);
3032 
3033 }
3034 
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)3035 void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
3036 {
3037 	im->alphaBlendingFlag = alphaBlendingArg;
3038 }
3039 
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)3040 void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
3041 {
3042 	im->saveAlphaFlag = saveAlphaArg;
3043 }
3044 
gdLayerOverlay(int dst,int src)3045 int gdLayerOverlay (int dst, int src)
3046 {
3047 	int a1, a2;
3048 	a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
3049 	a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
3050 	return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
3051 		(gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
3052 		(gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
3053 		(gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
3054 		);
3055 }
3056 
gdAlphaOverlayColor(int src,int dst,int max)3057 static int gdAlphaOverlayColor (int src, int dst, int max )
3058 {
3059 	/* this function implements the algorithm
3060 	 *
3061 	 * for dst[rgb] < 0.5,
3062 	 *   c[rgb] = 2.src[rgb].dst[rgb]
3063 	 * and for dst[rgb] > 0.5,
3064 	 *   c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
3065 	 *
3066 	 */
3067 
3068 	dst = dst << 1;
3069 	if( dst > max ) {
3070 		/* in the "light" zone */
3071 		return dst + (src << 1) - (dst * src / max) - max;
3072 	} else {
3073 		/* in the "dark" zone */
3074 		return dst * src / max;
3075 	}
3076 }
3077 
gdLayerMultiply(int dst,int src)3078 int gdLayerMultiply (int dst, int src)
3079 {
3080 	int a1, a2, r1, r2, g1, g2, b1, b2;
3081 	a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
3082 	a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
3083 
3084 	r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
3085 	r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
3086 	g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
3087 	g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
3088 	b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
3089 	b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
3090 
3091 	a1 = gdAlphaMax - a1;
3092 	a2 = gdAlphaMax - a2;
3093 	return ( ((a1*a2/gdAlphaMax) << 24) +
3094 			 ((r1*r2/gdRedMax) << 16) +
3095 			 ((g1*g2/gdGreenMax) << 8) +
3096 			 ((b1*b2/gdBlueMax))
3097 		);
3098 }
3099 
gdImageSetClip(gdImagePtr im,int x1,int y1,int x2,int y2)3100 void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
3101 {
3102 	if (x1 < 0) {
3103 		x1 = 0;
3104 	}
3105 	if (x1 >= im->sx) {
3106 		x1 = im->sx - 1;
3107 	}
3108 	if (x2 < 0) {
3109 		x2 = 0;
3110 	}
3111 	if (x2 >= im->sx) {
3112 		x2 = im->sx - 1;
3113 	}
3114 	if (y1 < 0) {
3115 		y1 = 0;
3116 	}
3117 	if (y1 >= im->sy) {
3118 		y1 = im->sy - 1;
3119 	}
3120 	if (y2 < 0) {
3121 		y2 = 0;
3122 	}
3123 	if (y2 >= im->sy) {
3124 		y2 = im->sy - 1;
3125 	}
3126 	im->cx1 = x1;
3127 	im->cy1 = y1;
3128 	im->cx2 = x2;
3129 	im->cy2 = y2;
3130 }
3131 
gdImageGetClip(gdImagePtr im,int * x1P,int * y1P,int * x2P,int * y2P)3132 void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
3133 {
3134 	*x1P = im->cx1;
3135 	*y1P = im->cy1;
3136 	*x2P = im->cx2;
3137 	*y2P = im->cy2;
3138 }
3139 
gdImageSetResolution(gdImagePtr im,const unsigned int res_x,const unsigned int res_y)3140 void gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
3141 {
3142 	if (res_x > 0) im->res_x = res_x;
3143 	if (res_y > 0) im->res_y = res_y;
3144 }
3145 
3146 /* convert a palette image to true color */
gdImagePaletteToTrueColor(gdImagePtr src)3147 int gdImagePaletteToTrueColor(gdImagePtr src)
3148 {
3149 	unsigned int y;
3150 	unsigned int yy;
3151 
3152 	if (src == NULL) {
3153 		return 0;
3154 	}
3155 
3156 	if (src->trueColor == 1) {
3157 		return 1;
3158 	} else {
3159 		unsigned int x;
3160 		const unsigned int sy = gdImageSY(src);
3161 		const unsigned int sx = gdImageSX(src);
3162 
3163 		src->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
3164 		if (src->tpixels == NULL) {
3165 			return 0;
3166 		}
3167 
3168 		for (y = 0; y < sy; y++) {
3169 			const unsigned char *src_row = src->pixels[y];
3170 			int * dst_row;
3171 
3172 			/* no need to calloc it, we overwrite all pxl anyway */
3173 			src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int));
3174 			if (src->tpixels[y] == NULL) {
3175 				goto clean_on_error;
3176 			}
3177 
3178 			dst_row = src->tpixels[y];
3179 			for (x = 0; x < sx; x++) {
3180 				const unsigned char c = *(src_row + x);
3181 				if (c == src->transparent) {
3182 					*(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
3183 				} else {
3184 					*(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3185 				}
3186 			}
3187 		}
3188 	}
3189 
3190 	/* free old palette buffer (y is sy) */
3191 	for (yy = 0; yy < y; yy++) {
3192 		gdFree(src->pixels[yy]);
3193 	}
3194 	gdFree(src->pixels);
3195 	src->trueColor = 1;
3196 	src->pixels = NULL;
3197 	src->alphaBlendingFlag = 0;
3198 	src->saveAlphaFlag = 1;
3199 
3200 	if (src->transparent >= 0) {
3201 		const unsigned char c = src->transparent;
3202 		src->transparent =  gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3203 	}
3204 
3205 	return 1;
3206 
3207 clean_on_error:
3208 	/* free new true color buffer (y is not allocated, have failed) */
3209 	for (yy = 0; yy < y; yy++) {
3210 		gdFree(src->tpixels[yy]);
3211 	}
3212 	gdFree(src->tpixels);
3213 	return 0;
3214 }
3215