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