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