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