xref: /PHP-7.4/ext/gd/libgd/gd.c (revision 2c3dfe51)
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((int)dx) > abs((int)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 	const int xuppper = (x > INT_MAX - f->w) ? INT_MAX : x + f->w;
1467 	const int yuppper = (y > INT_MAX - f->h) ? INT_MAX : y + f->h;
1468 	cx = 0;
1469 	cy = 0;
1470 #ifdef CHARSET_EBCDIC
1471 	c = ASC (c);
1472 #endif /*CHARSET_EBCDIC */
1473 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1474 		return;
1475 	}
1476 	fline = (c - f->offset) * f->h * f->w;
1477 	for (py = y; py < yuppper; py++) {
1478 		for (px = x; px < xuppper; px++) {
1479 			if (f->data[fline + cy * f->w + cx]) {
1480 				gdImageSetPixel(im, px, py, color);
1481 			}
1482 			cx++;
1483 		}
1484 		cx = 0;
1485 		cy++;
1486 	}
1487 }
1488 
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1489 void gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1490 {
1491 	int cx, cy;
1492 	int px, py;
1493 	int fline;
1494 	const int xuppper = (x > INT_MAX - f->h) ? INT_MAX : x + f->h;
1495 	const int ylower = (y < INT_MIN + f->w) ? INT_MIN : y - f->w;
1496 	cx = 0;
1497 	cy = 0;
1498 #ifdef CHARSET_EBCDIC
1499 	c = ASC (c);
1500 #endif /*CHARSET_EBCDIC */
1501 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1502 		return;
1503 	}
1504 	fline = (c - f->offset) * f->h * f->w;
1505 	for (py = y; py > ylower; py--) {
1506 		for (px = x; px < xuppper; px++) {
1507 			if (f->data[fline + cy * f->w + cx]) {
1508 				gdImageSetPixel(im, px, py, color);
1509 			}
1510 			cy++;
1511 		}
1512 		cy = 0;
1513 		cx++;
1514 	}
1515 }
1516 
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1517 void gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1518 {
1519 	int i;
1520 	int l;
1521 	l = strlen ((char *) s);
1522 	for (i = 0; (i < l); i++) {
1523 		gdImageChar(im, f, x, y, s[i], color);
1524 		x += f->w;
1525 	}
1526 }
1527 
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1528 void gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
1529 {
1530 	int i;
1531 	int l;
1532 	l = strlen ((char *) s);
1533 	for (i = 0; (i < l); i++) {
1534 		gdImageCharUp(im, f, x, y, s[i], color);
1535 		y -= f->w;
1536 	}
1537 }
1538 
1539 static int strlen16 (unsigned short *s);
1540 
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1541 void gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1542 {
1543 	int i;
1544 	int l;
1545 	l = strlen16(s);
1546 	for (i = 0; (i < l); i++) {
1547 		gdImageChar(im, f, x, y, s[i], color);
1548 		x += f->w;
1549 	}
1550 }
1551 
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1552 void gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
1553 {
1554 	int i;
1555 	int l;
1556 	l = strlen16(s);
1557 	for (i = 0; i < l; i++) {
1558 		gdImageCharUp(im, f, x, y, s[i], color);
1559 		y -= f->w;
1560 	}
1561 }
1562 
strlen16(unsigned short * s)1563 static int strlen16 (unsigned short *s)
1564 {
1565 	int len = 0;
1566 	while (*s) {
1567 		s++;
1568 		len++;
1569 	}
1570 	return len;
1571 }
1572 
1573 #ifndef HAVE_LSQRT
1574 /* If you don't have a nice square root function for longs, you can use
1575    ** this hack
1576  */
lsqrt(long n)1577 long lsqrt (long n)
1578 {
1579  	long result = (long) sqrt ((double) n);
1580 	return result;
1581 }
1582 #endif
1583 
1584 /* s and e are integers modulo 360 (degrees), with 0 degrees
1585    being the rightmost extreme and degrees changing clockwise.
1586    cx and cy are the center in pixels; w and h are the horizontal
1587    and vertical diameter in pixels. */
1588 
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)1589 void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
1590 {
1591 	gdImageFilledArc(im, cx, cy, w, h, s, e, color, gdNoFill);
1592 }
1593 
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)1594 void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
1595 {
1596 	gdPoint pts[363];
1597 	int i, pti;
1598 	int lx = 0, ly = 0;
1599 	int fx = 0, fy = 0;
1600 	int startx = -1, starty = -1, endx = -1, endy = -1;
1601 
1602     if ((s % 360)  == (e % 360)) {
1603 		s = 0; e = 360;
1604 	} else {
1605 		if (s > 360) {
1606 			s = s % 360;
1607 		}
1608 
1609 		if (e > 360) {
1610 			e = e % 360;
1611 		}
1612 
1613 		while (s < 0) {
1614 			s += 360;
1615 		}
1616 
1617 		while (e < s) {
1618 			e += 360;
1619 		}
1620 		if (s == e) {
1621 			s = 0; e = 360;
1622 		}
1623 	}
1624 
1625 	for (i = s, pti = 1; i <= e; i++, pti++) {
1626 		int x, y;
1627 		x = endx = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
1628 		y = endy = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
1629 		if (i != s) {
1630 			if (!(style & gdChord)) {
1631 				if (style & gdNoFill) {
1632 					gdImageLine(im, lx, ly, x, y, color);
1633 				} else {
1634 					if (y == ly) {
1635 						pti--; /* don't add this point */
1636 						if (((i > 270 || i < 90) && x > lx) || ((i >  90 && i < 270) && x < lx)) {
1637 							/* replace the old x coord, if increasing on the
1638 							   right side or decreasing on the left side */
1639 							pts[pti].x = x;
1640 						}
1641 					} else {
1642 						pts[pti].x = x;
1643 						pts[pti].y = y;
1644 					}
1645   				}
1646 			}
1647 		} else {
1648 			fx = x;
1649 			fy = y;
1650 			if (!(style & (gdChord | gdNoFill))) {
1651 				pts[0].x = cx;
1652 				pts[0].y = cy;
1653 				pts[pti].x = startx = x;
1654 				pts[pti].y = starty = y;
1655 			}
1656 		}
1657 		lx = x;
1658 		ly = y;
1659 	}
1660 	if (style & gdChord) {
1661 		if (style & gdNoFill) {
1662 			if (style & gdEdged) {
1663 				gdImageLine(im, cx, cy, lx, ly, color);
1664 				gdImageLine(im, cx, cy, fx, fy, color);
1665 			}
1666 			gdImageLine(im, fx, fy, lx, ly, color);
1667 		} else {
1668 			pts[0].x = fx;
1669 			pts[0].y = fy;
1670 			pts[1].x = lx;
1671 			pts[1].y = ly;
1672 			pts[2].x = cx;
1673 			pts[2].y = cy;
1674 			gdImageFilledPolygon(im, pts, 3, color);
1675 		}
1676 	} else {
1677 		if (style & gdNoFill) {
1678 			if (style & gdEdged) {
1679 				gdImageLine(im, cx, cy, lx, ly, color);
1680 				gdImageLine(im, cx, cy, fx, fy, color);
1681 			}
1682 		} else {
1683 			if (e - s < 360) {
1684 				if (pts[1].x != startx && pts[1].y == starty) {
1685 					/* start point has been removed due to y-coord fix => insert it */
1686 					for (i = pti; i > 1; i--) {
1687 						pts[i].x = pts[i-1].x;
1688 						pts[i].y = pts[i-1].y;
1689 					}
1690 					pts[1].x = startx;
1691 					pts[1].y = starty;
1692 					pti++;
1693 				}
1694 				if (pts[pti-1].x != endx && pts[pti-1].y == endy) {
1695 					/* end point has been removed due to y-coord fix => insert it */
1696 					pts[pti].x = endx;
1697 					pts[pti].y = endy;
1698 					pti++;
1699 				}
1700 			}
1701 			pts[pti].x = cx;
1702 			pts[pti].y = cy;
1703 			gdImageFilledPolygon(im, pts, pti+1, color);
1704 		}
1705 	}
1706 }
1707 
1708 /**
1709  * Integer Ellipse functions (gdImageEllipse and gdImageFilledEllipse)
1710  * Function added by Pierre-Alain Joye 02/08/2003 (paj@pearfr.org)
1711  * See the ellipse function simplification for the equation
1712  * as well as the midpoint algorithm.
1713  */
1714 
gdImageEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1715 void gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c)
1716 {
1717 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
1718 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
1719 
1720 	a=w>>1;
1721 	b=h>>1;
1722 	gdImageSetPixel(im,mx+a, my, c);
1723 	gdImageSetPixel(im,mx-a, my, c);
1724 	mx1 = mx-a;my1 = my;
1725 	mx2 = mx+a;my2 = my;
1726 
1727 	aq = a * a;
1728 	bq = b * b;
1729 	dx = aq << 1;
1730 	dy = bq << 1;
1731 	r  = a * bq;
1732 	rx = r << 1;
1733 	ry = 0;
1734 	x = a;
1735 	while (x > 0){
1736 		if (r > 0) {
1737 			my1++;my2--;
1738 			ry +=dx;
1739 			r  -=ry;
1740 		}
1741 		if (r <= 0){
1742 			x--;
1743 			mx1++;mx2--;
1744 			rx -=dy;
1745 			r  +=rx;
1746 		}
1747 		gdImageSetPixel(im,mx1, my1, c);
1748 		gdImageSetPixel(im,mx1, my2, c);
1749 		gdImageSetPixel(im,mx2, my1, c);
1750 		gdImageSetPixel(im,mx2, my2, c);
1751 	}
1752 }
1753 
gdImageFilledEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1754 void gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
1755 {
1756 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
1757 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
1758 	int i;
1759 	int old_y2;
1760 
1761 	a=w>>1;
1762 	b=h>>1;
1763 
1764 	for (x = mx-a; x <= mx+a; x++) {
1765 		gdImageSetPixel(im, x, my, c);
1766 	}
1767 
1768 	mx1 = mx-a;my1 = my;
1769 	mx2 = mx+a;my2 = my;
1770 
1771 	aq = a * a;
1772 	bq = b * b;
1773 	dx = aq << 1;
1774 	dy = bq << 1;
1775 	r  = a * bq;
1776 	rx = r << 1;
1777 	ry = 0;
1778 	x = a;
1779 	old_y2=-2;
1780 	while (x > 0){
1781 		if (r > 0) {
1782 			my1++;my2--;
1783 			ry +=dx;
1784 			r  -=ry;
1785 		}
1786 		if (r <= 0){
1787 			x--;
1788 			mx1++;mx2--;
1789 			rx -=dy;
1790 			r  +=rx;
1791 		}
1792 		if(old_y2!=my2){
1793 			for(i=mx1;i<=mx2;i++){
1794 				gdImageSetPixel(im,i,my1,c);
1795 				gdImageSetPixel(im,i,my2,c);
1796 			}
1797 		}
1798 		old_y2 = my2;
1799 	}
1800 }
1801 
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)1802 void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
1803 {
1804 	int lastBorder;
1805 	/* Seek left */
1806 	int leftLimit = -1, rightLimit;
1807 	int i, restoreAlphaBlending = 0;
1808 
1809 	if (border < 0 || color < 0) {
1810 		/* Refuse to fill to a non-solid border */
1811 		return;
1812 	}
1813 
1814 	if (!im->trueColor) {
1815 		if ((color > (im->colorsTotal - 1)) || (border > (im->colorsTotal - 1)) || (color < 0)) {
1816 			return;
1817 		}
1818 	}
1819 
1820 	restoreAlphaBlending = im->alphaBlendingFlag;
1821 	im->alphaBlendingFlag = 0;
1822 
1823 	if (x >= im->sx) {
1824 		x = im->sx - 1;
1825 	} else if (x < 0) {
1826 		x = 0;
1827 	}
1828 	if (y >= im->sy) {
1829 		y = im->sy - 1;
1830 	} else if (y < 0) {
1831 		y = 0;
1832 	}
1833 
1834 	for (i = x; i >= 0; i--) {
1835 		if (gdImageGetPixel(im, i, y) == border) {
1836 			break;
1837 		}
1838 		gdImageSetPixel(im, i, y, color);
1839 		leftLimit = i;
1840 	}
1841 	if (leftLimit == -1) {
1842 		im->alphaBlendingFlag = restoreAlphaBlending;
1843 		return;
1844 	}
1845 	/* Seek right */
1846 	rightLimit = x;
1847 	for (i = (x + 1); i < im->sx; i++) {
1848 		if (gdImageGetPixel(im, i, y) == border) {
1849 			break;
1850 		}
1851 		gdImageSetPixel(im, i, y, color);
1852 		rightLimit = i;
1853 	}
1854 	/* Look at lines above and below and start paints */
1855 	/* Above */
1856 	if (y > 0) {
1857 		lastBorder = 1;
1858 		for (i = leftLimit; i <= rightLimit; i++) {
1859 			int c = gdImageGetPixel(im, i, y - 1);
1860 			if (lastBorder) {
1861 				if ((c != border) && (c != color)) {
1862 					gdImageFillToBorder(im, i, y - 1, border, color);
1863 					lastBorder = 0;
1864 				}
1865 			} else if ((c == border) || (c == color)) {
1866 				lastBorder = 1;
1867 			}
1868 		}
1869 	}
1870 
1871 	/* Below */
1872 	if (y < ((im->sy) - 1)) {
1873 		lastBorder = 1;
1874 		for (i = leftLimit; i <= rightLimit; i++) {
1875 			int c = gdImageGetPixel(im, i, y + 1);
1876 
1877 			if (lastBorder) {
1878 				if ((c != border) && (c != color)) {
1879 					gdImageFillToBorder(im, i, y + 1, border, color);
1880 					lastBorder = 0;
1881 				}
1882 			} else if ((c == border) || (c == color)) {
1883 				lastBorder = 1;
1884 			}
1885 		}
1886 	}
1887 	im->alphaBlendingFlag = restoreAlphaBlending;
1888 }
1889 
1890 /*
1891  * set the pixel at (x,y) and its 4-connected neighbors
1892  * with the same pixel value to the new pixel value nc (new color).
1893  * A 4-connected neighbor:  pixel above, below, left, or right of a pixel.
1894  * ideas from comp.graphics discussions.
1895  * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
1896  * contain the same color as the color to fill. To do not bloat normal filling
1897  * code I added a 2nd private function.
1898  */
1899 
1900 /* horizontal segment of scan line y */
1901 struct seg {int y, xl, xr, dy;};
1902 
1903 /* max depth of stack */
1904 #define FILL_MAX ((int)(im->sy*im->sx)/4)
1905 #define FILL_PUSH(Y, XL, XR, DY) \
1906     if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
1907     {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
1908 
1909 #define FILL_POP(Y, XL, XR, DY) \
1910     {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
1911 
1912 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
1913 
gdImageFill(gdImagePtr im,int x,int y,int nc)1914 void gdImageFill(gdImagePtr im, int x, int y, int nc)
1915 {
1916 	int l, x1, x2, dy;
1917 	int oc;   /* old pixel value */
1918 	int wx2,wy2;
1919 
1920 	int alphablending_bak;
1921 
1922 	/* stack of filled segments */
1923 	/* struct seg stack[FILL_MAX],*sp = stack; */
1924 	struct seg *stack = NULL;
1925 	struct seg *sp;
1926 
1927 	if (!im->trueColor && nc > (im->colorsTotal -1)) {
1928 		return;
1929 	}
1930 
1931 	alphablending_bak = im->alphaBlendingFlag;
1932 	im->alphaBlendingFlag = 0;
1933 
1934 	if (nc==gdTiled){
1935 		_gdImageFillTiled(im,x,y,nc);
1936 		im->alphaBlendingFlag = alphablending_bak;
1937 		return;
1938 	}
1939 
1940 	wx2=im->sx;wy2=im->sy;
1941 	oc = gdImageGetPixel(im, x, y);
1942 	if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
1943 		im->alphaBlendingFlag = alphablending_bak;
1944 		return;
1945 	}
1946 
1947 	/* Do not use the 4 neighbors implementation with
1948 	 * small images
1949 	 */
1950 	if (im->sx < 4) {
1951 		int ix = x, iy = y, c;
1952 		do {
1953 			do {
1954 				c = gdImageGetPixel(im, ix, iy);
1955 				if (c != oc) {
1956 					goto done;
1957 				}
1958 				gdImageSetPixel(im, ix, iy, nc);
1959 			} while(ix++ < (im->sx -1));
1960 			ix = x;
1961 		} while(iy++ < (im->sy -1));
1962 		goto done;
1963 	}
1964 
1965 	stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
1966 	sp = stack;
1967 
1968 	/* required! */
1969 	FILL_PUSH(y,x,x,1);
1970 	/* seed segment (popped 1st) */
1971  	FILL_PUSH(y+1, x, x, -1);
1972 	while (sp>stack) {
1973 		FILL_POP(y, x1, x2, dy);
1974 
1975 		for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
1976 			gdImageSetPixel(im,x, y, nc);
1977 		}
1978 		if (x>=x1) {
1979 			goto skip;
1980 		}
1981 		l = x+1;
1982 
1983                 /* leak on left? */
1984 		if (l<x1) {
1985 			FILL_PUSH(y, l, x1-1, -dy);
1986 		}
1987 		x = x1+1;
1988 		do {
1989 			for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
1990 				gdImageSetPixel(im, x, y, nc);
1991 			}
1992 			FILL_PUSH(y, l, x-1, dy);
1993 			/* leak on right? */
1994 			if (x>x2+1) {
1995 				FILL_PUSH(y, x2+1, x-1, -dy);
1996 			}
1997 skip:
1998 			for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
1999 
2000 			l = x;
2001 		} while (x<=x2);
2002 	}
2003 
2004 	efree(stack);
2005 
2006 done:
2007 	im->alphaBlendingFlag = alphablending_bak;
2008 }
2009 
_gdImageFillTiled(gdImagePtr im,int x,int y,int nc)2010 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
2011 {
2012 	int i, l, x1, x2, dy;
2013 	int oc;   /* old pixel value */
2014 	int wx2,wy2;
2015 	/* stack of filled segments */
2016 	struct seg *stack;
2017 	struct seg *sp;
2018 	char **pts;
2019 
2020 	if (!im->tile) {
2021 		return;
2022 	}
2023 
2024 	wx2=im->sx;wy2=im->sy;
2025 
2026 	nc =  gdImageTileGet(im,x,y);
2027 
2028 	pts = (char **) ecalloc(im->sy + 1, sizeof(char *));
2029 	for (i = 0; i < im->sy + 1; i++) {
2030 		pts[i] = (char *) ecalloc(im->sx + 1, sizeof(char));
2031 	}
2032 
2033 	stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
2034 	sp = stack;
2035 
2036 	oc = gdImageGetPixel(im, x, y);
2037 
2038 	/* required! */
2039 	FILL_PUSH(y,x,x,1);
2040 	/* seed segment (popped 1st) */
2041  	FILL_PUSH(y+1, x, x, -1);
2042 	while (sp>stack) {
2043 		FILL_POP(y, x1, x2, dy);
2044 		for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) {
2045 			nc = gdImageTileGet(im,x,y);
2046 			pts[y][x] = 1;
2047 			gdImageSetPixel(im,x, y, nc);
2048 		}
2049 		if (x>=x1) {
2050 			goto skip;
2051 		}
2052 		l = x+1;
2053 
2054 		/* leak on left? */
2055 		if (l<x1) {
2056 			FILL_PUSH(y, l, x1-1, -dy);
2057 		}
2058 		x = x1+1;
2059 		do {
2060 			for(; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc); x++) {
2061 				nc = gdImageTileGet(im,x,y);
2062 				pts[y][x] = 1;
2063 				gdImageSetPixel(im, x, y, nc);
2064 			}
2065 			FILL_PUSH(y, l, x-1, dy);
2066 			/* leak on right? */
2067 			if (x>x2+1) {
2068 				FILL_PUSH(y, x2+1, x-1, -dy);
2069 			}
2070 skip:
2071 			for(x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++);
2072 			l = x;
2073 		} while (x<=x2);
2074 	}
2075 
2076 	for(i = 0; i < im->sy + 1; i++) {
2077 		efree(pts[i]);
2078 	}
2079 
2080 	efree(pts);
2081 	efree(stack);
2082 }
2083 
2084 
2085 
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2086 void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2087 {
2088 	int thick = im->thick;
2089 	int t;
2090 
2091 	if (x1 == x2 && y1 == y2 && thick == 1) {
2092 		gdImageSetPixel(im, x1, y1, color);
2093 		return;
2094 	}
2095 
2096 	if (y2 < y1) {
2097 		t=y1;
2098 		y1 = y2;
2099 		y2 = t;
2100 	}
2101 
2102 	if (x2 < x1) {
2103 		t = x1;
2104 		x1 = x2;
2105 		x2 = t;
2106 	}
2107 
2108 	if (thick > 1) {
2109 		int cx, cy, x1ul, y1ul, x2lr, y2lr;
2110 		int half = thick >> 1;
2111 
2112 		x1ul = x1 - half;
2113 		y1ul = y1 - half;
2114 
2115 		x2lr = x2 + half;
2116 		y2lr = y2 + half;
2117 
2118 		cy = y1ul + thick;
2119 		while (cy-- > y1ul) {
2120 			cx = x1ul - 1;
2121 			while (cx++ < x2lr) {
2122 				gdImageSetPixel(im, cx, cy, color);
2123 			}
2124 		}
2125 
2126 		cy = y2lr - thick;
2127 		while (cy++ < y2lr) {
2128 			cx = x1ul - 1;
2129 			while (cx++ < x2lr) {
2130 				gdImageSetPixel(im, cx, cy, color);
2131 			}
2132 		}
2133 
2134 		cy = y1ul + thick - 1;
2135 		while (cy++ < y2lr -thick) {
2136 			cx = x1ul - 1;
2137 			while (cx++ < x1ul + thick) {
2138 				gdImageSetPixel(im, cx, cy, color);
2139 			}
2140 		}
2141 
2142 		cy = y1ul + thick - 1;
2143 		while (cy++ < y2lr -thick) {
2144 			cx = x2lr - thick - 1;
2145 			while (cx++ < x2lr) {
2146 				gdImageSetPixel(im, cx, cy, color);
2147 			}
2148 		}
2149 
2150 		return;
2151 	} else {
2152 		if (x1 == x2 || y1 == y2) {
2153 			gdImageLine(im, x1, y1, x2, y2, color);
2154 		} else {
2155 			gdImageLine(im, x1, y1, x2, y1, color);
2156 			gdImageLine(im, x1, y2, x2, y2, color);
2157 			gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color);
2158 			gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color);
2159 		}
2160 	}
2161 }
2162 
_gdImageFilledHRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2163 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2164 {
2165 	int x, y;
2166 
2167 	if (x1 == x2 && y1 == y2) {
2168 		gdImageSetPixel(im, x1, y1, color);
2169 		return;
2170 	}
2171 
2172 	if (x1 > x2) {
2173 		x = x1;
2174 		x1 = x2;
2175 		x2 = x;
2176 	}
2177 
2178 	if (y1 > y2) {
2179 		y = y1;
2180 		y1 = y2;
2181 		y2 = y;
2182 	}
2183 
2184 	if (x1 < 0) {
2185 		x1 = 0;
2186 	}
2187 
2188 	if (x2 >= gdImageSX(im)) {
2189 		x2 = gdImageSX(im) - 1;
2190 	}
2191 
2192 	if (y1 < 0) {
2193 		y1 = 0;
2194 	}
2195 
2196 	if (y2 >= gdImageSY(im)) {
2197 		y2 = gdImageSY(im) - 1;
2198 	}
2199 
2200 	for (x = x1; (x <= x2); x++) {
2201 		for (y = y1; (y <= y2); y++) {
2202 			gdImageSetPixel (im, x, y, color);
2203 		}
2204 	}
2205 }
2206 
_gdImageFilledVRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2207 static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2208 {
2209 	int x, y;
2210 
2211 	if (x1 == x2 && y1 == y2) {
2212 		gdImageSetPixel(im, x1, y1, color);
2213 		return;
2214 	}
2215 
2216 	if (x1 > x2) {
2217 		x = x1;
2218 		x1 = x2;
2219 		x2 = x;
2220 	}
2221 
2222 	if (y1 > y2) {
2223 		y = y1;
2224 		y1 = y2;
2225 		y2 = y;
2226 	}
2227 
2228 	if (x1 < 0) {
2229 		x1 = 0;
2230 	}
2231 
2232 	if (x2 >= gdImageSX(im)) {
2233 		x2 = gdImageSX(im) - 1;
2234 	}
2235 
2236 	if (y1 < 0) {
2237 		y1 = 0;
2238 	}
2239 
2240 	if (y2 >= gdImageSY(im)) {
2241 		y2 = gdImageSY(im) - 1;
2242 	}
2243 
2244 	for (y = y1; (y <= y2); y++) {
2245 		for (x = x1; (x <= x2); x++) {
2246 			gdImageSetPixel (im, x, y, color);
2247 		}
2248 	}
2249 }
2250 
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2251 void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2252 {
2253 	_gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
2254 }
2255 
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)2256 void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
2257 {
2258 	int c;
2259 	int x, y;
2260 	int tox, toy;
2261 	int i;
2262 	int colorMap[gdMaxColors];
2263 
2264 	if (dst->trueColor) {
2265 		/* 2.0: much easier when the destination is truecolor. */
2266 		/* 2.0.10: needs a transparent-index check that is still valid if
2267 		 * the source is not truecolor. Thanks to Frank Warmerdam.
2268 		 */
2269 
2270 		if (src->trueColor) {
2271 			for (y = 0; (y < h); y++) {
2272 				for (x = 0; (x < w); x++) {
2273 					int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
2274 					if (c != src->transparent) {
2275 						gdImageSetPixel (dst, dstX + x, dstY + y, c);
2276 					}
2277 				}
2278 			}
2279 		} else {
2280 			/* source is palette based */
2281 			for (y = 0; (y < h); y++) {
2282 				for (x = 0; (x < w); x++) {
2283 					int c = gdImageGetPixel (src, srcX + x, srcY + y);
2284 					if (c != src->transparent) {
2285 						gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
2286 					}
2287 				}
2288 			}
2289 		}
2290 		return;
2291 	}
2292 
2293 	/* Palette based to palette based */
2294 	for (i = 0; i < gdMaxColors; i++) {
2295 		colorMap[i] = (-1);
2296 	}
2297 	toy = dstY;
2298 	for (y = srcY; y < (srcY + h); y++) {
2299 		tox = dstX;
2300 		for (x = srcX; x < (srcX + w); x++) {
2301 			int nc;
2302 			int mapTo;
2303 			c = gdImageGetPixel (src, x, y);
2304 			/* Added 7/24/95: support transparent copies */
2305 			if (gdImageGetTransparent (src) == c) {
2306 				tox++;
2307 				continue;
2308 			}
2309 			/* Have we established a mapping for this color? */
2310 			if (src->trueColor) {
2311 				/* 2.05: remap to the palette available in the destination image. This is slow and
2312 				 * works badly, but it beats crashing! Thanks to Padhrig McCarthy.
2313 				 */
2314 				mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c));
2315 			} else if (colorMap[c] == (-1)) {
2316 				/* If it's the same image, mapping is trivial */
2317 				if (dst == src) {
2318 					nc = c;
2319 				} else {
2320 					/* Get best match possible. This function never returns error. */
2321 					nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]);
2322 				}
2323 				colorMap[c] = nc;
2324 				mapTo = colorMap[c];
2325 			} else {
2326 				mapTo = colorMap[c];
2327 			}
2328 			gdImageSetPixel (dst, tox, toy, mapTo);
2329 			tox++;
2330 		}
2331 		toy++;
2332 	}
2333 }
2334 
2335 /* This function is a substitute for real alpha channel operations,
2336    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)2337 void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2338 {
2339 	int c, dc;
2340 	int x, y;
2341 	int tox, toy;
2342 	int ncR, ncG, ncB;
2343 	toy = dstY;
2344 
2345 	for (y = srcY; y < (srcY + h); y++) {
2346 		tox = dstX;
2347 		for (x = srcX; x < (srcX + w); x++) {
2348 			int nc;
2349 			c = gdImageGetPixel(src, x, y);
2350 			/* Added 7/24/95: support transparent copies */
2351 			if (gdImageGetTransparent(src) == c) {
2352 				tox++;
2353 				continue;
2354 			}
2355 			/* If it's the same image, mapping is trivial */
2356 			if (dst == src) {
2357 				nc = c;
2358 			} else {
2359 				dc = gdImageGetPixel(dst, tox, toy);
2360 
2361  				ncR = (int)(gdImageRed (src, c) * (pct / 100.0) + gdImageRed (dst, dc) * ((100 - pct) / 100.0));
2362  				ncG = (int)(gdImageGreen (src, c) * (pct / 100.0) + gdImageGreen (dst, dc) * ((100 - pct) / 100.0));
2363  				ncB = (int)(gdImageBlue (src, c) * (pct / 100.0) + gdImageBlue (dst, dc) * ((100 - pct) / 100.0));
2364 
2365 				/* Find a reasonable color */
2366 				nc = gdImageColorResolve (dst, ncR, ncG, ncB);
2367 			}
2368 			gdImageSetPixel (dst, tox, toy, nc);
2369 			tox++;
2370 		}
2371 		toy++;
2372 	}
2373 }
2374 
2375 /* This function is a substitute for real alpha channel operations,
2376    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)2377 void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
2378 {
2379 	int c, dc;
2380 	int x, y;
2381 	int tox, toy;
2382 	int ncR, ncG, ncB;
2383 	float g;
2384 	toy = dstY;
2385 
2386 	for (y = srcY; (y < (srcY + h)); y++) {
2387 		tox = dstX;
2388 		for (x = srcX; (x < (srcX + w)); x++) {
2389 			int nc;
2390 			c = gdImageGetPixel (src, x, y);
2391 			/* Added 7/24/95: support transparent copies */
2392 			if (gdImageGetTransparent(src) == c) {
2393 				tox++;
2394 				continue;
2395 			}
2396 
2397 			/*
2398 			 * If it's the same image, mapping is NOT trivial since we
2399 			 * merge with greyscale target, but if pct is 100, the grey
2400 			 * value is not used, so it becomes trivial. pjw 2.0.12.
2401 			 */
2402 			if (dst == src && pct == 100) {
2403 				nc = c;
2404 			} else {
2405 				dc = gdImageGetPixel(dst, tox, toy);
2406 				g = (0.29900f * gdImageRed(dst, dc)) + (0.58700f * gdImageGreen(dst, dc)) + (0.11400f * gdImageBlue(dst, dc));
2407 
2408 				ncR = (int)(gdImageRed (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2409 				ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2410 				ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
2411 
2412 
2413 				/* First look for an exact match */
2414 				nc = gdImageColorExact(dst, ncR, ncG, ncB);
2415 				if (nc == (-1)) {
2416 					/* No, so try to allocate it */
2417 					nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
2418 					/* If we're out of colors, go for the closest color */
2419 					if (nc == (-1)) {
2420 						nc = gdImageColorClosest(dst, ncR, ncG, ncB);
2421 					}
2422 				}
2423 			}
2424 			gdImageSetPixel(dst, tox, toy, nc);
2425 			tox++;
2426 		}
2427 		toy++;
2428 	}
2429 }
2430 
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2431 void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2432 {
2433 	int c;
2434 	int x, y;
2435 	int tox, toy;
2436 	int ydest;
2437 	int i;
2438 	int colorMap[gdMaxColors];
2439 	/* Stretch vectors */
2440 	int *stx, *sty;
2441 
2442 	if (overflow2(sizeof(int), srcW)) {
2443 		return;
2444 	}
2445 	if (overflow2(sizeof(int), srcH)) {
2446 		return;
2447 	}
2448 
2449 	stx = (int *) gdMalloc (sizeof (int) * srcW);
2450 	sty = (int *) gdMalloc (sizeof (int) * srcH);
2451 
2452 	/* Fixed by Mao Morimoto 2.0.16 */
2453 	for (i = 0; (i < srcW); i++) {
2454 		stx[i] = dstW * (i+1) / srcW - dstW * i / srcW ;
2455 	}
2456 	for (i = 0; (i < srcH); i++) {
2457 		sty[i] = dstH * (i+1) / srcH - dstH * i / srcH ;
2458 	}
2459 	for (i = 0; (i < gdMaxColors); i++) {
2460 		colorMap[i] = (-1);
2461 	}
2462 	toy = dstY;
2463 	for (y = srcY; (y < (srcY + srcH)); y++) {
2464 		for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
2465 			tox = dstX;
2466 			for (x = srcX; (x < (srcX + srcW)); x++) {
2467 				int nc = 0;
2468 				int mapTo;
2469 				if (!stx[x - srcX]) {
2470 					continue;
2471 				}
2472 				if (dst->trueColor) {
2473 					/* 2.0.9: Thorben Kundinger: Maybe the source image is not a truecolor image */
2474 					if (!src->trueColor) {
2475 					  	int tmp = gdImageGetPixel (src, x, y);
2476 		  				mapTo = gdImageGetTrueColorPixel (src, x, y);
2477 					  	if (gdImageGetTransparent (src) == tmp) {
2478 							/* 2.0.21, TK: not tox++ */
2479 							tox += stx[x - srcX];
2480 					  		continue;
2481 					  	}
2482 					} else {
2483 						/* TK: old code follows */
2484 					  	mapTo = gdImageGetTrueColorPixel (src, x, y);
2485 						/* Added 7/24/95: support transparent copies */
2486 						if (gdImageGetTransparent (src) == mapTo) {
2487 							/* 2.0.21, TK: not tox++ */
2488 							tox += stx[x - srcX];
2489 							continue;
2490 						}
2491 					}
2492 				} else {
2493 					c = gdImageGetPixel (src, x, y);
2494 					/* Added 7/24/95: support transparent copies */
2495 					if (gdImageGetTransparent (src) == c) {
2496 					      tox += stx[x - srcX];
2497 					      continue;
2498 					}
2499 					if (src->trueColor) {
2500 					      /* Remap to the palette available in the destination image. This is slow and works badly. */
2501 					      mapTo = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c),
2502 					      					    gdTrueColorGetGreen(c),
2503 					      					    gdTrueColorGetBlue(c),
2504 					      					    gdTrueColorGetAlpha (c));
2505 					} else {
2506 						/* Have we established a mapping for this color? */
2507 						if (colorMap[c] == (-1)) {
2508 							/* If it's the same image, mapping is trivial */
2509 							if (dst == src) {
2510 								nc = c;
2511 							} else {
2512 								/* Find or create the best match */
2513 								/* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
2514 								nc = gdImageColorResolveAlpha(dst, gdImageRed(src, c),
2515 												   gdImageGreen(src, c),
2516 												   gdImageBlue(src, c),
2517 												   gdImageAlpha(src, c));
2518 							}
2519 							colorMap[c] = nc;
2520 						}
2521 						mapTo = colorMap[c];
2522 					}
2523 				}
2524 				for (i = 0; (i < stx[x - srcX]); i++) {
2525 					gdImageSetPixel (dst, tox, toy, mapTo);
2526 					tox++;
2527 				}
2528 			}
2529 			toy++;
2530 		}
2531 	}
2532 	gdFree (stx);
2533 	gdFree (sty);
2534 }
2535 
2536 /* When gd 1.x was first created, floating point was to be avoided.
2537    These days it is often faster than table lookups or integer
2538    arithmetic. The routine below is shamelessly, gloriously
2539    floating point. TBB */
2540 
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2541 void gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2542 {
2543 	int x, y;
2544 	double sy1, sy2, sx1, sx2;
2545 
2546 	if (!dst->trueColor) {
2547 		gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
2548 		return;
2549 	}
2550 	for (y = dstY; (y < dstY + dstH); y++) {
2551 		sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
2552 		sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
2553 		for (x = dstX; (x < dstX + dstW); x++) {
2554 			double sx, sy;
2555 			double spixels = 0;
2556 			double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
2557 			double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
2558 			sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
2559 			sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
2560 			sy = sy1;
2561 			do {
2562 				double yportion;
2563 				if (floor_cast(sy) == floor_cast(sy1)) {
2564 					yportion = 1.0f - (sy - floor_cast(sy));
2565 					if (yportion > sy2 - sy1) {
2566 						yportion = sy2 - sy1;
2567 					}
2568 					sy = floor_cast(sy);
2569 				} else if (sy == floorf(sy2)) {
2570 					yportion = sy2 - floor_cast(sy2);
2571 				} else {
2572 					yportion = 1.0f;
2573 				}
2574 				sx = sx1;
2575 				do {
2576 					double xportion;
2577 					double pcontribution;
2578 					int p;
2579 					if (floorf(sx) == floor_cast(sx1)) {
2580 						xportion = 1.0f - (sx - floor_cast(sx));
2581 						if (xportion > sx2 - sx1) {
2582 							xportion = sx2 - sx1;
2583 						}
2584 						sx = floor_cast(sx);
2585 					} else if (sx == floorf(sx2)) {
2586 						xportion = sx2 - floor_cast(sx2);
2587 					} else {
2588 						xportion = 1.0f;
2589 					}
2590 					pcontribution = xportion * yportion;
2591 					p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
2592 
2593 					alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
2594 					red += gdTrueColorGetRed (p) * alpha_factor;
2595 					green += gdTrueColorGetGreen (p) * alpha_factor;
2596 					blue += gdTrueColorGetBlue (p) * alpha_factor;
2597 					alpha += gdTrueColorGetAlpha (p) * pcontribution;
2598 					alpha_sum += alpha_factor;
2599 					contrib_sum += pcontribution;
2600 					spixels += xportion * yportion;
2601 					sx += 1.0f;
2602 				}
2603 				while (sx < sx2);
2604 
2605 				sy += 1.0f;
2606 			}
2607 
2608 			while (sy < sy2);
2609 
2610 			if (spixels != 0.0f) {
2611 				red /= spixels;
2612 				green /= spixels;
2613 				blue /= spixels;
2614 				alpha /= spixels;
2615 			}
2616 			if ( alpha_sum != 0.0f) {
2617 				if( contrib_sum != 0.0f) {
2618 					alpha_sum /= contrib_sum;
2619 				}
2620 				red /= alpha_sum;
2621 				green /= alpha_sum;
2622 				blue /= alpha_sum;
2623 			}
2624 			/* Round up closest next channel value and clamp to max channel value */
2625 			red = red >= 255.5 ? 255 : red+0.5;
2626 			blue = blue >= 255.5 ? 255 : blue+0.5;
2627 			green = green >= 255.5 ? 255 : green+0.5;
2628 			alpha = alpha >= gdAlphaMax+0.5 ? gdAlphaMax : alpha+0.5;
2629 			gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int)red, (int)green, (int)blue, (int)alpha));
2630 		}
2631 	}
2632 }
2633 
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)2634 void gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2635 {
2636 	if (n <= 0) {
2637 		return;
2638 	}
2639 
2640 
2641 	gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
2642 	gdImageOpenPolygon (im, p, n, c);
2643 }
2644 
gdImageOpenPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2645 void gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2646 {
2647 	int i;
2648 	int lx, ly;
2649 
2650 	if (n <= 0) {
2651 		return;
2652 	}
2653 
2654 	lx = p->x;
2655 	ly = p->y;
2656 	for (i = 1; i < n; i++) {
2657 		p++;
2658 		gdImageLine(im, lx, ly, p->x, p->y, c);
2659 		lx = p->x;
2660 		ly = p->y;
2661 	}
2662 }
2663 
2664 int gdCompareInt (const void *a, const void *b);
2665 
2666 /* THANKS to Kirsten Schulz for the polygon fixes! */
2667 
2668 /* The intersection finding technique of this code could be improved
2669  * by remembering the previous intertersection, and by using the slope.
2670  * That could help to adjust intersections  to produce a nice
2671  * interior_extrema.
2672  */
2673 
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2674 void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2675 {
2676 	int i;
2677 	int y;
2678 	int miny, maxy, pmaxy;
2679 	int x1, y1;
2680 	int x2, y2;
2681 	int ind1, ind2;
2682 	int ints;
2683 	int fill_color;
2684 
2685 	if (n <= 0) {
2686 		return;
2687 	}
2688 
2689 	if (overflow2(sizeof(int), n)) {
2690 		return;
2691 	}
2692 
2693 	if (c == gdAntiAliased) {
2694 		fill_color = im->AA_color;
2695 	} else {
2696 		fill_color = c;
2697 	}
2698 
2699 	if (!im->polyAllocated) {
2700 		im->polyInts = (int *) gdMalloc(sizeof(int) * n);
2701 		im->polyAllocated = n;
2702 	}
2703 	if (im->polyAllocated < n) {
2704 		while (im->polyAllocated < n) {
2705 			im->polyAllocated *= 2;
2706 		}
2707 		if (overflow2(sizeof(int), im->polyAllocated)) {
2708 			return;
2709 		}
2710 		im->polyInts = (int *) gdRealloc(im->polyInts, sizeof(int) * im->polyAllocated);
2711 	}
2712 	miny = p[0].y;
2713 	maxy = p[0].y;
2714 	for (i = 1; i < n; i++) {
2715 		if (p[i].y < miny) {
2716 			miny = p[i].y;
2717 		}
2718 		if (p[i].y > maxy) {
2719 			maxy = p[i].y;
2720 		}
2721 	}
2722 	/* necessary special case: horizontal line */
2723 	if (n > 1 && miny == maxy) {
2724 		x1 = x2 = p[0].x;
2725 		for (i = 1; (i < n); i++) {
2726 			if (p[i].x < x1) {
2727 				x1 = p[i].x;
2728 			} else if (p[i].x > x2) {
2729 				x2 = p[i].x;
2730 			}
2731 		}
2732 		gdImageLine(im, x1, miny, x2, miny, c);
2733 		return;
2734 	}
2735 	pmaxy = maxy;
2736 	/* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
2737 	if (miny < 0) {
2738 		miny = 0;
2739 	}
2740 	if (maxy >= gdImageSY(im)) {
2741 		maxy = gdImageSY(im) - 1;
2742 	}
2743 
2744 	/* Fix in 1.3: count a vertex only once */
2745 	for (y = miny; y <= maxy; y++) {
2746 		/*1.4           int interLast = 0; */
2747 		/*              int dirLast = 0; */
2748 		/*              int interFirst = 1; */
2749 		ints = 0;
2750 		for (i = 0; i < n; i++) {
2751 			if (!i) {
2752 				ind1 = n - 1;
2753 				ind2 = 0;
2754 			} else {
2755 				ind1 = i - 1;
2756 				ind2 = i;
2757 			}
2758 			y1 = p[ind1].y;
2759 			y2 = p[ind2].y;
2760 			if (y1 < y2) {
2761 				x1 = p[ind1].x;
2762 				x2 = p[ind2].x;
2763 			} else if (y1 > y2) {
2764 				y2 = p[ind1].y;
2765 				y1 = p[ind2].y;
2766 				x2 = p[ind1].x;
2767 				x1 = p[ind2].x;
2768 			} else {
2769 				continue;
2770 			}
2771 			/* Do the following math as float intermediately, and round to ensure
2772 			 * that Polygon and FilledPolygon for the same set of points have the
2773 			 * same footprint.
2774 			 */
2775 			if (y >= y1 && y < y2) {
2776 				im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
2777 			} else if (y == pmaxy && y == y2) {
2778 				im->polyInts[ints++] = x2;
2779 			}
2780 		}
2781 		qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2782 
2783 		for (i = 0; i < ints - 1; i += 2) {
2784 			gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, fill_color);
2785 		}
2786 	}
2787 
2788 	/* If we are drawing this AA, then redraw the border with AA lines. */
2789 	if (c == gdAntiAliased) {
2790 		gdImagePolygon(im, p, n, c);
2791 	}
2792 }
2793 
gdCompareInt(const void * a,const void * b)2794 int gdCompareInt (const void *a, const void *b)
2795 {
2796 	return (*(const int *) a) - (*(const int *) b);
2797 }
2798 
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)2799 void gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
2800 {
2801 	if (im->style) {
2802 		gdFree(im->style);
2803 	}
2804 	if (overflow2(sizeof (int), noOfPixels)) {
2805 		return;
2806 	}
2807 	im->style = (int *) gdMalloc(sizeof(int) * noOfPixels);
2808 	memcpy(im->style, style, sizeof(int) * noOfPixels);
2809 	im->styleLength = noOfPixels;
2810 	im->stylePos = 0;
2811 }
2812 
gdImageSetThickness(gdImagePtr im,int thickness)2813 void gdImageSetThickness (gdImagePtr im, int thickness)
2814 {
2815 	im->thick = thickness;
2816 }
2817 
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)2818 void gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
2819 {
2820 	int i;
2821 	im->brush = brush;
2822 	if (!im->trueColor && !im->brush->trueColor) {
2823 		for (i = 0; i < gdImageColorsTotal(brush); i++) {
2824 			int index;
2825 			index = gdImageColorResolveAlpha(im, gdImageRed(brush, i), gdImageGreen(brush, i), gdImageBlue(brush, i), gdImageAlpha(brush, i));
2826 			im->brushColorMap[i] = index;
2827 		}
2828 	}
2829 }
2830 
gdImageSetTile(gdImagePtr im,gdImagePtr tile)2831 void gdImageSetTile (gdImagePtr im, gdImagePtr tile)
2832 {
2833 	int i;
2834 	im->tile = tile;
2835 	if (!im->trueColor && !im->tile->trueColor) {
2836 		for (i = 0; i < gdImageColorsTotal(tile); i++) {
2837 			int index;
2838 			index = gdImageColorResolveAlpha(im, gdImageRed(tile, i), gdImageGreen(tile, i), gdImageBlue(tile, i), gdImageAlpha(tile, i));
2839 			im->tileColorMap[i] = index;
2840 		}
2841 	}
2842 }
2843 
gdImageSetAntiAliased(gdImagePtr im,int c)2844 void gdImageSetAntiAliased (gdImagePtr im, int c)
2845 {
2846 	im->AA = 1;
2847 	im->AA_color = c;
2848 	im->AA_dont_blend = -1;
2849 }
2850 
gdImageSetAntiAliasedDontBlend(gdImagePtr im,int c,int dont_blend)2851 void gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
2852 {
2853 	im->AA = 1;
2854 	im->AA_color = c;
2855 	im->AA_dont_blend = dont_blend;
2856 }
2857 
2858 
gdImageInterlace(gdImagePtr im,int interlaceArg)2859 void gdImageInterlace (gdImagePtr im, int interlaceArg)
2860 {
2861 	im->interlace = interlaceArg;
2862 }
2863 
gdImageCompare(gdImagePtr im1,gdImagePtr im2)2864 int gdImageCompare (gdImagePtr im1, gdImagePtr im2)
2865 {
2866 	int x, y;
2867 	int p1, p2;
2868 	int cmpStatus = 0;
2869 	int sx, sy;
2870 
2871 	if (im1->interlace != im2->interlace) {
2872 		cmpStatus |= GD_CMP_INTERLACE;
2873 	}
2874 
2875 	if (im1->transparent != im2->transparent) {
2876 		cmpStatus |= GD_CMP_TRANSPARENT;
2877 	}
2878 
2879 	if (im1->trueColor != im2->trueColor) {
2880 		cmpStatus |= GD_CMP_TRUECOLOR;
2881 	}
2882 
2883 	sx = im1->sx;
2884 	if (im1->sx != im2->sx) {
2885 		cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
2886 		if (im2->sx < im1->sx) {
2887 			sx = im2->sx;
2888 		}
2889 	}
2890 
2891 	sy = im1->sy;
2892 	if (im1->sy != im2->sy) {
2893 		cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
2894 		if (im2->sy < im1->sy) {
2895 			sy = im2->sy;
2896 		}
2897 	}
2898 
2899 	if (im1->colorsTotal != im2->colorsTotal) {
2900 		cmpStatus |= GD_CMP_NUM_COLORS;
2901 	}
2902 
2903 	for (y = 0; y < sy; y++) {
2904 		for (x = 0; x < sx; x++) {
2905 			p1 = im1->trueColor ? gdImageTrueColorPixel(im1, x, y) : gdImagePalettePixel(im1, x, y);
2906 			p2 = im2->trueColor ? gdImageTrueColorPixel(im2, x, y) : gdImagePalettePixel(im2, x, y);
2907 
2908 			if (gdImageRed(im1, p1) != gdImageRed(im2, p2)) {
2909 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2910 				break;
2911 			}
2912 			if (gdImageGreen(im1, p1) != gdImageGreen(im2, p2)) {
2913 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2914 				break;
2915 			}
2916 			if (gdImageBlue(im1, p1) != gdImageBlue(im2, p2)) {
2917 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2918 				break;
2919 			}
2920 #if 0
2921 			/* Soon we'll add alpha channel to palettes */
2922 			if (gdImageAlpha(im1, p1) != gdImageAlpha(im2, p2)) {
2923 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2924 				break;
2925 			}
2926 #endif
2927 		}
2928 		if (cmpStatus & GD_CMP_COLOR) {
2929 			break;
2930 		}
2931 	}
2932 
2933 	return cmpStatus;
2934 }
2935 
gdAlphaBlend(int dst,int src)2936 int gdAlphaBlend (int dst, int src) {
2937     int src_alpha = gdTrueColorGetAlpha(src);
2938     int dst_alpha, alpha, red, green, blue;
2939     int src_weight, dst_weight, tot_weight;
2940 
2941 /* -------------------------------------------------------------------- */
2942 /*      Simple cases we want to handle fast.                            */
2943 /* -------------------------------------------------------------------- */
2944     if( src_alpha == gdAlphaOpaque )
2945         return src;
2946 
2947     dst_alpha = gdTrueColorGetAlpha(dst);
2948     if( src_alpha == gdAlphaTransparent )
2949         return dst;
2950     if( dst_alpha == gdAlphaTransparent )
2951         return src;
2952 
2953 /* -------------------------------------------------------------------- */
2954 /*      What will the source and destination alphas be?  Note that      */
2955 /*      the destination weighting is substantially reduced as the       */
2956 /*      overlay becomes quite opaque.                                   */
2957 /* -------------------------------------------------------------------- */
2958     src_weight = gdAlphaTransparent - src_alpha;
2959     dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
2960     tot_weight = src_weight + dst_weight;
2961 
2962 /* -------------------------------------------------------------------- */
2963 /*      What red, green and blue result values will we use?             */
2964 /* -------------------------------------------------------------------- */
2965     alpha = src_alpha * dst_alpha / gdAlphaMax;
2966 
2967     red = (gdTrueColorGetRed(src) * src_weight
2968            + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
2969     green = (gdTrueColorGetGreen(src) * src_weight
2970            + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
2971     blue = (gdTrueColorGetBlue(src) * src_weight
2972            + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
2973 
2974 /* -------------------------------------------------------------------- */
2975 /*      Return merged result.                                           */
2976 /* -------------------------------------------------------------------- */
2977     return ((alpha << 24) + (red << 16) + (green << 8) + blue);
2978 
2979 }
2980 
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)2981 void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
2982 {
2983 	im->alphaBlendingFlag = alphaBlendingArg;
2984 }
2985 
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)2986 void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
2987 {
2988 	im->saveAlphaFlag = saveAlphaArg;
2989 }
2990 
gdLayerOverlay(int dst,int src)2991 int gdLayerOverlay (int dst, int src)
2992 {
2993 	int a1, a2;
2994 	a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
2995 	a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
2996 	return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
2997 		(gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
2998 		(gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
2999 		(gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
3000 		);
3001 }
3002 
gdAlphaOverlayColor(int src,int dst,int max)3003 static int gdAlphaOverlayColor (int src, int dst, int max )
3004 {
3005 	/* this function implements the algorithm
3006 	 *
3007 	 * for dst[rgb] < 0.5,
3008 	 *   c[rgb] = 2.src[rgb].dst[rgb]
3009 	 * and for dst[rgb] > 0.5,
3010 	 *   c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
3011 	 *
3012 	 */
3013 
3014 	dst = dst << 1;
3015 	if( dst > max ) {
3016 		/* in the "light" zone */
3017 		return dst + (src << 1) - (dst * src / max) - max;
3018 	} else {
3019 		/* in the "dark" zone */
3020 		return dst * src / max;
3021 	}
3022 }
3023 
gdLayerMultiply(int dst,int src)3024 int gdLayerMultiply (int dst, int src)
3025 {
3026 	int a1, a2, r1, r2, g1, g2, b1, b2;
3027 	a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
3028 	a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
3029 
3030 	r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
3031 	r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
3032 	g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
3033 	g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
3034 	b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
3035 	b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
3036 
3037 	a1 = gdAlphaMax - a1;
3038 	a2 = gdAlphaMax - a2;
3039 	return ( ((a1*a2/gdAlphaMax) << 24) +
3040 			 ((r1*r2/gdRedMax) << 16) +
3041 			 ((g1*g2/gdGreenMax) << 8) +
3042 			 ((b1*b2/gdBlueMax))
3043 		);
3044 }
3045 
gdImageSetClip(gdImagePtr im,int x1,int y1,int x2,int y2)3046 void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
3047 {
3048 	if (x1 < 0) {
3049 		x1 = 0;
3050 	}
3051 	if (x1 >= im->sx) {
3052 		x1 = im->sx - 1;
3053 	}
3054 	if (x2 < 0) {
3055 		x2 = 0;
3056 	}
3057 	if (x2 >= im->sx) {
3058 		x2 = im->sx - 1;
3059 	}
3060 	if (y1 < 0) {
3061 		y1 = 0;
3062 	}
3063 	if (y1 >= im->sy) {
3064 		y1 = im->sy - 1;
3065 	}
3066 	if (y2 < 0) {
3067 		y2 = 0;
3068 	}
3069 	if (y2 >= im->sy) {
3070 		y2 = im->sy - 1;
3071 	}
3072 	im->cx1 = x1;
3073 	im->cy1 = y1;
3074 	im->cx2 = x2;
3075 	im->cy2 = y2;
3076 }
3077 
gdImageGetClip(gdImagePtr im,int * x1P,int * y1P,int * x2P,int * y2P)3078 void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
3079 {
3080 	*x1P = im->cx1;
3081 	*y1P = im->cy1;
3082 	*x2P = im->cx2;
3083 	*y2P = im->cy2;
3084 }
3085 
gdImageSetResolution(gdImagePtr im,const unsigned int res_x,const unsigned int res_y)3086 void gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
3087 {
3088 	if (res_x > 0) im->res_x = res_x;
3089 	if (res_y > 0) im->res_y = res_y;
3090 }
3091 
3092 /* convert a palette image to true color */
gdImagePaletteToTrueColor(gdImagePtr src)3093 int gdImagePaletteToTrueColor(gdImagePtr src)
3094 {
3095 	unsigned int y;
3096 	unsigned int yy;
3097 
3098 	if (src == NULL) {
3099 		return 0;
3100 	}
3101 
3102 	if (src->trueColor == 1) {
3103 		return 1;
3104 	} else {
3105 		unsigned int x;
3106 		const unsigned int sy = gdImageSY(src);
3107 		const unsigned int sx = gdImageSX(src);
3108 
3109 		src->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
3110 		if (src->tpixels == NULL) {
3111 			return 0;
3112 		}
3113 
3114 		for (y = 0; y < sy; y++) {
3115 			const unsigned char *src_row = src->pixels[y];
3116 			int * dst_row;
3117 
3118 			/* no need to calloc it, we overwrite all pxl anyway */
3119 			src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int));
3120 			if (src->tpixels[y] == NULL) {
3121 				goto clean_on_error;
3122 			}
3123 
3124 			dst_row = src->tpixels[y];
3125 			for (x = 0; x < sx; x++) {
3126 				const unsigned char c = *(src_row + x);
3127 				if (c == src->transparent) {
3128 					*(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
3129 				} else {
3130 					*(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3131 				}
3132 			}
3133 		}
3134 	}
3135 
3136 	/* free old palette buffer (y is sy) */
3137 	for (yy = 0; yy < y; yy++) {
3138 		gdFree(src->pixels[yy]);
3139 	}
3140 	gdFree(src->pixels);
3141 	src->trueColor = 1;
3142 	src->pixels = NULL;
3143 	src->alphaBlendingFlag = 0;
3144 	src->saveAlphaFlag = 1;
3145 
3146 	if (src->transparent >= 0) {
3147 		const unsigned char c = src->transparent;
3148 		src->transparent =  gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
3149 	}
3150 
3151 	return 1;
3152 
3153 clean_on_error:
3154 	/* free new true color buffer (y is not allocated, have failed) */
3155 	for (yy = 0; yy < y; yy++) {
3156 		gdFree(src->tpixels[yy]);
3157 	}
3158 	gdFree(src->tpixels);
3159 	return 0;
3160 }
3161