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