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