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