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