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