1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdarg.h>
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 #include "gd_intern.h"
12 
13 /* 2.03: don't include zlib here or we can't build without PNG */
14 #include "gd.h"
15 #include "gdhelpers.h"
16 #include "gd_color.h"
17 #include "gd_errors.h"
18 
19 /* 2.0.12: this now checks the clipping rectangle */
20 #define gdImageBoundsSafeMacro(im, x, y) (!((((y) < (im)->cy1) || ((y) > (im)->cy2)) || (((x) < (im)->cx1) || ((x) > (im)->cx2))))
21 
22 #ifdef _OSD_POSIX		/* BS2000 uses the EBCDIC char set instead of ASCII */
23 #define CHARSET_EBCDIC
24 #define __attribute__(any)	/*nothing */
25 #endif
26 /*_OSD_POSIX*/
27 
28 #ifndef CHARSET_EBCDIC
29 #define ASC(ch)  ch
30 #else /*CHARSET_EBCDIC */
31 #define ASC(ch) gd_toascii[(unsigned char)ch]
32 static const unsigned char gd_toascii[256] = {
33 	/*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
34 	0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,	/*................ */
35 	/*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
36 	0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f,	/*................ */
37 	/*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
38 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,	/*................ */
39 	/*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
40 	0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,	/*................ */
41 	/*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
42 	0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,	/* .........`.<(+| */
43 	/*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
44 	0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f,	/*&.........!$*);. */
45 	/*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
46 	0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
47 	/*-/........^,%_>?*/
48 	/*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
49 	0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,	/*..........:#@'=" */
50 	/*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
51 	0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1,	/*.abcdefghi...... */
52 	/*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
53 	0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4,	/*.jklmnopqr...... */
54 	/*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
55 	0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae,	/*..stuvwxyz...... */
56 	/*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
57 	0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7,	/*...........[\].. */
58 	/*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
59 	0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5,	/*.ABCDEFGHI...... */
60 	/*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
61 	0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff,	/*.JKLMNOPQR...... */
62 	/*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
63 	0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5,	/*..STUVWXYZ...... */
64 	/*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
65 	0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e	/*0123456789.{.}.~ */
66 };
67 #endif /*CHARSET_EBCDIC */
68 
69 /* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */
70 #define floor_cast(exp) ((long) exp)
71 
72 extern const int gdCosT[];
73 extern const int gdSinT[];
74 
75 /**
76  * Group: Error Handling
77  */
78 
gd_stderr_error(int priority,const char * format,va_list args)79 void gd_stderr_error(int priority, const char *format, va_list args)
80 {
81 	switch (priority) {
82 	case GD_ERROR:
83 		fputs("GD Error: ", stderr);
84 		break;
85 	case GD_WARNING:
86 		fputs("GD Warning: ", stderr);
87 		break;
88 	case GD_NOTICE:
89 		fputs("GD Notice: ", stderr);
90 		break;
91 	case GD_INFO:
92 		fputs("GD Info: ", stderr);
93 		break;
94 	case GD_DEBUG:
95 		fputs("GD Debug: ", stderr);
96 		break;
97 	}
98 	vfprintf(stderr, format, args);
99 	fflush(stderr);
100 }
101 
102 static gdErrorMethod gd_error_method = gd_stderr_error;
103 
_gd_error_ex(int priority,const char * format,va_list args)104 static void _gd_error_ex(int priority, const char *format, va_list args)
105 {
106 	if (gd_error_method) {
107 		gd_error_method(priority, format, args);
108 	}
109 }
110 
gd_error(const char * format,...)111 void gd_error(const char *format, ...)
112 {
113 	va_list args;
114 
115 	va_start(args, format);
116 	_gd_error_ex(GD_WARNING, format, args);
117 	va_end(args);
118 }
gd_error_ex(int priority,const char * format,...)119 void gd_error_ex(int priority, const char *format, ...)
120 {
121 	va_list args;
122 
123 	va_start(args, format);
124 	_gd_error_ex(priority, format, args);
125 	va_end(args);
126 }
127 
128 /*
129 	Function: gdSetErrorMethod
130 */
gdSetErrorMethod(gdErrorMethod error_method)131 BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod error_method)
132 {
133 	gd_error_method = error_method;
134 }
135 
136 /*
137 	Function: gdClearErrorMethod
138 */
gdClearErrorMethod(void)139 BGD_DECLARE(void) gdClearErrorMethod(void)
140 {
141 	gd_error_method = gd_stderr_error;
142 }
143 
144 static void gdImageBrushApply (gdImagePtr im, int x, int y);
145 static void gdImageTileApply (gdImagePtr im, int x, int y);
146 
147 BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
148 
149 /**
150  * Group: Creation and Destruction
151  */
152 
153 /*
154     Function: gdImageCreate
155 
156       gdImageCreate is called to create palette-based images, with no
157       more than 256 colors. The image must eventually be destroyed using
158       gdImageDestroy().
159 
160     Parameters:
161 
162         sx - The image width.
163         sy - The image height.
164 
165     Returns:
166 
167         A pointer to the new image or NULL if an error occurred.
168 
169     Example:
170       (start code)
171 
172       gdImagePtr im;
173       im = gdImageCreate(64, 64);
174       // ... Use the image ...
175       gdImageDestroy(im);
176 
177       (end code)
178 
179     See Also:
180 
181         <gdImageCreateTrueColor>
182 
183  */
gdImageCreate(int sx,int sy)184 BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
185 {
186 	int i;
187 	gdImagePtr im;
188 
189 	if (overflow2(sx, sy)) {
190 		return NULL;
191 	}
192 
193 	if (overflow2(sizeof (unsigned char *), sy)) {
194 		return NULL;
195 	}
196 	if (overflow2(sizeof (unsigned char), sx)) {
197 		return NULL;
198 	}
199 
200 	im = (gdImage *) gdCalloc(1, sizeof(gdImage));
201 	if (!im) {
202 		return NULL;
203 	}
204 
205 	/* Row-major ever since gd 1.3 */
206 	im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy);
207 	if (!im->pixels) {
208 		gdFree(im);
209 		return NULL;
210 	}
211 
212 	im->polyInts = 0;
213 	im->polyAllocated = 0;
214 	im->brush = 0;
215 	im->tile = 0;
216 	im->style = 0;
217 	for (i = 0; (i < sy); i++) {
218 		/* Row-major ever since gd 1.3 */
219 		im->pixels[i] = (unsigned char *) gdCalloc (sx, sizeof (unsigned char));
220 		if (!im->pixels[i]) {
221 			for (--i ; i >= 0; i--) {
222 				gdFree(im->pixels[i]);
223 			}
224 			gdFree(im->pixels);
225 			gdFree(im);
226 			return NULL;
227 		}
228 
229 	}
230 	im->sx = sx;
231 	im->sy = sy;
232 	im->colorsTotal = 0;
233 	im->transparent = (-1);
234 	im->interlace = 0;
235 	im->thick = 1;
236 	im->AA = 0;
237 	for (i = 0; (i < gdMaxColors); i++) {
238 		im->open[i] = 1;
239 	};
240 	im->trueColor = 0;
241 	im->tpixels = 0;
242 	im->cx1 = 0;
243 	im->cy1 = 0;
244 	im->cx2 = im->sx - 1;
245 	im->cy2 = im->sy - 1;
246 	im->res_x = GD_RESOLUTION;
247 	im->res_y = GD_RESOLUTION;
248 	im->interpolation = NULL;
249 	im->interpolation_id = GD_BILINEAR_FIXED;
250 	return im;
251 }
252 
253 
254 
255 /*
256     Function: gdImageCreateTrueColor
257 
258       <gdImageCreateTrueColor> is called to create truecolor images,
259       with an essentially unlimited number of colors. Invoke
260       <gdImageCreateTrueColor> with the x and y dimensions of the
261       desired image. <gdImageCreateTrueColor> returns a <gdImagePtr>
262       to the new image, or NULL if unable to allocate the image. The
263       image must eventually be destroyed using <gdImageDestroy>().
264 
265       Truecolor images are always filled with black at creation
266       time. There is no concept of a "background" color index.
267 
268     Parameters:
269 
270         sx - The image width.
271         sy - The image height.
272 
273     Returns:
274 
275         A pointer to the new image or NULL if an error occurred.
276 
277     Example:
278       (start code)
279 
280       gdImagePtr im;
281       im = gdImageCreateTrueColor(64, 64);
282       // ... Use the image ...
283       gdImageDestroy(im);
284 
285       (end code)
286 
287     See Also:
288 
289         <gdImageCreateTrueColor>
290 
291 */
gdImageCreateTrueColor(int sx,int sy)292 BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
293 {
294 	int i;
295 	gdImagePtr im;
296 
297 	if (overflow2(sx, sy)) {
298 		return NULL;
299 	}
300 	if (overflow2(sizeof (int *), sy)) {
301 		return 0;
302 	}
303 	if (overflow2(sizeof(int), sx)) {
304 		return NULL;
305 	}
306 
307 	im = (gdImage *) gdMalloc (sizeof (gdImage));
308 	if (!im) {
309 		return 0;
310 	}
311 	memset (im, 0, sizeof (gdImage));
312 
313 	im->tpixels = (int **) gdMalloc (sizeof (int *) * sy);
314 	if (!im->tpixels) {
315 		gdFree(im);
316 		return 0;
317 	}
318 	im->polyInts = 0;
319 	im->polyAllocated = 0;
320 	im->brush = 0;
321 	im->tile = 0;
322 	im->style = 0;
323 	for (i = 0; (i < sy); i++) {
324 		im->tpixels[i] = (int *) gdCalloc (sx, sizeof (int));
325 		if (!im->tpixels[i]) {
326 			/* 2.0.34 */
327 			i--;
328 			while (i >= 0) {
329 				gdFree(im->tpixels[i]);
330 				i--;
331 			}
332 			gdFree(im->tpixels);
333 			gdFree(im);
334 			return 0;
335 		}
336 	}
337 	im->sx = sx;
338 	im->sy = sy;
339 	im->transparent = (-1);
340 	im->interlace = 0;
341 	im->trueColor = 1;
342 	/* 2.0.2: alpha blending is now on by default, and saving of alpha is
343 	   off by default. This allows font antialiasing to work as expected
344 	   on the first try in JPEGs -- quite important -- and also allows
345 	   for smaller PNGs when saving of alpha channel is not really
346 	   desired, which it usually isn't! */
347 	im->saveAlphaFlag = 0;
348 	im->alphaBlendingFlag = 1;
349 	im->thick = 1;
350 	im->AA = 0;
351 	im->cx1 = 0;
352 	im->cy1 = 0;
353 	im->cx2 = im->sx - 1;
354 	im->cy2 = im->sy - 1;
355 	im->res_x = GD_RESOLUTION;
356 	im->res_y = GD_RESOLUTION;
357 	im->interpolation = NULL;
358 	im->interpolation_id = GD_BILINEAR_FIXED;
359 	return im;
360 }
361 
362 /*
363   Function: gdImageDestroy
364 
365     <gdImageDestroy> is used to free the memory associated with an
366     image. It is important to invoke <gdImageDestroy> before exiting
367     your program or assigning a new image to a <gdImagePtr> variable.
368 
369   Parameters:
370 
371     im  - Pointer to the gdImage to delete.
372 
373   Returns:
374 
375     Nothing.
376 
377   Example:
378     (start code)
379 
380     gdImagePtr im;
381     im = gdImageCreate(10, 10);
382     // ... Use the image ...
383     // Now destroy it
384     gdImageDestroy(im);
385 
386 	(end code)
387 
388 */
389 
gdImageDestroy(gdImagePtr im)390 BGD_DECLARE(void) gdImageDestroy (gdImagePtr im)
391 {
392 	int i;
393 	if (im->pixels) {
394 		for (i = 0; (i < im->sy); i++) {
395 			gdFree (im->pixels[i]);
396 		}
397 		gdFree (im->pixels);
398 	}
399 	if (im->tpixels) {
400 		for (i = 0; (i < im->sy); i++) {
401 			gdFree (im->tpixels[i]);
402 		}
403 		gdFree (im->tpixels);
404 	}
405 	if (im->polyInts) {
406 		gdFree (im->polyInts);
407 	}
408 	if (im->style) {
409 		gdFree (im->style);
410 	}
411 	gdFree (im);
412 }
413 
414 /**
415  * Group: Color
416  */
417 
418 /**
419  * Function: gdImageColorClosest
420  *
421  * Gets the closest color of the image
422  *
423  * This is a simplified variant of <gdImageColorClosestAlpha> where the alpha
424  * channel is always opaque.
425  *
426  * Parameters:
427  *   im - The image.
428  *   r  - The value of the red component.
429  *   g  - The value of the green component.
430  *   b  - The value of the blue component.
431  *
432  * Returns:
433  *   The closest color already available in the palette for palette images;
434  *   the color value of the given components for truecolor images.
435  *
436  * See also:
437  *   - <gdImageColorExact>
438  */
gdImageColorClosest(gdImagePtr im,int r,int g,int b)439 BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b)
440 {
441 	return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
442 }
443 
444 /**
445  * Function: gdImageColorClosestAlpha
446  *
447  * Gets the closest color of the image
448  *
449  * Parameters:
450  *   im - The image.
451  *   r  - The value of the red component.
452  *   g  - The value of the green component.
453  *   b  - The value of the blue component.
454  *   a  - The value of the alpha component.
455  *
456  * Returns:
457  *   The closest color already available in the palette for palette images;
458  *   the color value of the given components for truecolor images.
459  *
460  * See also:
461  *   - <gdImageColorExactAlpha>
462  */
gdImageColorClosestAlpha(gdImagePtr im,int r,int g,int b,int a)463 BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
464 {
465 	int i;
466 	long rd, gd, bd, ad;
467 	int ct = (-1);
468 	int first = 1;
469 	long mindist = 0;
470 	if (im->trueColor) {
471 		return gdTrueColorAlpha (r, g, b, a);
472 	}
473 	for (i = 0; (i < (im->colorsTotal)); i++) {
474 		long dist;
475 		if (im->open[i]) {
476 			continue;
477 		}
478 		rd = (im->red[i] - r);
479 		gd = (im->green[i] - g);
480 		bd = (im->blue[i] - b);
481 		/* gd 2.02: whoops, was - b (thanks to David Marwood) */
482 		/* gd 2.16: was blue rather than alpha! Geez! Thanks to
483 		   Artur Jakub Jerzak */
484 		ad = (im->alpha[i] - a);
485 		dist = rd * rd + gd * gd + bd * bd + ad * ad;
486 		if (first || (dist < mindist)) {
487 			mindist = dist;
488 			ct = i;
489 			first = 0;
490 		}
491 	}
492 	return ct;
493 }
494 
495 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
496  * on colour conversion to/from RBG and HWB colour systems.
497  * It has been modified to return the converted value as a * parameter.
498  */
499 
500 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
501 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
502 #define HWB_UNDEFINED -1
503 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;}
504 
505 #define MIN(a,b) ((a)<(b)?(a):(b))
506 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
507 #define MAX(a,b) ((a)<(b)?(b):(a))
508 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
509 
510 
511 /*
512  * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
513  * red always maps to 6 in this implementation. Therefore UNDEFINED can be
514  * defined as 0 in situations where only unsigned numbers are desired.
515  */
516 typedef struct {
517 	float R, G, B;
518 }
519 RGBType;
520 typedef struct {
521 	float H, W, B;
522 }
523 HWBType;
524 
525 static HWBType *
RGB_to_HWB(RGBType RGB,HWBType * HWB)526 RGB_to_HWB (RGBType RGB, HWBType * HWB)
527 {
528 
529 	/*
530 	 * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
531 	 * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
532 	 */
533 
534 	float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
535 	int i;
536 
537 	w = MIN3 (R, G, B);
538 	v = MAX3 (R, G, B);
539 	b = 1 - v;
540 	if (v == w)
541 		RETURN_HWB (HWB_UNDEFINED, w, b);
542 	f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
543 	i = (R == w) ? 3 : ((G == w) ? 5 : 1);
544 	RETURN_HWB (i - f / (v - w), w, b);
545 
546 }
547 
548 static float
HWB_Diff(int r1,int g1,int b1,int r2,int g2,int b2)549 HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
550 {
551 	RGBType RGB1, RGB2;
552 	HWBType HWB1, HWB2;
553 	float diff;
554 
555 	SETUP_RGB (RGB1, r1, g1, b1);
556 	SETUP_RGB (RGB2, r2, g2, b2);
557 
558 	RGB_to_HWB (RGB1, &HWB1);
559 	RGB_to_HWB (RGB2, &HWB2);
560 
561 	/*
562 	 * I made this bit up; it seems to produce OK results, and it is certainly
563 	 * more visually correct than the current RGB metric. (PJW)
564 	 */
565 
566 	if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
567 		diff = 0;			/* Undefined hues always match... */
568 	} else {
569 		diff = fabs (HWB1.H - HWB2.H);
570 		if (diff > 3) {
571 			diff = 6 - diff;	/* Remember, it's a colour circle */
572 		}
573 	}
574 
575 	diff =
576 	    diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B -
577 	            HWB2.B) * (HWB1.B -
578 	                       HWB2.B);
579 
580 	return diff;
581 }
582 
583 
584 #if 0
585 /*
586  * This is not actually used, but is here for completeness, in case someone wants to
587  * use the HWB stuff for anything else...
588  */
589 static RGBType *
590 HWB_to_RGB (HWBType HWB, RGBType * RGB)
591 {
592 
593 	/*
594 	 * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
595 	 * RGB are each returned on [0, 1].
596 	 */
597 
598 	float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
599 	int i;
600 
601 	v = 1 - b;
602 	if (h == HWB_UNDEFINED)
603 		RETURN_RGB (v, v, v);
604 	i = floor (h);
605 	f = h - i;
606 	if (i & 1)
607 		f = 1 - f;			/* if i is odd */
608 	n = w + f * (v - w);		/* linear interpolation between w and v */
609 	switch (i) {
610 	case 6:
611 	case 0:
612 		RETURN_RGB (v, n, w);
613 	case 1:
614 		RETURN_RGB (n, v, w);
615 	case 2:
616 		RETURN_RGB (w, v, n);
617 	case 3:
618 		RETURN_RGB (w, n, v);
619 	case 4:
620 		RETURN_RGB (n, w, v);
621 	case 5:
622 		RETURN_RGB (v, w, n);
623 	}
624 
625 	return RGB;
626 
627 }
628 #endif
629 
630 /*
631 	Function: gdImageColorClosestHWB
632 */
gdImageColorClosestHWB(gdImagePtr im,int r,int g,int b)633 BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
634 {
635 	int i;
636 	/* long rd, gd, bd; */
637 	int ct = (-1);
638 	int first = 1;
639 	float mindist = 0;
640 	if (im->trueColor) {
641 		return gdTrueColor (r, g, b);
642 	}
643 	for (i = 0; (i < (im->colorsTotal)); i++) {
644 		float dist;
645 		if (im->open[i]) {
646 			continue;
647 		}
648 		dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b);
649 		if (first || (dist < mindist)) {
650 			mindist = dist;
651 			ct = i;
652 			first = 0;
653 		}
654 	}
655 	return ct;
656 }
657 
658 /**
659  * Function: gdImageColorExact
660  *
661  * Gets the exact color of the image
662  *
663  * This is a simplified variant of <gdImageColorExactAlpha> where the alpha
664  * channel is always opaque.
665  *
666  * Parameters:
667  *   im - The image.
668  *   r  - The value of the red component.
669  *   g  - The value of the green component.
670  *   b  - The value of the blue component.
671  *
672  * Returns:
673  *   The exact color already available in the palette for palette images; if
674  *   there is no exact color, -1 is returned.
675  *   For truecolor images the color value of the given components is returned.
676  *
677  * See also:
678  *   - <gdImageColorClosest>
679  */
gdImageColorExact(gdImagePtr im,int r,int g,int b)680 BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b)
681 {
682 	return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
683 }
684 
685 /**
686  * Function: gdImageColorExactAlpha
687  *
688  * Gets the exact color of the image
689  *
690  * Parameters:
691  *   im - The image.
692  *   r  - The value of the red component.
693  *   g  - The value of the green component.
694  *   b  - The value of the blue component.
695  *   a  - The value of the alpha component.
696  *
697  * Returns:
698  *   The exact color already available in the palette for palette images; if
699  *   there is no exact color, -1 is returned.
700  *   For truecolor images the color value of the given components is returned.
701  *
702  * See also:
703  *   - <gdImageColorClosestAlpha>
704  *   - <gdTrueColorAlpha>
705  */
gdImageColorExactAlpha(gdImagePtr im,int r,int g,int b,int a)706 BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
707 {
708 	int i;
709 	if (im->trueColor) {
710 		return gdTrueColorAlpha (r, g, b, a);
711 	}
712 	for (i = 0; (i < (im->colorsTotal)); i++) {
713 		if (im->open[i]) {
714 			continue;
715 		}
716 		if ((im->red[i] == r) &&
717 		        (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
718 			return i;
719 		}
720 	}
721 	return -1;
722 }
723 
724 /**
725  * Function: gdImageColorAllocate
726  *
727  * Allocates a color
728  *
729  * This is a simplified variant of <gdImageColorAllocateAlpha> where the alpha
730  * channel is always opaque.
731  *
732  * Parameters:
733  *   im - The image.
734  *   r  - The value of the red component.
735  *   g  - The value of the green component.
736  *   b  - The value of the blue component.
737  *
738  * Returns:
739  *   The color value.
740  *
741  * See also:
742  *   - <gdImageColorDeallocate>
743  */
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)744 BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
745 {
746 	return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
747 }
748 
749 /**
750  * Function: gdImageColorAllocateAlpha
751  *
752  * Allocates a color
753  *
754  * This is typically used for palette images, but can be used for truecolor
755  * images as well.
756  *
757  * Parameters:
758  *   im - The image.
759  *   r  - The value of the red component.
760  *   g  - The value of the green component.
761  *   b  - The value of the blue component.
762  *
763  * Returns:
764  *   The color value.
765  *
766  * See also:
767  *   - <gdImageColorDeallocate>
768  */
gdImageColorAllocateAlpha(gdImagePtr im,int r,int g,int b,int a)769 BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
770 {
771 	int i;
772 	int ct = (-1);
773 	if (im->trueColor) {
774 		return gdTrueColorAlpha (r, g, b, a);
775 	}
776 	for (i = 0; (i < (im->colorsTotal)); i++) {
777 		if (im->open[i]) {
778 			ct = i;
779 			break;
780 		}
781 	}
782 	if (ct == (-1)) {
783 		ct = im->colorsTotal;
784 		if (ct == gdMaxColors) {
785 			return -1;
786 		}
787 		im->colorsTotal++;
788 	}
789 	im->red[ct] = r;
790 	im->green[ct] = g;
791 	im->blue[ct] = b;
792 	im->alpha[ct] = a;
793 	im->open[ct] = 0;
794 	return ct;
795 }
796 
797 /*
798 	Function: gdImageColorResolve
799 
800 	gdImageColorResolve is an alternative for the code fragment
801 	(start code)
802 	if ((color=gdImageColorExact(im,R,G,B)) < 0)
803 	  if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
804 	    color=gdImageColorClosest(im,R,G,B);
805 	(end code)
806 	in a single function.    Its advantage is that it is guaranteed to
807 	return a color index in one search over the color table.
808 */
809 
gdImageColorResolve(gdImagePtr im,int r,int g,int b)810 BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b)
811 {
812 	return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);
813 }
814 
815 /*
816 	Function: gdImageColorResolveAlpha
817 */
gdImageColorResolveAlpha(gdImagePtr im,int r,int g,int b,int a)818 BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
819 {
820 	int c;
821 	int ct = -1;
822 	int op = -1;
823 	long rd, gd, bd, ad, dist;
824 	long mindist = 4 * 255 * 255;	/* init to max poss dist */
825 	if (im->trueColor) {
826 		return gdTrueColorAlpha (r, g, b, a);
827 	}
828 
829 	for (c = 0; c < im->colorsTotal; c++) {
830 		if (im->open[c]) {
831 			op = c;		/* Save open slot */
832 			continue;		/* Color not in use */
833 		}
834 		if (c == im->transparent) {
835 			/* don't ever resolve to the color that has
836 			 * been designated as the transparent color */
837 			continue;
838 		}
839 		rd = (long) (im->red[c] - r);
840 		gd = (long) (im->green[c] - g);
841 		bd = (long) (im->blue[c] - b);
842 		ad = (long) (im->alpha[c] - a);
843 		dist = rd * rd + gd * gd + bd * bd + ad * ad;
844 		if (dist < mindist) {
845 			if (dist == 0) {
846 				return c;		/* Return exact match color */
847 			}
848 			mindist = dist;
849 			ct = c;
850 		}
851 	}
852 	/* no exact match.  We now know closest, but first try to allocate exact */
853 	if (op == -1) {
854 		op = im->colorsTotal;
855 		if (op == gdMaxColors) {
856 			/* No room for more colors */
857 			return ct;		/* Return closest available color */
858 		}
859 		im->colorsTotal++;
860 	}
861 	im->red[op] = r;
862 	im->green[op] = g;
863 	im->blue[op] = b;
864 	im->alpha[op] = a;
865 	im->open[op] = 0;
866 	return op;			/* Return newly allocated color */
867 }
868 
869 /**
870  * Function: gdImageColorDeallocate
871  *
872  * Removes a palette entry
873  *
874  * This is a no-op for truecolor images.
875  *
876  * Parameters:
877  *   im    - The image.
878  *   color - The palette index.
879  *
880  * See also:
881  *   - <gdImageColorAllocate>
882  *   - <gdImageColorAllocateAlpha>
883  */
gdImageColorDeallocate(gdImagePtr im,int color)884 BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color)
885 {
886 	if (im->trueColor || (color >= gdMaxColors) || (color < 0)) {
887 		return;
888 	}
889 	/* Mark it open. */
890 	im->open[color] = 1;
891 }
892 
893 /**
894  * Function: gdImageColorTransparent
895  *
896  * Sets the transparent color of the image
897  *
898  * Parameter:
899  *   im    - The image.
900  *   color - The color.
901  *
902  * See also:
903  *   - <gdImageGetTransparent>
904  */
gdImageColorTransparent(gdImagePtr im,int color)905 BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color)
906 {
907 	if (color < 0) {
908 		return;
909 	}
910 
911 	if (!im->trueColor) {
912 		if (color >= gdMaxColors) {
913 			return;
914 		}
915 		if (im->transparent != -1) {
916 			im->alpha[im->transparent] = gdAlphaOpaque;
917 		}
918 		im->alpha[color] = gdAlphaTransparent;
919 	}
920 	im->transparent = color;
921 }
922 
923 /*
924 	Function: gdImagePaletteCopy
925 */
gdImagePaletteCopy(gdImagePtr to,gdImagePtr from)926 BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
927 {
928 	int i;
929 	int x, y, p;
930 	int xlate[256];
931 	if (to->trueColor) {
932 		return;
933 	}
934 	if (from->trueColor) {
935 		return;
936 	}
937 
938 	for (i = 0; i < 256; i++) {
939 		xlate[i] = -1;
940 	};
941 
942 	for (y = 0; y < (to->sy); y++) {
943 		for (x = 0; x < (to->sx); x++) {
944 			/* Optimization: no gdImageGetPixel */
945 			p = to->pixels[y][x];
946 			if (xlate[p] == -1) {
947 				/* This ought to use HWB, but we don't have an alpha-aware
948 				   version of that yet. */
949 				xlate[p] =
950 				    gdImageColorClosestAlpha (from, to->red[p], to->green[p],
951 				                              to->blue[p], to->alpha[p]);
952 				/*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */
953 				/*      p,  to->red[p], to->green[p], to->blue[p], to->alpha[p], */
954 				/*      xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
955 			};
956 			/* Optimization: no gdImageSetPixel */
957 			to->pixels[y][x] = xlate[p];
958 		};
959 	};
960 
961 	for (i = 0; (i < (from->colorsTotal)); i++) {
962 		/*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */
963 		to->red[i] = from->red[i];
964 		to->blue[i] = from->blue[i];
965 		to->green[i] = from->green[i];
966 		to->alpha[i] = from->alpha[i];
967 		to->open[i] = 0;
968 	};
969 
970 	for (i = from->colorsTotal; (i < to->colorsTotal); i++) {
971 		to->open[i] = 1;
972 	};
973 
974 	to->colorsTotal = from->colorsTotal;
975 
976 }
977 
978 /*
979 	Function: gdImageColorReplace
980 */
gdImageColorReplace(gdImagePtr im,int src,int dst)981 BGD_DECLARE(int) gdImageColorReplace (gdImagePtr im, int src, int dst)
982 {
983 	register int x, y;
984 	int n = 0;
985 
986 	if (src == dst) {
987 		return 0;
988 	}
989 
990 #define REPLACING_LOOP(pixel) do {								\
991 		for (y = im->cy1; y <= im->cy2; y++) {					\
992 			for (x = im->cx1; x <= im->cx2; x++) {				\
993 				if (pixel(im, x, y) == src) {					\
994 					gdImageSetPixel(im, x, y, dst);				\
995 					n++;										\
996 				}												\
997 			}													\
998 		}														\
999 	} while (0)
1000 
1001 	if (im->trueColor) {
1002 		REPLACING_LOOP(gdImageTrueColorPixel);
1003 	} else {
1004 		REPLACING_LOOP(gdImagePalettePixel);
1005 	}
1006 
1007 #undef REPLACING_LOOP
1008 
1009 	return n;
1010 }
1011 
1012 /*
1013 	Function: gdImageColorReplaceThreshold
1014 */
gdImageColorReplaceThreshold(gdImagePtr im,int src,int dst,float threshold)1015 BGD_DECLARE(int) gdImageColorReplaceThreshold (gdImagePtr im, int src, int dst, float threshold)
1016 {
1017 	register int x, y;
1018 	int n = 0;
1019 
1020 	if (src == dst) {
1021 		return 0;
1022 	}
1023 
1024 #define REPLACING_LOOP(pixel) do {										\
1025 		for (y = im->cy1; y <= im->cy2; y++) {							\
1026 			for (x = im->cx1; x <= im->cx2; x++) {						\
1027 				if (gdColorMatch(im, src, pixel(im, x, y), threshold)) { \
1028 					gdImageSetPixel(im, x, y, dst);						\
1029 					n++;												\
1030 				}														\
1031 			}															\
1032 		}																\
1033 	} while (0)
1034 
1035 	if (im->trueColor) {
1036 		REPLACING_LOOP(gdImageTrueColorPixel);
1037 	} else {
1038 		REPLACING_LOOP(gdImagePalettePixel);
1039 	}
1040 
1041 #undef REPLACING_LOOP
1042 
1043 	return n;
1044 }
1045 
colorCmp(const void * x,const void * y)1046 static int colorCmp (const void *x, const void *y)
1047 {
1048 	int a = *(int const *)x;
1049 	int b = *(int const *)y;
1050 	return (a > b) - (a < b);
1051 }
1052 
1053 /*
1054 	Function: gdImageColorReplaceArray
1055 */
gdImageColorReplaceArray(gdImagePtr im,int len,int * src,int * dst)1056 BGD_DECLARE(int) gdImageColorReplaceArray (gdImagePtr im, int len, int *src, int *dst)
1057 {
1058 	register int x, y;
1059 	int c, *d, *base;
1060 	int i, n = 0;
1061 
1062 	if (len <= 0 || src == dst) {
1063 		return 0;
1064 	}
1065 	if (len == 1) {
1066 		return gdImageColorReplace(im, src[0], dst[0]);
1067 	}
1068 	if (overflow2(len, sizeof(int)<<1)) {
1069 		return -1;
1070 	}
1071 	base = (int *)gdMalloc(len * (sizeof(int)<<1));
1072 	if (!base) {
1073 		return -1;
1074 	}
1075 	for (i = 0; i < len; i++) {
1076 		base[(i<<1)]   = src[i];
1077 		base[(i<<1)+1] = dst[i];
1078 	}
1079 	qsort(base, len, sizeof(int)<<1, colorCmp);
1080 
1081 #define REPLACING_LOOP(pixel) do {										\
1082 		for (y = im->cy1; y <= im->cy2; y++) {							\
1083 			for (x = im->cx1; x <= im->cx2; x++) {						\
1084 				c = pixel(im, x, y);									\
1085 				if ( (d = (int *)bsearch(&c, base, len, sizeof(int)<<1, colorCmp)) ) { \
1086 					gdImageSetPixel(im, x, y, d[1]);					\
1087 					n++;												\
1088 				}														\
1089 			}															\
1090 		}																\
1091 	} while (0)
1092 
1093 	if (im->trueColor) {
1094 		REPLACING_LOOP(gdImageTrueColorPixel);
1095 	} else {
1096 		REPLACING_LOOP(gdImagePalettePixel);
1097 	}
1098 
1099 #undef REPLACING_LOOP
1100 
1101 	gdFree(base);
1102 	return n;
1103 }
1104 
1105 /*
1106 	Function: gdImageColorReplaceCallback
1107 */
gdImageColorReplaceCallback(gdImagePtr im,gdCallbackImageColor callback)1108 BGD_DECLARE(int) gdImageColorReplaceCallback (gdImagePtr im, gdCallbackImageColor callback)
1109 {
1110 	int c, d, n = 0;
1111 
1112 	if (!callback) {
1113 		return 0;
1114 	}
1115 	if (im->trueColor) {
1116 		register int x, y;
1117 
1118 		for (y = im->cy1; y <= im->cy2; y++) {
1119 			for (x = im->cx1; x <= im->cx2; x++) {
1120 				c = gdImageTrueColorPixel(im, x, y);
1121 				if ( (d = callback(im, c)) != c) {
1122 					gdImageSetPixel(im, x, y, d);
1123 					n++;
1124 				}
1125 			}
1126 		}
1127 	} else { /* palette */
1128 		int *sarr, *darr;
1129 		int k, len = 0;
1130 
1131 		sarr = (int *)gdCalloc(im->colorsTotal, sizeof(int));
1132 		if (!sarr) {
1133 			return -1;
1134 		}
1135 		for (c = 0; c < im->colorsTotal; c++) {
1136 			if (!im->open[c]) {
1137 				sarr[len++] = c;
1138 			}
1139 		}
1140 		darr = (int *)gdCalloc(len, sizeof(int));
1141 		if (!darr) {
1142 			gdFree(sarr);
1143 			return -1;
1144 		}
1145 		for (k = 0; k < len; k++) {
1146 			darr[k] = callback(im, sarr[k]);
1147 		}
1148 		n = gdImageColorReplaceArray(im, k, sarr, darr);
1149 		gdFree(darr);
1150 		gdFree(sarr);
1151 	}
1152 	return n;
1153 }
1154 
1155 /* 2.0.10: before the drawing routines, some code to clip points that are
1156  * outside the drawing window.  Nick Atty (nick@canalplan.org.uk)
1157  *
1158  * This is the Sutherland Hodgman Algorithm, as implemented by
1159  * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short.  See Dr Dobb's
1160  * Journal, January 1996, pp107-110 and 116-117
1161  *
1162  * Given the end points of a line, and a bounding rectangle (which we
1163  * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
1164  * the edges of the rectangle if the line should be drawn at all,
1165  * otherwise return a failure code */
1166 
1167 /* this does "one-dimensional" clipping: note that the second time it
1168    is called, all the x parameters refer to height and the y to width
1169    - the comments ignore this (if you can understand it when it's
1170    looking at the X parameters, it should become clear what happens on
1171    the second call!)  The code is simplified from that in the article,
1172    as we know that gd images always start at (0,0) */
1173 
1174 /* 2.0.26, TBB: we now have to respect a clipping rectangle, it won't
1175 	necessarily start at 0. */
1176 
1177 static int
clip_1d(int * x0,int * y0,int * x1,int * y1,int mindim,int maxdim)1178 clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim)
1179 {
1180 	double m;			/* gradient of line */
1181 	if (*x0 < mindim) {
1182 		/* start of line is left of window */
1183 		if (*x1 < mindim)		/* as is the end, so the line never cuts the window */
1184 			return 0;
1185 		m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
1186 		/* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
1187 		*y0 -= (int)(m * (*x0 - mindim));
1188 		*x0 = mindim;
1189 		/* now, perhaps, adjust the far end of the line as well */
1190 		if (*x1 > maxdim) {
1191 			*y1 += m * (maxdim - *x1);
1192 			*x1 = maxdim;
1193 		}
1194 		return 1;
1195 	}
1196 	if (*x0 > maxdim) {
1197 		/* start of line is right of window -
1198 		complement of above */
1199 		if (*x1 > maxdim)		/* as is the end, so the line misses the window */
1200 			return 0;
1201 		m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
1202 		*y0 += (int)(m * (maxdim - *x0));	/* adjust so point is on the right
1203 							   boundary */
1204 		*x0 = maxdim;
1205 		/* now, perhaps, adjust the end of the line */
1206 		if (*x1 < mindim) {
1207 			*y1 -= (int)(m * (*x1 - mindim));
1208 			*x1 = mindim;
1209 		}
1210 		return 1;
1211 	}
1212 	/* the final case - the start of the line is inside the window */
1213 	if (*x1 > maxdim) {
1214 		/* other end is outside to the right */
1215 		m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
1216 		*y1 += (int)(m * (maxdim - *x1));
1217 		*x1 = maxdim;
1218 		return 1;
1219 	}
1220 	if (*x1 < mindim) {
1221 		/* other end is outside to the left */
1222 		m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
1223 		*y1 -= (int)(m * (*x1 - mindim));
1224 		*x1 = mindim;
1225 		return 1;
1226 	}
1227 	/* only get here if both points are inside the window */
1228 	return 1;
1229 }
1230 
1231 /* end of line clipping code */
1232 
1233 /**
1234  * Group: Pixels
1235  */
1236 
1237 /*
1238 	Function: gdImageSetPixel
1239 */
gdImageSetPixel(gdImagePtr im,int x,int y,int color)1240 BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color)
1241 {
1242 	int p;
1243 	switch (color) {
1244 	case gdStyled:
1245 		if (!im->style) {
1246 			/* Refuse to draw if no style is set. */
1247 			return;
1248 		} else {
1249 			p = im->style[im->stylePos++];
1250 		}
1251 		if (p != (gdTransparent)) {
1252 			gdImageSetPixel (im, x, y, p);
1253 		}
1254 		im->stylePos = im->stylePos % im->styleLength;
1255 		break;
1256 	case gdStyledBrushed:
1257 		if (!im->style) {
1258 			/* Refuse to draw if no style is set. */
1259 			return;
1260 		}
1261 		p = im->style[im->stylePos++];
1262 		if ((p != gdTransparent) && (p != 0)) {
1263 			gdImageSetPixel (im, x, y, gdBrushed);
1264 		}
1265 		im->stylePos = im->stylePos % im->styleLength;
1266 		break;
1267 	case gdBrushed:
1268 		gdImageBrushApply (im, x, y);
1269 		break;
1270 	case gdTiled:
1271 		gdImageTileApply (im, x, y);
1272 		break;
1273 	case gdAntiAliased:
1274 		/* This shouldn't happen (2.0.26) because we just call
1275 		  gdImageAALine now, but do something sane. */
1276 		gdImageSetPixel(im, x, y, im->AA_color);
1277 		break;
1278 	default:
1279 		if (gdImageBoundsSafeMacro (im, x, y)) {
1280 			if (im->trueColor) {
1281 				switch (im->alphaBlendingFlag) {
1282 					default:
1283 					case gdEffectReplace:
1284 						im->tpixels[y][x] = color;
1285 						break;
1286 					case gdEffectAlphaBlend:
1287 					case gdEffectNormal:
1288 						im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
1289 						break;
1290 					case gdEffectOverlay :
1291 						im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
1292 						break;
1293 					case gdEffectMultiply :
1294 						im->tpixels[y][x] = gdLayerMultiply(im->tpixels[y][x], color);
1295 						break;
1296 				}
1297 			} else {
1298 				im->pixels[y][x] = color;
1299 			}
1300 		}
1301 		break;
1302 	}
1303 }
1304 
1305 static void
gdImageBrushApply(gdImagePtr im,int x,int y)1306 gdImageBrushApply (gdImagePtr im, int x, int y)
1307 {
1308 	int lx, ly;
1309 	int hy;
1310 	int hx;
1311 	int x1, y1, x2, y2;
1312 	int srcx, srcy;
1313 	if (!im->brush) {
1314 		return;
1315 	}
1316 	hy = gdImageSY (im->brush) / 2;
1317 	y1 = y - hy;
1318 	y2 = y1 + gdImageSY (im->brush);
1319 	hx = gdImageSX (im->brush) / 2;
1320 	x1 = x - hx;
1321 	x2 = x1 + gdImageSX (im->brush);
1322 	srcy = 0;
1323 	if (im->trueColor) {
1324 		if (im->brush->trueColor) {
1325 			for (ly = y1; (ly < y2); ly++) {
1326 				srcx = 0;
1327 				for (lx = x1; (lx < x2); lx++) {
1328 					int p;
1329 					p = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
1330 					/* 2.0.9, Thomas Winzig: apply simple full transparency */
1331 					if (p != gdImageGetTransparent (im->brush)) {
1332 						gdImageSetPixel (im, lx, ly, p);
1333 					}
1334 					srcx++;
1335 				}
1336 				srcy++;
1337 			}
1338 		} else {
1339 			/* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger
1340 			   for pointing out the issue) */
1341 			for (ly = y1; (ly < y2); ly++) {
1342 				srcx = 0;
1343 				for (lx = x1; (lx < x2); lx++) {
1344 					int p, tc;
1345 					p = gdImageGetPixel (im->brush, srcx, srcy);
1346 					tc = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
1347 					/* 2.0.9, Thomas Winzig: apply simple full transparency */
1348 					if (p != gdImageGetTransparent (im->brush)) {
1349 						gdImageSetPixel (im, lx, ly, tc);
1350 					}
1351 					srcx++;
1352 				}
1353 				srcy++;
1354 			}
1355 		}
1356 	} else {
1357 		for (ly = y1; (ly < y2); ly++) {
1358 			srcx = 0;
1359 			for (lx = x1; (lx < x2); lx++) {
1360 				int p;
1361 				p = gdImageGetPixel (im->brush, srcx, srcy);
1362 				/* Allow for non-square brushes! */
1363 				if (p != gdImageGetTransparent (im->brush)) {
1364 					/* Truecolor brush. Very slow
1365 					   on a palette destination. */
1366 					if (im->brush->trueColor) {
1367 						gdImageSetPixel (im, lx, ly,
1368 						                 gdImageColorResolveAlpha (im,
1369 						                         gdTrueColorGetRed
1370 						                         (p),
1371 						                         gdTrueColorGetGreen
1372 						                         (p),
1373 						                         gdTrueColorGetBlue
1374 						                         (p),
1375 						                         gdTrueColorGetAlpha
1376 						                         (p)));
1377 					} else {
1378 						gdImageSetPixel (im, lx, ly, im->brushColorMap[p]);
1379 					}
1380 				}
1381 				srcx++;
1382 			}
1383 			srcy++;
1384 		}
1385 	}
1386 }
1387 
1388 static void
gdImageTileApply(gdImagePtr im,int x,int y)1389 gdImageTileApply (gdImagePtr im, int x, int y)
1390 {
1391 	gdImagePtr tile = im->tile;
1392 	int srcx, srcy;
1393 	int p;
1394 	if (!tile) {
1395 		return;
1396 	}
1397 	srcx = x % gdImageSX (tile);
1398 	srcy = y % gdImageSY (tile);
1399 	if (im->trueColor) {
1400 		p = gdImageGetPixel (tile, srcx, srcy);
1401 		if (p != gdImageGetTransparent (tile)) {
1402 			if (!tile->trueColor) {
1403 				p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]);
1404 			}
1405 			gdImageSetPixel (im, x, y, p);
1406 		}
1407 	} else {
1408 		p = gdImageGetPixel (tile, srcx, srcy);
1409 		/* Allow for transparency */
1410 		if (p != gdImageGetTransparent (tile)) {
1411 			if (tile->trueColor) {
1412 				/* Truecolor tile. Very slow
1413 				   on a palette destination. */
1414 				gdImageSetPixel (im, x, y,
1415 				                 gdImageColorResolveAlpha (im,
1416 				                         gdTrueColorGetRed
1417 				                         (p),
1418 				                         gdTrueColorGetGreen
1419 				                         (p),
1420 				                         gdTrueColorGetBlue
1421 				                         (p),
1422 				                         gdTrueColorGetAlpha
1423 				                         (p)));
1424 			} else {
1425 				gdImageSetPixel (im, x, y, im->tileColorMap[p]);
1426 			}
1427 		}
1428 	}
1429 }
1430 
1431 /**
1432  * Function: gdImageGetPixel
1433  *
1434  * Gets a pixel color as stored in the image.
1435  *
1436  * Parameters:
1437  *   im - The image.
1438  *   x  - The x-coordinate.
1439  *   y  - The y-coordinate.
1440  *
1441  * See also:
1442  *   - <gdImageGetTrueColorPixel>
1443  *   - <gdImagePalettePixel>
1444  *   - <gdImageTrueColorPixel>
1445  */
gdImageGetPixel(gdImagePtr im,int x,int y)1446 BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y)
1447 {
1448 	if (gdImageBoundsSafeMacro (im, x, y)) {
1449 		if (im->trueColor) {
1450 			return im->tpixels[y][x];
1451 		} else {
1452 			return im->pixels[y][x];
1453 		}
1454 	} else {
1455 		return 0;
1456 	}
1457 }
1458 
1459 /**
1460  * Function: gdImageGetTrueColorPixel
1461  *
1462  * Gets a pixel color always as truecolor value.
1463  *
1464  * Parameters:
1465  *   im - The image.
1466  *   x  - The x-coordinate.
1467  *   y  - The y-coordinate.
1468  *
1469  * See also:
1470  *   - <gdImageGetPixel>
1471  *   - <gdImageTrueColorPixel>
1472  */
gdImageGetTrueColorPixel(gdImagePtr im,int x,int y)1473 BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
1474 {
1475 	int p = gdImageGetPixel (im, x, y);
1476 	if (!im->trueColor) {
1477 		return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p],
1478 		                         (im->transparent == p) ? gdAlphaTransparent :
1479 		                         im->alpha[p]);
1480 	} else {
1481 		return p;
1482 	}
1483 }
1484 
1485 /**
1486  * Group: Primitives
1487  */
1488 
1489 /*
1490 	Function: gdImageAABlend
1491 
1492 	NO-OP, kept for library compatibility.
1493 */
gdImageAABlend(gdImagePtr im)1494 BGD_DECLARE(void) gdImageAABlend (gdImagePtr im)
1495 {
1496 	(void)im;
1497 }
1498 
1499 static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col);
1500 
1501 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
1502 		int color);
1503 
gdImageHLine(gdImagePtr im,int y,int x1,int x2,int col)1504 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
1505 {
1506 	if (im->thick > 1) {
1507 		int thickhalf = im->thick >> 1;
1508 		_gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
1509 	} else {
1510 		if (x2 < x1) {
1511 			int t = x2;
1512 			x2 = x1;
1513 			x1 = t;
1514 		}
1515 
1516 		for (; x1 <= x2; x1++) {
1517 			gdImageSetPixel(im, x1, y, col);
1518 		}
1519 	}
1520 	return;
1521 }
1522 
gdImageVLine(gdImagePtr im,int x,int y1,int y2,int col)1523 static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
1524 {
1525 	if (im->thick > 1) {
1526 		int thickhalf = im->thick >> 1;
1527 		gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
1528 	} else {
1529 		if (y2 < y1) {
1530 			int t = y1;
1531 			y1 = y2;
1532 			y2 = t;
1533 		}
1534 
1535 		for (; y1 <= y2; y1++) {
1536 			gdImageSetPixel(im, x, y1, col);
1537 		}
1538 	}
1539 	return;
1540 }
1541 
1542 /*
1543 	Function: gdImageLine
1544 
1545 	Bresenham as presented in Foley & Van Dam.
1546 */
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1547 BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1548 {
1549 	int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1550 	int wid;
1551 	int w, wstart;
1552 	int thick;
1553 
1554 	if (color == gdAntiAliased) {
1555 		/*
1556 		  gdAntiAliased passed as color: use the much faster, much cheaper
1557 		  and equally attractive gdImageAALine implementation. That
1558 		  clips too, so don't clip twice.
1559 		*/
1560 		gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
1561 		return;
1562 	}
1563 	/* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no
1564 	   points need to be drawn. 2.0.26, TBB: clip to edges of clipping
1565 	   rectangle. We were getting away with this because gdImageSetPixel
1566 	   is used for actual drawing, but this is still more efficient and opens
1567 	   the way to skip per-pixel bounds checking in the future. */
1568 
1569 	if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
1570 		return;
1571 	if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
1572 		return;
1573 	thick = im->thick;
1574 
1575 	dx = abs (x2 - x1);
1576 	dy = abs (y2 - y1);
1577 
1578 	if (dx == 0) {
1579 		gdImageVLine(im, x1, y1, y2, color);
1580 		return;
1581 	} else if (dy == 0) {
1582 		gdImageHLine(im, y1, x1, x2, color);
1583 		return;
1584 	}
1585 
1586 	if (dy <= dx) {
1587 		/* More-or-less horizontal. use wid for vertical stroke */
1588 		/* Doug Claar: watch out for NaN in atan2 (2.0.5) */
1589 
1590 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1591 			  TBB: but watch out for /0! */
1592 		double ac = cos (atan2 (dy, dx));
1593 		if (ac != 0) {
1594 			wid = thick / ac;
1595 		} else {
1596 			wid = 1;
1597 		}
1598 		if (wid == 0) {
1599 			wid = 1;
1600 		}
1601 		d = 2 * dy - dx;
1602 		incr1 = 2 * dy;
1603 		incr2 = 2 * (dy - dx);
1604 		if (x1 > x2) {
1605 			x = x2;
1606 			y = y2;
1607 			ydirflag = (-1);
1608 			xend = x1;
1609 		} else {
1610 			x = x1;
1611 			y = y1;
1612 			ydirflag = 1;
1613 			xend = x2;
1614 		}
1615 
1616 		/* Set up line thickness */
1617 		wstart = y - wid / 2;
1618 		for (w = wstart; w < wstart + wid; w++)
1619 			gdImageSetPixel (im, x, w, color);
1620 
1621 		if (((y2 - y1) * ydirflag) > 0) {
1622 			while (x < xend) {
1623 				x++;
1624 				if (d < 0) {
1625 					d += incr1;
1626 				} else {
1627 					y++;
1628 					d += incr2;
1629 				}
1630 				wstart = y - wid / 2;
1631 				for (w = wstart; w < wstart + wid; w++)
1632 					gdImageSetPixel (im, x, w, color);
1633 			}
1634 		} else {
1635 			while (x < xend) {
1636 				x++;
1637 				if (d < 0) {
1638 					d += incr1;
1639 				} else {
1640 					y--;
1641 					d += incr2;
1642 				}
1643 				wstart = y - wid / 2;
1644 				for (w = wstart; w < wstart + wid; w++)
1645 					gdImageSetPixel (im, x, w, color);
1646 			}
1647 		}
1648 	} else {
1649 		/* More-or-less vertical. use wid for horizontal stroke */
1650 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1651 		   TBB: but watch out for /0! */
1652 		double as = sin (atan2 (dy, dx));
1653 		if (as != 0) {
1654 			wid = thick / as;
1655 		} else {
1656 			wid = 1;
1657 		}
1658 		if (wid == 0)
1659 			wid = 1;
1660 
1661 		d = 2 * dx - dy;
1662 		incr1 = 2 * dx;
1663 		incr2 = 2 * (dx - dy);
1664 		if (y1 > y2) {
1665 			y = y2;
1666 			x = x2;
1667 			yend = y1;
1668 			xdirflag = (-1);
1669 		} else {
1670 			y = y1;
1671 			x = x1;
1672 			yend = y2;
1673 			xdirflag = 1;
1674 		}
1675 
1676 		/* Set up line thickness */
1677 		wstart = x - wid / 2;
1678 		for (w = wstart; w < wstart + wid; w++)
1679 			gdImageSetPixel (im, w, y, color);
1680 
1681 		if (((x2 - x1) * xdirflag) > 0) {
1682 			while (y < yend) {
1683 				y++;
1684 				if (d < 0) {
1685 					d += incr1;
1686 				} else {
1687 					x++;
1688 					d += incr2;
1689 				}
1690 				wstart = x - wid / 2;
1691 				for (w = wstart; w < wstart + wid; w++)
1692 					gdImageSetPixel (im, w, y, color);
1693 			}
1694 		} else {
1695 			while (y < yend) {
1696 				y++;
1697 				if (d < 0) {
1698 					d += incr1;
1699 				} else {
1700 					x--;
1701 					d += incr2;
1702 				}
1703 				wstart = x - wid / 2;
1704 				for (w = wstart; w < wstart + wid; w++)
1705 					gdImageSetPixel (im, w, y, color);
1706 			}
1707 		}
1708 	}
1709 
1710 }
1711 static void dashedSet (gdImagePtr im, int x, int y, int color,
1712 					   int *onP, int *dashStepP, int wid, int vert);
1713 
1714 /*
1715 	Function: gdImageDashedLine
1716 */
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1717 BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1718 {
1719 	int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1720 	int dashStep = 0;
1721 	int on = 1;
1722 	int wid;
1723 	int vert;
1724 	int thick = im->thick;
1725 
1726 	dx = abs (x2 - x1);
1727 	dy = abs (y2 - y1);
1728 	if (dy <= dx) {
1729 		/* More-or-less horizontal. use wid for vertical stroke */
1730 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1731 		   TBB: but watch out for /0! */
1732 		double as = sin (atan2 (dy, dx));
1733 		if (as != 0) {
1734 			wid = thick / as;
1735 		} else {
1736 			wid = 1;
1737 		}
1738 		vert = 1;
1739 
1740 		d = 2 * dy - dx;
1741 		incr1 = 2 * dy;
1742 		incr2 = 2 * (dy - dx);
1743 		if (x1 > x2) {
1744 			x = x2;
1745 			y = y2;
1746 			ydirflag = (-1);
1747 			xend = x1;
1748 		} else {
1749 			x = x1;
1750 			y = y1;
1751 			ydirflag = 1;
1752 			xend = x2;
1753 		}
1754 		dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1755 		if (((y2 - y1) * ydirflag) > 0) {
1756 			while (x < xend) {
1757 				x++;
1758 				if (d < 0) {
1759 					d += incr1;
1760 				} else {
1761 					y++;
1762 					d += incr2;
1763 				}
1764 				dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1765 			}
1766 		} else {
1767 			while (x < xend) {
1768 				x++;
1769 				if (d < 0) {
1770 					d += incr1;
1771 				} else {
1772 					y--;
1773 					d += incr2;
1774 				}
1775 				dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1776 			}
1777 		}
1778 	} else {
1779 		/* 2.0.12: Michael Schwartz: divide rather than multiply;
1780 		   TBB: but watch out for /0! */
1781 		double as = sin (atan2 (dy, dx));
1782 		if (as != 0) {
1783 			wid = thick / as;
1784 		} else {
1785 			wid = 1;
1786 		}
1787 		vert = 0;
1788 
1789 		d = 2 * dx - dy;
1790 		incr1 = 2 * dx;
1791 		incr2 = 2 * (dx - dy);
1792 		if (y1 > y2) {
1793 			y = y2;
1794 			x = x2;
1795 			yend = y1;
1796 			xdirflag = (-1);
1797 		} else {
1798 			y = y1;
1799 			x = x1;
1800 			yend = y2;
1801 			xdirflag = 1;
1802 		}
1803 		dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1804 		if (((x2 - x1) * xdirflag) > 0) {
1805 			while (y < yend) {
1806 				y++;
1807 				if (d < 0) {
1808 					d += incr1;
1809 				} else {
1810 					x++;
1811 					d += incr2;
1812 				}
1813 				dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1814 			}
1815 		} else {
1816 			while (y < yend) {
1817 				y++;
1818 				if (d < 0) {
1819 					d += incr1;
1820 				} else {
1821 					x--;
1822 					d += incr2;
1823 				}
1824 				dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1825 			}
1826 		}
1827 	}
1828 }
1829 
1830 static void
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1831 dashedSet (gdImagePtr im, int x, int y, int color,
1832 		   int *onP, int *dashStepP, int wid, int vert)
1833 {
1834 	int dashStep = *dashStepP;
1835 	int on = *onP;
1836 	int w, wstart;
1837 
1838 	dashStep++;
1839 	if (dashStep == gdDashSize) {
1840 		dashStep = 0;
1841 		on = !on;
1842 	}
1843 	if (on) {
1844 		if (vert) {
1845 			wstart = y - wid / 2;
1846 			for (w = wstart; w < wstart + wid; w++)
1847 				gdImageSetPixel (im, x, w, color);
1848 		} else {
1849 			wstart = x - wid / 2;
1850 			for (w = wstart; w < wstart + wid; w++)
1851 				gdImageSetPixel (im, w, y, color);
1852 		}
1853 	}
1854 	*dashStepP = dashStep;
1855 	*onP = on;
1856 }
1857 
1858 /*
1859 	Function: gdImageBoundsSafe
1860 */
gdImageBoundsSafe(gdImagePtr im,int x,int y)1861 BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y)
1862 {
1863 	return gdImageBoundsSafeMacro (im, x, y);
1864 }
1865 
1866 /**
1867  * Function: gdImageChar
1868  *
1869  * Draws a single character.
1870  *
1871  * Parameters:
1872  *  im    - The image to draw onto.
1873  *  f     - The raster font.
1874  *  x     - The x coordinate of the upper left pixel.
1875  *  y     - The y coordinate of the upper left pixel.
1876  *  c     - The character.
1877  *  color - The color.
1878  *
1879  * Variants:
1880  *  - <gdImageCharUp>
1881  *
1882  * See also:
1883  *  - <gdFontPtr>
1884  */
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1885 BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1886 {
1887 	int cx, cy;
1888 	int px, py;
1889 	int fline;
1890 	const int xuppper = (x > INT_MAX - f->w) ? INT_MAX : x + f->w;
1891 	const int yuppper = (y > INT_MAX - f->h) ? INT_MAX : y + f->h;
1892 	cx = 0;
1893 	cy = 0;
1894 #ifdef CHARSET_EBCDIC
1895 	c = ASC (c);
1896 #endif /*CHARSET_EBCDIC */
1897 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1898 		return;
1899 	}
1900 	fline = (c - f->offset) * f->h * f->w;
1901 	for (py = y; py < yuppper; py++) {
1902 		for (px = x; px < xuppper; px++) {
1903 			if (f->data[fline + cy * f->w + cx]) {
1904 				gdImageSetPixel (im, px, py, color);
1905 			}
1906 			cx++;
1907 		}
1908 		cx = 0;
1909 		cy++;
1910 	}
1911 }
1912 
1913 /**
1914  * Function: gdImageCharUp
1915  */
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1916 BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1917 {
1918 	int cx, cy;
1919 	int px, py;
1920 	int fline;
1921 	const int xuppper = (x > INT_MAX - f->h) ? INT_MAX : x + f->h;
1922 	const int ylower = (y < INT_MIN + f->w) ? INT_MIN : y - f->w;
1923 	cx = 0;
1924 	cy = 0;
1925 #ifdef CHARSET_EBCDIC
1926 	c = ASC (c);
1927 #endif /*CHARSET_EBCDIC */
1928 	if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
1929 		return;
1930 	}
1931 	fline = (c - f->offset) * f->h * f->w;
1932 	for (py = y; py > ylower; py--) {
1933 		for (px = x; px < xuppper; px++) {
1934 			if (f->data[fline + cy * f->w + cx]) {
1935 				gdImageSetPixel (im, px, py, color);
1936 			}
1937 			cy++;
1938 		}
1939 		cy = 0;
1940 		cx++;
1941 	}
1942 }
1943 
1944 /**
1945  * Function: gdImageString
1946  *
1947  * Draws a character string.
1948  *
1949  * Parameters:
1950  *  im    - The image to draw onto.
1951  *  f     - The raster font.
1952  *  x     - The x coordinate of the upper left pixel.
1953  *  y     - The y coordinate of the upper left pixel.
1954  *  c     - The character string.
1955  *  color - The color.
1956  *
1957  * Variants:
1958  *  - <gdImageStringUp>
1959  *  - <gdImageString16>
1960  *  - <gdImageStringUp16>
1961  *
1962  * See also:
1963  *  - <gdFontPtr>
1964  *  - <gdImageStringTTF>
1965  */
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1966 BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f,
1967 								 int x, int y, unsigned char *s, int color)
1968 {
1969 	int i;
1970 	int l;
1971 	l = strlen ((char *) s);
1972 	for (i = 0; (i < l); i++) {
1973 		gdImageChar (im, f, x, y, s[i], color);
1974 		x += f->w;
1975 	}
1976 }
1977 
1978 /**
1979  * Function: gdImageStringUp
1980  */
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1981 BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f,
1982 								   int x, int y, unsigned char *s, int color)
1983 {
1984 	int i;
1985 	int l;
1986 	l = strlen ((char *) s);
1987 	for (i = 0; (i < l); i++) {
1988 		gdImageCharUp (im, f, x, y, s[i], color);
1989 		y -= f->w;
1990 	}
1991 }
1992 
1993 static int strlen16 (unsigned short *s);
1994 
1995 /**
1996  * Function: gdImageString16
1997  */
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1998 BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f,
1999 								   int x, int y, unsigned short *s, int color)
2000 {
2001 	int i;
2002 	int l;
2003 	l = strlen16 (s);
2004 	for (i = 0; (i < l); i++) {
2005 		gdImageChar (im, f, x, y, s[i], color);
2006 		x += f->w;
2007 	}
2008 }
2009 
2010 /**
2011  * Function: gdImageStringUp16
2012  */
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)2013 BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f,
2014 									 int x, int y, unsigned short *s, int color)
2015 {
2016 	int i;
2017 	int l;
2018 	l = strlen16 (s);
2019 	for (i = 0; (i < l); i++) {
2020 		gdImageCharUp (im, f, x, y, s[i], color);
2021 		y -= f->w;
2022 	}
2023 }
2024 
2025 static int
strlen16(unsigned short * s)2026 strlen16 (unsigned short *s)
2027 {
2028 	int len = 0;
2029 	while (*s) {
2030 		s++;
2031 		len++;
2032 	}
2033 	return len;
2034 }
2035 
2036 #ifndef HAVE_LSQRT
2037 /* If you don't have a nice square root function for longs, you can use
2038    ** this hack
2039  */
2040 long
lsqrt(long n)2041 lsqrt (long n)
2042 {
2043 	long result = (long) sqrt ((double) n);
2044 	return result;
2045 }
2046 #endif
2047 
2048 /* s and e are integers modulo 360 (degrees), with 0 degrees
2049    being the rightmost extreme and degrees changing clockwise.
2050    cx and cy are the center in pixels; w and h are the horizontal
2051    and vertical diameter in pixels. */
2052 
2053 /*
2054 	Function: gdImageArc
2055 */
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)2056 BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
2057 							  int color)
2058 {
2059 	gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill);
2060 }
2061 
2062 /*
2063 	Function: gdImageFilledArc
2064 */
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)2065 BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
2066 									int color, int style)
2067 {
2068 	gdPoint pts[363];
2069 	int i, pti;
2070 	int lx = 0, ly = 0;
2071 	int fx = 0, fy = 0;
2072 	int startx = -1, starty = -1, endx = -1, endy = -1;
2073 
2074 	if ((s % 360)  == (e % 360)) {
2075 		s = 0;
2076 		e = 360;
2077 	} else {
2078 		if (s > 360) {
2079 			s = s % 360;
2080 		}
2081 
2082 		if (e > 360) {
2083 			e = e % 360;
2084 		}
2085 
2086 		while (s < 0) {
2087 			s += 360;
2088 		}
2089 
2090 		while (e < s) {
2091 			e += 360;
2092 		}
2093 
2094 		if (s == e) {
2095 			s = 0;
2096 			e = 360;
2097 		}
2098 	}
2099 
2100 	for (i = s, pti = 1; (i <= e); i++, pti++) {
2101 		int x, y;
2102 		x = endx = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
2103 		y = endy = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
2104 		if (i != s) {
2105 			if (!(style & gdChord)) {
2106 				if (style & gdNoFill) {
2107 					gdImageLine (im, lx, ly, x, y, color);
2108 				} else {
2109 					if (y == ly) {
2110 						pti--; /* don't add this point */
2111 						if (((i > 270 || i < 90) && x > lx) || ((i >  90 && i < 270) && x < lx)) {
2112 							/* replace the old x coord, if increasing on the
2113 							   right side or decreasing on the left side */
2114 							pts[pti].x = x;
2115 						}
2116 					} else {
2117 						pts[pti].x = x;
2118 						pts[pti].y = y;
2119 					}
2120 				}
2121 			}
2122 		} else {
2123 			fx = x;
2124 			fy = y;
2125 
2126 			if (!(style & (gdChord | gdNoFill))) {
2127 				pts[0].x = cx;
2128 				pts[0].y = cy;
2129 				pts[pti].x = startx = x;
2130 				pts[pti].y = starty = y;
2131 			}
2132 		}
2133 		lx = x;
2134 		ly = y;
2135 	}
2136 	if (style & gdChord) {
2137 		if (style & gdNoFill) {
2138 			if (style & gdEdged) {
2139 				gdImageLine (im, cx, cy, lx, ly, color);
2140 				gdImageLine (im, cx, cy, fx, fy, color);
2141 			}
2142 			gdImageLine (im, fx, fy, lx, ly, color);
2143 		} else {
2144 			pts[0].x = fx;
2145 			pts[0].y = fy;
2146 			pts[1].x = lx;
2147 			pts[1].y = ly;
2148 			pts[2].x = cx;
2149 			pts[2].y = cy;
2150 			gdImageFilledPolygon (im, pts, 3, color);
2151 		}
2152 	} else {
2153 		if (style & gdNoFill) {
2154 			if (style & gdEdged) {
2155 				gdImageLine (im, cx, cy, lx, ly, color);
2156 				gdImageLine (im, cx, cy, fx, fy, color);
2157 			}
2158 		} else {
2159 			if (e - s < 360) {
2160 				if (pts[1].x != startx && pts[1].y == starty) {
2161 					/* start point has been removed due to y-coord fix => insert it */
2162 					for (i = pti; i > 1; i--) {
2163 						pts[i].x = pts[i-1].x;
2164 						pts[i].y = pts[i-1].y;
2165 					}
2166 					pts[1].x = startx;
2167 					pts[1].y = starty;
2168 					pti++;
2169 				}
2170 				if (pts[pti-1].x != endx && pts[pti-1].y == endy) {
2171 					/* end point has been removed due to y-coord fix => insert it */
2172 					pts[pti].x = endx;
2173 					pts[pti].y = endy;
2174 					pti++;
2175 				}
2176 			}
2177 			pts[pti].x = cx;
2178 			pts[pti].y = cy;
2179 			gdImageFilledPolygon(im, pts, pti+1, color);
2180 		}
2181 	}
2182 }
2183 
2184 /*
2185 	Function: gdImageEllipse
2186 */
gdImageEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)2187 BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c)
2188 {
2189 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
2190 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
2191 
2192 	a=w>>1;
2193 	b=h>>1;
2194 	gdImageSetPixel(im,mx+a, my, c);
2195 	gdImageSetPixel(im,mx-a, my, c);
2196 	mx1 = mx-a;
2197 	my1 = my;
2198 	mx2 = mx+a;
2199 	my2 = my;
2200 
2201 	aq = a * a;
2202 	bq = b * b;
2203 	dx = aq << 1;
2204 	dy = bq << 1;
2205 	r  = a * bq;
2206 	rx = r << 1;
2207 	ry = 0;
2208 	x = a;
2209 	while (x > 0) {
2210 		if (r > 0) {
2211 			my1++;
2212 			my2--;
2213 			ry +=dx;
2214 			r  -=ry;
2215 		}
2216 		if (r <= 0) {
2217 			x--;
2218 			mx1++;
2219 			mx2--;
2220 			rx -=dy;
2221 			r  +=rx;
2222 		}
2223 		gdImageSetPixel(im,mx1, my1, c);
2224 		gdImageSetPixel(im,mx1, my2, c);
2225 		gdImageSetPixel(im,mx2, my1, c);
2226 		gdImageSetPixel(im,mx2, my2, c);
2227 	}
2228 }
2229 
2230 
2231 /*
2232 	Function: gdImageFilledEllipse
2233 */
gdImageFilledEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)2234 BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
2235 {
2236 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
2237 	int64_t aq,bq,dx,dy,r,rx,ry,a,b;
2238 	int i;
2239 	int old_y2;
2240 
2241 	a=w>>1;
2242 	b=h>>1;
2243 
2244 	for (x = mx-a; x <= mx+a; x++) {
2245 		gdImageSetPixel(im, x, my, c);
2246 	}
2247 
2248 	mx1 = mx-a;
2249 	my1 = my;
2250 	mx2 = mx+a;
2251 	my2 = my;
2252 
2253 	aq = a * a;
2254 	bq = b * b;
2255 	dx = aq << 1;
2256 	dy = bq << 1;
2257 	r  = a * bq;
2258 	rx = r << 1;
2259 	ry = 0;
2260 	x = a;
2261 	old_y2=-2;
2262 	while (x > 0) {
2263 		if (r > 0) {
2264 			my1++;
2265 			my2--;
2266 			ry +=dx;
2267 			r  -=ry;
2268 		}
2269 		if (r <= 0) {
2270 			x--;
2271 			mx1++;
2272 			mx2--;
2273 			rx -=dy;
2274 			r  +=rx;
2275 		}
2276 
2277 		if(old_y2!=my2) {
2278 			for(i=mx1; i<=mx2; i++) {
2279 				gdImageSetPixel(im,i,my2,c);
2280 				gdImageSetPixel(im,i,my1,c);
2281 			}
2282 		}
2283 		old_y2 = my2;
2284 	}
2285 }
2286 
2287 /*
2288 	Function: gdImageFillToBorder
2289 */
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)2290 BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
2291 {
2292 	int lastBorder;
2293 	/* Seek left */
2294 	int leftLimit, rightLimit;
2295 	int i;
2296 	int restoreAlphaBleding;
2297 
2298 	if (border < 0 || color < 0) {
2299 		/* Refuse to fill to a non-solid border */
2300 		return;
2301 	}
2302 
2303 	if (!im->trueColor) {
2304 		if (color > (im->colorsTotal - 1) || border > (im->colorsTotal - 1)) {
2305 			return;
2306 		}
2307 	}
2308 
2309 	leftLimit = (-1);
2310 
2311 	restoreAlphaBleding = im->alphaBlendingFlag;
2312 	im->alphaBlendingFlag = 0;
2313 
2314 	if (x >= im->sx) {
2315 		x = im->sx - 1;
2316 	} else if (x < 0) {
2317 		x = 0;
2318 	}
2319 	if (y >= im->sy) {
2320 		y = im->sy - 1;
2321 	} else if (y < 0) {
2322 		y = 0;
2323 	}
2324 
2325 	for (i = x; (i >= 0); i--) {
2326 		if (gdImageGetPixel (im, i, y) == border) {
2327 			break;
2328 		}
2329 		gdImageSetPixel (im, i, y, color);
2330 		leftLimit = i;
2331 	}
2332 	if (leftLimit == (-1)) {
2333 		im->alphaBlendingFlag = restoreAlphaBleding;
2334 		return;
2335 	}
2336 	/* Seek right */
2337 	rightLimit = x;
2338 	for (i = (x + 1); (i < im->sx); i++) {
2339 		if (gdImageGetPixel (im, i, y) == border) {
2340 			break;
2341 		}
2342 		gdImageSetPixel (im, i, y, color);
2343 		rightLimit = i;
2344 	}
2345 	/* Look at lines above and below and start paints */
2346 	/* Above */
2347 	if (y > 0) {
2348 		lastBorder = 1;
2349 		for (i = leftLimit; (i <= rightLimit); i++) {
2350 			int c;
2351 			c = gdImageGetPixel (im, i, y - 1);
2352 			if (lastBorder) {
2353 				if ((c != border) && (c != color)) {
2354 					gdImageFillToBorder (im, i, y - 1, border, color);
2355 					lastBorder = 0;
2356 				}
2357 			} else if ((c == border) || (c == color)) {
2358 				lastBorder = 1;
2359 			}
2360 		}
2361 	}
2362 	/* Below */
2363 	if (y < ((im->sy) - 1)) {
2364 		lastBorder = 1;
2365 		for (i = leftLimit; (i <= rightLimit); i++) {
2366 			int c = gdImageGetPixel (im, i, y + 1);
2367 			if (lastBorder) {
2368 				if ((c != border) && (c != color)) {
2369 					gdImageFillToBorder (im, i, y + 1, border, color);
2370 					lastBorder = 0;
2371 				}
2372 			} else if ((c == border) || (c == color)) {
2373 				lastBorder = 1;
2374 			}
2375 		}
2376 	}
2377 	im->alphaBlendingFlag = restoreAlphaBleding;
2378 }
2379 
2380 /*
2381  * set the pixel at (x,y) and its 4-connected neighbors
2382  * with the same pixel value to the new pixel value nc (new color).
2383  * A 4-connected neighbor:  pixel above, below, left, or right of a pixel.
2384  * ideas from comp.graphics discussions.
2385  * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
2386  * contain the same color as the color to fill. To do not bloat normal filling
2387  * code I added a 2nd private function.
2388  */
2389 
gdImageTileGet(gdImagePtr im,int x,int y)2390 static int gdImageTileGet (gdImagePtr im, int x, int y)
2391 {
2392 	int srcx, srcy;
2393 	int tileColor,p;
2394 	if (!im->tile) {
2395 		return -1;
2396 	}
2397 	srcx = x % gdImageSX(im->tile);
2398 	srcy = y % gdImageSY(im->tile);
2399 	p = gdImageGetPixel(im->tile, srcx, srcy);
2400 	if (p == im->tile->transparent) {
2401 		tileColor = im->transparent;
2402 	} else if (im->trueColor) {
2403 		if (im->tile->trueColor) {
2404 			tileColor = p;
2405 		} else {
2406 			tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
2407 		}
2408 	} else {
2409 		if (im->tile->trueColor) {
2410 			tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
2411 		} else {
2412 			tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
2413 		}
2414 	}
2415 	return tileColor;
2416 }
2417 
2418 
2419 
2420 /* horizontal segment of scan line y */
2421 struct seg {
2422 	int y, xl, xr, dy;
2423 };
2424 
2425 /* max depth of stack */
2426 #define FILL_MAX ((int)(im->sy*im->sx)/4)
2427 #define FILL_PUSH(Y, XL, XR, DY) \
2428 	if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
2429 	{sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
2430 
2431 #define FILL_POP(Y, XL, XR, DY) \
2432 	{sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
2433 
2434 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
2435 
2436 /*
2437 	Function: gdImageFill
2438 */
gdImageFill(gdImagePtr im,int x,int y,int nc)2439 BGD_DECLARE(void) gdImageFill(gdImagePtr im, int x, int y, int nc)
2440 {
2441 	int l, x1, x2, dy;
2442 	int oc;   /* old pixel value */
2443 	int wx2,wy2;
2444 
2445 	int alphablending_bak;
2446 
2447 	/* stack of filled segments */
2448 	/* struct seg stack[FILL_MAX],*sp = stack; */
2449 	struct seg *stack;
2450 	struct seg *sp;
2451 
2452 	if (!im->trueColor && nc > (im->colorsTotal - 1)) {
2453 		return;
2454 	}
2455 
2456 	alphablending_bak = im->alphaBlendingFlag;
2457 	im->alphaBlendingFlag = 0;
2458 
2459 	if (nc==gdTiled) {
2460 		_gdImageFillTiled(im,x,y,nc);
2461 		im->alphaBlendingFlag = alphablending_bak;
2462 		return;
2463 	}
2464 
2465 	wx2=im->sx;
2466 	wy2=im->sy;
2467 	oc = gdImageGetPixel(im, x, y);
2468 	if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
2469 		im->alphaBlendingFlag = alphablending_bak;
2470 		return;
2471 	}
2472 
2473 	/* Do not use the 4 neighbors implementation with
2474 	* small images
2475 	*/
2476 	if (im->sx < 4) {
2477 		int ix = x, iy = y, c;
2478 		do {
2479 			do {
2480 				c = gdImageGetPixel(im, ix, iy);
2481 				if (c != oc) {
2482 					goto done;
2483 				}
2484 				gdImageSetPixel(im, ix, iy, nc);
2485 			} while(ix++ < (im->sx -1));
2486 			ix = x;
2487 		} while(iy++ < (im->sy -1));
2488 		goto done;
2489 	}
2490 
2491 	if(overflow2(im->sy, im->sx)) {
2492 		return;
2493 	}
2494 
2495 	if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
2496 		return;
2497 	}
2498 
2499 	stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
2500 	if (!stack) {
2501 		return;
2502 	}
2503 	sp = stack;
2504 
2505 	/* required! */
2506 	FILL_PUSH(y,x,x,1);
2507 	/* seed segment (popped 1st) */
2508 	FILL_PUSH(y+1, x, x, -1);
2509 	while (sp>stack) {
2510 		FILL_POP(y, x1, x2, dy);
2511 
2512 		for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
2513 			gdImageSetPixel(im,x, y, nc);
2514 		}
2515 		if (x>=x1) {
2516 			goto skip;
2517 		}
2518 		l = x+1;
2519 
2520 		/* leak on left? */
2521 		if (l<x1) {
2522 			FILL_PUSH(y, l, x1-1, -dy);
2523 		}
2524 		x = x1+1;
2525 		do {
2526 			for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
2527 				gdImageSetPixel(im, x, y, nc);
2528 			}
2529 			FILL_PUSH(y, l, x-1, dy);
2530 			/* leak on right? */
2531 			if (x>x2+1) {
2532 				FILL_PUSH(y, x2+1, x-1, -dy);
2533 			}
2534 skip:
2535 			for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
2536 
2537 			l = x;
2538 		} while (x<=x2);
2539 	}
2540 
2541 	gdFree(stack);
2542 
2543 done:
2544 	im->alphaBlendingFlag = alphablending_bak;
2545 }
2546 
_gdImageFillTiled(gdImagePtr im,int x,int y,int nc)2547 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
2548 {
2549 	int l, x1, x2, dy;
2550 	int oc;   /* old pixel value */
2551 	int wx2,wy2;
2552 	/* stack of filled segments */
2553 	struct seg *stack;
2554 	struct seg *sp;
2555 	char *pts;
2556 
2557 	if (!im->tile) {
2558 		return;
2559 	}
2560 
2561 	wx2=im->sx;
2562 	wy2=im->sy;
2563 
2564 	if(overflow2(im->sy, im->sx)) {
2565 		return;
2566 	}
2567 
2568 	if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
2569 		return;
2570 	}
2571 
2572 	pts = (char *) gdCalloc(im->sy * im->sx, sizeof(char));
2573 	if (!pts) {
2574 		return;
2575 	}
2576 
2577 	stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
2578 	if (!stack) {
2579 		gdFree(pts);
2580 		return;
2581 	}
2582 	sp = stack;
2583 
2584 	oc = gdImageGetPixel(im, x, y);
2585 
2586 	/* required! */
2587 	FILL_PUSH(y,x,x,1);
2588 	/* seed segment (popped 1st) */
2589 	FILL_PUSH(y+1, x, x, -1);
2590 	while (sp>stack) {
2591 		FILL_POP(y, x1, x2, dy);
2592 		for (x=x1; x>=0 && (!pts[y + x*wy2] && gdImageGetPixel(im,x,y)==oc); x--) {
2593 			nc = gdImageTileGet(im,x,y);
2594 			pts[y + x*wy2]=1;
2595 			gdImageSetPixel(im,x, y, nc);
2596 		}
2597 		if (x>=x1) {
2598 			goto skip;
2599 		}
2600 		l = x+1;
2601 
2602 		/* leak on left? */
2603 		if (l<x1) {
2604 			FILL_PUSH(y, l, x1-1, -dy);
2605 		}
2606 		x = x1+1;
2607 		do {
2608 			for (; x<wx2 && (!pts[y + x*wy2] && gdImageGetPixel(im,x, y)==oc) ; x++) {
2609 				if (pts[y + x*wy2]) {
2610 					/* we should never be here */
2611 					break;
2612 				}
2613 				nc = gdImageTileGet(im,x,y);
2614 				pts[y + x*wy2]=1;
2615 				gdImageSetPixel(im, x, y, nc);
2616 			}
2617 			FILL_PUSH(y, l, x-1, dy);
2618 			/* leak on right? */
2619 			if (x>x2+1) {
2620 				FILL_PUSH(y, x2+1, x-1, -dy);
2621 			}
2622 skip:
2623 			for (x++; x<=x2 && (pts[y + x*wy2] || gdImageGetPixel(im,x, y)!=oc); x++);
2624 			l = x;
2625 		} while (x<=x2);
2626 	}
2627 
2628 	gdFree(pts);
2629 	gdFree(stack);
2630 }
2631 
2632 /**
2633  * Function: gdImageRectangle
2634  *
2635  * Draws a rectangle.
2636  *
2637  * Parameters:
2638  *   im    - The image.
2639  *   x1    - The x-coordinate of one of the corners.
2640  *   y1    - The y-coordinate of one of the corners.
2641  *   x2    - The x-coordinate of another corner.
2642  *   y2    - The y-coordinate of another corner.
2643  *   color - The color.
2644  *
2645  * See also:
2646  *   - <gdImageFilledRectangle>
2647  */
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2648 BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2649 {
2650 	int thick = im->thick;
2651 
2652 	if (x1 == x2 && y1 == y2 && thick == 1) {
2653 		gdImageSetPixel(im, x1, y1, color);
2654 		return;
2655 	}
2656 
2657 	if (y2 < y1) {
2658 		int t = y1;
2659 		y1 = y2;
2660 		y2 = t;
2661 	}
2662 
2663 	if (x2 < x1) {
2664 		int t = x1;
2665 		x1 = x2;
2666 		x2 = t;
2667 	}
2668 
2669 	if (thick > 1) {
2670 		int cx, cy, x1ul, y1ul, x2lr, y2lr;
2671 		int half = thick >> 1;
2672 		x1ul = x1 - half;
2673 		y1ul = y1 - half;
2674 
2675 		x2lr = x2 + half;
2676 		y2lr = y2 + half;
2677 
2678 		cy = y1ul + thick;
2679 		while (cy-- > y1ul) {
2680 			cx = x1ul - 1;
2681 			while (cx++ < x2lr) {
2682 				gdImageSetPixel(im, cx, cy, color);
2683 			}
2684 		}
2685 
2686 		cy = y2lr - thick;
2687 		while (cy++ < y2lr) {
2688 			cx = x1ul - 1;
2689 			while (cx++ < x2lr) {
2690 				gdImageSetPixel(im, cx, cy, color);
2691 			}
2692 		}
2693 
2694 		cy = y1ul + thick - 1;
2695 		while (cy++ < y2lr -thick) {
2696 			cx = x1ul - 1;
2697 			while (cx++ < x1ul + thick) {
2698 				gdImageSetPixel(im, cx, cy, color);
2699 			}
2700 		}
2701 
2702 		cy = y1ul + thick - 1;
2703 		while (cy++ < y2lr -thick) {
2704 			cx = x2lr - thick - 1;
2705 			while (cx++ < x2lr) {
2706 				gdImageSetPixel(im, cx, cy, color);
2707 			}
2708 		}
2709 
2710 		return;
2711 	} else {
2712 		if (x1 == x2 || y1 == y2) {
2713 			gdImageLine(im, x1, y1, x2, y2, color);
2714 		} else {
2715 			gdImageLine(im, x1, y1, x2, y1, color);
2716 			gdImageLine(im, x1, y2, x2, y2, color);
2717 			gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color);
2718 			gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color);
2719 		}
2720 	}
2721 }
2722 
_gdImageFilledHRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2723 static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
2724 		int color)
2725 {
2726 	int x, y;
2727 
2728 	if (x1 == x2 && y1 == y2) {
2729 		gdImageSetPixel(im, x1, y1, color);
2730 		return;
2731 	}
2732 
2733 	if (x1 > x2) {
2734 		x = x1;
2735 		x1 = x2;
2736 		x2 = x;
2737 	}
2738 
2739 	if (y1 > y2) {
2740 		y = y1;
2741 		y1 = y2;
2742 		y2 = y;
2743 	}
2744 
2745 	if (x1 < 0) {
2746 		x1 = 0;
2747 	}
2748 
2749 	if (x2 >= gdImageSX(im)) {
2750 		x2 = gdImageSX(im) - 1;
2751 	}
2752 
2753 	if (y1 < 0) {
2754 		y1 = 0;
2755 	}
2756 
2757 	if (y2 >= gdImageSY(im)) {
2758 		y2 = gdImageSY(im) - 1;
2759 	}
2760 
2761 	for (x = x1; (x <= x2); x++) {
2762 		for (y = y1; (y <= y2); y++) {
2763 			gdImageSetPixel (im, x, y, color);
2764 		}
2765 	}
2766 }
2767 
_gdImageFilledVRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2768 static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
2769 		int color)
2770 {
2771 	int x, y;
2772 
2773 	if (x1 == x2 && y1 == y2) {
2774 		gdImageSetPixel(im, x1, y1, color);
2775 		return;
2776 	}
2777 
2778 	if (x1 > x2) {
2779 		x = x1;
2780 		x1 = x2;
2781 		x2 = x;
2782 	}
2783 
2784 	if (y1 > y2) {
2785 		y = y1;
2786 		y1 = y2;
2787 		y2 = y;
2788 	}
2789 
2790 	if (x1 < 0) {
2791 		x1 = 0;
2792 	}
2793 
2794 	if (x2 >= gdImageSX(im)) {
2795 		x2 = gdImageSX(im) - 1;
2796 	}
2797 
2798 	if (y1 < 0) {
2799 		y1 = 0;
2800 	}
2801 
2802 	if (y2 >= gdImageSY(im)) {
2803 		y2 = gdImageSY(im) - 1;
2804 	}
2805 
2806 	for (y = y1; (y <= y2); y++) {
2807 		for (x = x1; (x <= x2); x++) {
2808 			gdImageSetPixel (im, x, y, color);
2809 		}
2810 	}
2811 }
2812 
2813 /*
2814 	Function: gdImageFilledRectangle
2815 */
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2816 BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
2817 		int color)
2818 {
2819 	_gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
2820 }
2821 
2822 /**
2823  * Group: Cloning and Copying
2824  */
2825 
2826 /**
2827  * Function: gdImageClone
2828  *
2829  * Clones an image
2830  *
2831  * Creates an exact duplicate of the given image.
2832  *
2833  * Parameters:
2834  *   src - The source image.
2835  *
2836  * Returns:
2837  *   The cloned image on success, NULL on failure.
2838  */
gdImageClone(gdImagePtr src)2839 BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src) {
2840 	gdImagePtr dst;
2841 	register int i, x;
2842 
2843 	if (src->trueColor) {
2844 		dst = gdImageCreateTrueColor(src->sx , src->sy);
2845 	} else {
2846 		dst = gdImageCreate(src->sx , src->sy);
2847 	}
2848 
2849 	if (dst == NULL) {
2850 		return NULL;
2851 	}
2852 
2853 	if (src->trueColor == 0) {
2854 		dst->colorsTotal = src->colorsTotal;
2855 		for (i = 0; i < gdMaxColors; i++) {
2856 			dst->red[i]   = src->red[i];
2857 			dst->green[i] = src->green[i];
2858 			dst->blue[i]  = src->blue[i];
2859 			dst->alpha[i] = src->alpha[i];
2860 			dst->open[i]  = src->open[i];
2861 		}
2862 		for (i = 0; i < src->sy; i++) {
2863 			for (x = 0; x < src->sx; x++) {
2864 				dst->pixels[i][x] = src->pixels[i][x];
2865 			}
2866 		}
2867 	} else {
2868 		for (i = 0; i < src->sy; i++) {
2869 			for (x = 0; x < src->sx; x++) {
2870 				dst->tpixels[i][x] = src->tpixels[i][x];
2871 			}
2872 		}
2873 	}
2874 
2875 	dst->interlace   = src->interlace;
2876 
2877 	dst->alphaBlendingFlag = src->alphaBlendingFlag;
2878 	dst->saveAlphaFlag     = src->saveAlphaFlag;
2879 	dst->AA                = src->AA;
2880 	dst->AA_color          = src->AA_color;
2881 	dst->AA_dont_blend     = src->AA_dont_blend;
2882 
2883 	dst->cx1 = src->cx1;
2884 	dst->cy1 = src->cy1;
2885 	dst->cx2 = src->cx2;
2886 	dst->cy2 = src->cy2;
2887 
2888 	dst->res_x = src->res_x;
2889 	dst->res_y = src->res_y;
2890 
2891 	dst->paletteQuantizationMethod     = src->paletteQuantizationMethod;
2892 	dst->paletteQuantizationSpeed      = src->paletteQuantizationSpeed;
2893 	dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality;
2894 	dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality;
2895 
2896 	dst->interpolation_id = src->interpolation_id;
2897 	dst->interpolation    = src->interpolation;
2898 
2899 	if (src->brush) {
2900 		dst->brush = gdImageClone(src->brush);
2901 	}
2902 
2903 	if (src->tile) {
2904 		dst->tile = gdImageClone(src->tile);
2905 	}
2906 
2907 	if (src->style) {
2908 		gdImageSetStyle(dst, src->style, src->styleLength);
2909 		dst->stylePos = src->stylePos;
2910 	}
2911 
2912 	for (i = 0; i < gdMaxColors; i++) {
2913 		dst->brushColorMap[i] = src->brushColorMap[i];
2914 		dst->tileColorMap[i] = src->tileColorMap[i];
2915 	}
2916 
2917 	if (src->polyAllocated > 0) {
2918 		dst->polyAllocated = src->polyAllocated;
2919 		for (i = 0; i < src->polyAllocated; i++) {
2920 			dst->polyInts[i] = src->polyInts[i];
2921 		}
2922 	}
2923 
2924 	return dst;
2925 }
2926 
2927 /**
2928  * Function: gdImageCopy
2929  *
2930  * Copy an area of an image to another image
2931  *
2932  * Parameters:
2933  *   dst  - The destination image.
2934  *   src  - The source image.
2935  *   dstX - The x-coordinate of the upper left corner to copy to.
2936  *   dstY - The y-coordinate of the upper left corner to copy to.
2937  *   srcX - The x-coordinate of the upper left corner to copy from.
2938  *   srcY - The y-coordinate of the upper left corner to copy from.
2939  *   w    - The width of the area to copy.
2940  *   h    - The height of the area to copy.
2941  *
2942  * See also:
2943  *   - <gdImageCopyMerge>
2944  *   - <gdImageCopyMergeGray>
2945  */
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)2946 BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX,
2947 							   int srcY, int w, int h)
2948 {
2949 	int c;
2950 	int x, y;
2951 	int tox, toy;
2952 	int i;
2953 	int colorMap[gdMaxColors];
2954 
2955 	if (dst->trueColor) {
2956 		/* 2.0: much easier when the destination is truecolor. */
2957 		/* 2.0.10: needs a transparent-index check that is still valid if
2958 		 *          * the source is not truecolor. Thanks to Frank Warmerdam.
2959 		 */
2960 
2961 		if (src->trueColor) {
2962 			for (y = 0; (y < h); y++) {
2963 				for (x = 0; (x < w); x++) {
2964 					int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
2965 					if (c != src->transparent) {
2966 						gdImageSetPixel (dst, dstX + x, dstY + y, c);
2967 					}
2968 				}
2969 			}
2970 		} else {
2971 			/* source is palette based */
2972 			for (y = 0; (y < h); y++) {
2973 				for (x = 0; (x < w); x++) {
2974 					int c = gdImageGetPixel (src, srcX + x, srcY + y);
2975 					if (c != src->transparent) {
2976 						gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
2977 					}
2978 				}
2979 			}
2980 		}
2981 		return;
2982 	}
2983 
2984 	for (i = 0; (i < gdMaxColors); i++) {
2985 		colorMap[i] = (-1);
2986 	}
2987 	toy = dstY;
2988 	for (y = srcY; (y < (srcY + h)); y++) {
2989 		tox = dstX;
2990 		for (x = srcX; (x < (srcX + w)); x++) {
2991 			int nc;
2992 			int mapTo;
2993 			c = gdImageGetPixel (src, x, y);
2994 			/* Added 7/24/95: support transparent copies */
2995 			if (gdImageGetTransparent (src) == c) {
2996 				tox++;
2997 				continue;
2998 			}
2999 			/* Have we established a mapping for this color? */
3000 			if (src->trueColor) {
3001 				/* 2.05: remap to the palette available in the
3002 				 destination image. This is slow and
3003 				 works badly, but it beats crashing! Thanks
3004 				 to Padhrig McCarthy. */
3005 				mapTo = gdImageColorResolveAlpha (dst,
3006 				                                  gdTrueColorGetRed (c),
3007 				                                  gdTrueColorGetGreen (c),
3008 				                                  gdTrueColorGetBlue (c),
3009 				                                  gdTrueColorGetAlpha (c));
3010 			} else if (colorMap[c] == (-1)) {
3011 				/* If it's the same image, mapping is trivial */
3012 				if (dst == src) {
3013 					nc = c;
3014 				} else {
3015 					/* Get best match possible. This
3016 					   function never returns error. */
3017 					nc = gdImageColorResolveAlpha (dst,
3018 					                               src->red[c], src->green[c],
3019 					                               src->blue[c], src->alpha[c]);
3020 				}
3021 				colorMap[c] = nc;
3022 				mapTo = colorMap[c];
3023 			} else {
3024 				mapTo = colorMap[c];
3025 			}
3026 			gdImageSetPixel (dst, tox, toy, mapTo);
3027 			tox++;
3028 		}
3029 		toy++;
3030 	}
3031 }
3032 
3033 /**
3034  * Function: gdImageCopyMerge
3035  *
3036  * Copy an area of an image to another image ignoring alpha
3037  *
3038  * The source area will be copied to the destination are by merging the pixels.
3039  *
3040  * Note:
3041  *   This function is a substitute for real alpha channel operations,
3042  *   so it doesn't pay attention to the alpha channel.
3043  *
3044  * Parameters:
3045  *   dst  - The destination image.
3046  *   src  - The source image.
3047  *   dstX - The x-coordinate of the upper left corner to copy to.
3048  *   dstY - The y-coordinate of the upper left corner to copy to.
3049  *   srcX - The x-coordinate of the upper left corner to copy from.
3050  *   srcY - The y-coordinate of the upper left corner to copy from.
3051  *   w    - The width of the area to copy.
3052  *   h    - The height of the area to copy.
3053  *   pct  - The percentage in range 0..100.
3054  *
3055  * See also:
3056  *   - <gdImageCopy>
3057  *   - <gdImageCopyMergeGray>
3058  */
gdImageCopyMerge(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)3059 BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
3060 									int srcX, int srcY, int w, int h, int pct)
3061 {
3062 
3063 	int c, dc;
3064 	int x, y;
3065 	int tox, toy;
3066 	int ncR, ncG, ncB;
3067 	toy = dstY;
3068 	for (y = srcY; (y < (srcY + h)); y++) {
3069 		tox = dstX;
3070 		for (x = srcX; (x < (srcX + w)); x++) {
3071 			int nc;
3072 			c = gdImageGetPixel (src, x, y);
3073 			/* Added 7/24/95: support transparent copies */
3074 			if (gdImageGetTransparent (src) == c) {
3075 				tox++;
3076 				continue;
3077 			}
3078 			/* If it's the same image, mapping is trivial */
3079 			if (dst == src) {
3080 				nc = c;
3081 			} else {
3082 				dc = gdImageGetPixel (dst, tox, toy);
3083 
3084 				ncR = gdImageRed (src, c) * (pct / 100.0)
3085 				      + gdImageRed (dst, dc) * ((100 - pct) / 100.0);
3086 				ncG = gdImageGreen (src, c) * (pct / 100.0)
3087 				      + gdImageGreen (dst, dc) * ((100 - pct) / 100.0);
3088 				ncB = gdImageBlue (src, c) * (pct / 100.0)
3089 				      + gdImageBlue (dst, dc) * ((100 - pct) / 100.0);
3090 
3091 				/* Find a reasonable color */
3092 				nc = gdImageColorResolve (dst, ncR, ncG, ncB);
3093 			}
3094 			gdImageSetPixel (dst, tox, toy, nc);
3095 			tox++;
3096 		}
3097 		toy++;
3098 	}
3099 }
3100 
3101 /**
3102  * Function: gdImageCopyMergeGray
3103  *
3104  * Copy an area of an image to another image ignoring alpha
3105  *
3106  * The source area will be copied to the grayscaled destination area by merging
3107  * the pixels.
3108  *
3109  * Note:
3110  *   This function is a substitute for real alpha channel operations,
3111  *   so it doesn't pay attention to the alpha channel.
3112  *
3113  * Parameters:
3114  *   dst  - The destination image.
3115  *   src  - The source image.
3116  *   dstX - The x-coordinate of the upper left corner to copy to.
3117  *   dstY - The y-coordinate of the upper left corner to copy to.
3118  *   srcX - The x-coordinate of the upper left corner to copy from.
3119  *   srcY - The y-coordinate of the upper left corner to copy from.
3120  *   w    - The width of the area to copy.
3121  *   h    - The height of the area to copy.
3122  *   pct  - The percentage of the source color intensity in range 0..100.
3123  *
3124  * See also:
3125  *   - <gdImageCopy>
3126  *   - <gdImageCopyMerge>
3127  */
gdImageCopyMergeGray(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)3128 BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
3129 										int srcX, int srcY, int w, int h, int pct)
3130 {
3131 
3132 	int c, dc;
3133 	int x, y;
3134 	int tox, toy;
3135 	int ncR, ncG, ncB;
3136 	float g;
3137 	toy = dstY;
3138 	for (y = srcY; (y < (srcY + h)); y++) {
3139 		tox = dstX;
3140 		for (x = srcX; (x < (srcX + w)); x++) {
3141 			int nc;
3142 			c = gdImageGetPixel (src, x, y);
3143 			/* Added 7/24/95: support transparent copies */
3144 			if (gdImageGetTransparent (src) == c) {
3145 				tox++;
3146 				continue;
3147 			}
3148 			/*
3149 			 * If it's the same image, mapping is NOT trivial since we
3150 			 * merge with greyscale target, but if pct is 100, the grey
3151 			 * value is not used, so it becomes trivial. pjw 2.0.12.
3152 			 */
3153 			if (dst == src && pct == 100) {
3154 				nc = c;
3155 			} else {
3156 				dc = gdImageGetPixel (dst, tox, toy);
3157 				g = 0.29900 * gdImageRed(dst, dc)
3158 				    + 0.58700 * gdImageGreen(dst, dc) + 0.11400 * gdImageBlue(dst, dc);
3159 
3160 				ncR = gdImageRed (src, c) * (pct / 100.0)
3161 				      + g * ((100 - pct) / 100.0);
3162 				ncG = gdImageGreen (src, c) * (pct / 100.0)
3163 				      + g * ((100 - pct) / 100.0);
3164 				ncB = gdImageBlue (src, c) * (pct / 100.0)
3165 				      + g * ((100 - pct) / 100.0);
3166 
3167 				/* First look for an exact match */
3168 				nc = gdImageColorExact (dst, ncR, ncG, ncB);
3169 				if (nc == (-1)) {
3170 					/* No, so try to allocate it */
3171 					nc = gdImageColorAllocate (dst, ncR, ncG, ncB);
3172 					/* If we're out of colors, go for the
3173 					   closest color */
3174 					if (nc == (-1)) {
3175 						nc = gdImageColorClosest (dst, ncR, ncG, ncB);
3176 					}
3177 				}
3178 			}
3179 			gdImageSetPixel (dst, tox, toy, nc);
3180 			tox++;
3181 		}
3182 		toy++;
3183 	}
3184 }
3185 
3186 /**
3187  * Function: gdImageCopyResized
3188  *
3189  * Copy a resized area from an image to another image
3190  *
3191  * If the source and destination area differ in size, the area will be resized
3192  * using nearest-neighbor interpolation.
3193  *
3194  * Parameters:
3195  *   dst  - The destination image.
3196  *   src  - The source image.
3197  *   dstX - The x-coordinate of the upper left corner to copy to.
3198  *   dstY - The y-coordinate of the upper left corner to copy to.
3199  *   srcX - The x-coordinate of the upper left corner to copy from.
3200  *   srcY - The y-coordinate of the upper left corner to copy from.
3201  *   dstW - The width of the area to copy to.
3202  *   dstH - The height of the area to copy to.
3203  *   srcW - The width of the area to copy from.
3204  *   srcH - The height of the area to copy from.
3205  *
3206  * See also:
3207  *   - <gdImageCopyResampled>
3208  *   - <gdImageScale>
3209  */
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)3210 BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
3211 									  int srcX, int srcY, int dstW, int dstH, int srcW,
3212 									  int srcH)
3213 {
3214 	int c;
3215 	int x, y;
3216 	int tox, toy;
3217 	int ydest;
3218 	int i;
3219 	int colorMap[gdMaxColors];
3220 	/* Stretch vectors */
3221 	int *stx;
3222 	int *sty;
3223 	/* We only need to use floating point to determine the correct
3224 	   stretch vector for one line's worth. */
3225 	if (overflow2(sizeof (int), srcW)) {
3226 		return;
3227 	}
3228 	if (overflow2(sizeof (int), srcH)) {
3229 		return;
3230 	}
3231 	stx = (int *) gdMalloc (sizeof (int) * srcW);
3232 	if (!stx) {
3233 		return;
3234 	}
3235 
3236 	sty = (int *) gdMalloc (sizeof (int) * srcH);
3237 	if (!sty) {
3238 		gdFree(stx);
3239 		return;
3240 	}
3241 
3242 	/* Fixed by Mao Morimoto 2.0.16 */
3243 	for (i = 0; (i < srcW); i++) {
3244 		stx[i] = dstW * (i + 1) / srcW - dstW * i / srcW;
3245 	}
3246 	for (i = 0; (i < srcH); i++) {
3247 		sty[i] = dstH * (i + 1) / srcH - dstH * i / srcH;
3248 	}
3249 	for (i = 0; (i < gdMaxColors); i++) {
3250 		colorMap[i] = (-1);
3251 	}
3252 	toy = dstY;
3253 	for (y = srcY; (y < (srcY + srcH)); y++) {
3254 		for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
3255 			tox = dstX;
3256 			for (x = srcX; (x < (srcX + srcW)); x++) {
3257 				int nc = 0;
3258 				int mapTo;
3259 				if (!stx[x - srcX]) {
3260 					continue;
3261 				}
3262 				if (dst->trueColor) {
3263 					/* 2.0.9: Thorben Kundinger: Maybe the source image is not
3264 					   a truecolor image */
3265 					if (!src->trueColor) {
3266 						int tmp = gdImageGetPixel (src, x, y);
3267 						mapTo = gdImageGetTrueColorPixel (src, x, y);
3268 						if (gdImageGetTransparent (src) == tmp) {
3269 							/* 2.0.21, TK: not tox++ */
3270 							tox += stx[x - srcX];
3271 							continue;
3272 						}
3273 					} else {
3274 						/* TK: old code follows */
3275 						mapTo = gdImageGetTrueColorPixel (src, x, y);
3276 						/* Added 7/24/95: support transparent copies */
3277 						if (gdImageGetTransparent (src) == mapTo) {
3278 							/* 2.0.21, TK: not tox++ */
3279 							tox += stx[x - srcX];
3280 							continue;
3281 						}
3282 					}
3283 				} else {
3284 					c = gdImageGetPixel (src, x, y);
3285 					/* Added 7/24/95: support transparent copies */
3286 					if (gdImageGetTransparent (src) == c) {
3287 						tox += stx[x - srcX];
3288 						continue;
3289 					}
3290 					if (src->trueColor) {
3291 						/* Remap to the palette available in the
3292 						   destination image. This is slow and
3293 						   works badly. */
3294 						mapTo = gdImageColorResolveAlpha (dst,
3295 						                                  gdTrueColorGetRed (c),
3296 						                                  gdTrueColorGetGreen
3297 						                                  (c),
3298 						                                  gdTrueColorGetBlue
3299 						                                  (c),
3300 						                                  gdTrueColorGetAlpha
3301 						                                  (c));
3302 					} else {
3303 						/* Have we established a mapping for this color? */
3304 						if (colorMap[c] == (-1)) {
3305 							/* If it's the same image, mapping is trivial */
3306 							if (dst == src) {
3307 								nc = c;
3308 							} else {
3309 								/* Find or create the best match */
3310 								/* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
3311 								nc = gdImageColorResolveAlpha (dst,
3312 								                               gdImageRed (src,
3313 								                                       c),
3314 								                               gdImageGreen
3315 								                               (src, c),
3316 								                               gdImageBlue (src,
3317 								                                       c),
3318 								                               gdImageAlpha
3319 								                               (src, c));
3320 							}
3321 							colorMap[c] = nc;
3322 						}
3323 						mapTo = colorMap[c];
3324 					}
3325 				}
3326 				for (i = 0; (i < stx[x - srcX]); i++) {
3327 					gdImageSetPixel (dst, tox, toy, mapTo);
3328 					tox++;
3329 				}
3330 			}
3331 			toy++;
3332 		}
3333 	}
3334 	gdFree (stx);
3335 	gdFree (sty);
3336 }
3337 
3338 /**
3339  * Function: gdImageCopyRotated
3340  *
3341  * Copy a rotated area from an image to another image
3342  *
3343  * The area is counter-clockwise rotated using nearest-neighbor interpolation.
3344  *
3345  * Parameters:
3346  *   dst   - The destination image.
3347  *   src   - The source image.
3348  *   dstX  - The x-coordinate of the center of the area to copy to.
3349  *   dstY  - The y-coordinate of the center of the area to copy to.
3350  *   srcX  - The x-coordinate of the upper left corner to copy from.
3351  *   srcY  - The y-coordinate of the upper left corner to copy from.
3352  *   srcW  - The width of the area to copy from.
3353  *   srcH  - The height of the area to copy from.
3354  *   angle - The angle in degrees.
3355  *
3356  * See also:
3357  *   - <gdImageRotateInterpolated>
3358  */
gdImageCopyRotated(gdImagePtr dst,gdImagePtr src,double dstX,double dstY,int srcX,int srcY,int srcWidth,int srcHeight,int angle)3359 BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst,
3360 									  gdImagePtr src,
3361 									  double dstX, double dstY,
3362 									  int srcX, int srcY,
3363 									  int srcWidth, int srcHeight, int angle)
3364 {
3365 	double dx, dy;
3366 	double radius = sqrt (srcWidth * srcWidth + srcHeight * srcHeight);
3367 	double aCos = cos (angle * .0174532925);
3368 	double aSin = sin (angle * .0174532925);
3369 	double scX = srcX + ((double) srcWidth) / 2;
3370 	double scY = srcY + ((double) srcHeight) / 2;
3371 	int cmap[gdMaxColors];
3372 	int i;
3373 
3374 	/*
3375 		 2.0.34: transparency preservation. The transparentness of
3376 		 the transparent color is more important than its hue.
3377 	*/
3378 	if (src->transparent != -1) {
3379 		if (dst->transparent == -1) {
3380 			dst->transparent = src->transparent;
3381 		}
3382 	}
3383 
3384 	for (i = 0; (i < gdMaxColors); i++) {
3385 		cmap[i] = (-1);
3386 	}
3387 	for (dy = dstY - radius; (dy <= dstY + radius); dy++) {
3388 		for (dx = dstX - radius; (dx <= dstX + radius); dx++) {
3389 			double sxd = (dx - dstX) * aCos - (dy - dstY) * aSin;
3390 			double syd = (dy - dstY) * aCos + (dx - dstX) * aSin;
3391 			int sx = sxd + scX;
3392 			int sy = syd + scY;
3393 			if ((sx >= srcX) && (sx < srcX + srcWidth) &&
3394 			        (sy >= srcY) && (sy < srcY + srcHeight)) {
3395 				int c = gdImageGetPixel (src, sx, sy);
3396 				/* 2.0.34: transparency wins */
3397 				if (c == src->transparent) {
3398 					gdImageSetPixel (dst, dx, dy, dst->transparent);
3399 				} else if (!src->trueColor) {
3400 					/* Use a table to avoid an expensive
3401 					   lookup on every single pixel */
3402 					if (cmap[c] == -1) {
3403 						cmap[c] = gdImageColorResolveAlpha (dst,
3404 						                                    gdImageRed (src, c),
3405 						                                    gdImageGreen (src,
3406 						                                            c),
3407 						                                    gdImageBlue (src,
3408 						                                            c),
3409 						                                    gdImageAlpha (src,
3410 						                                            c));
3411 					}
3412 					gdImageSetPixel (dst, dx, dy, cmap[c]);
3413 				} else {
3414 					gdImageSetPixel (dst,
3415 					                 dx, dy,
3416 					                 gdImageColorResolveAlpha (dst,
3417 					                         gdImageRed (src,
3418 					                                     c),
3419 					                         gdImageGreen
3420 					                         (src, c),
3421 					                         gdImageBlue (src,
3422 					                                      c),
3423 					                         gdImageAlpha
3424 					                         (src, c)));
3425 				}
3426 			}
3427 		}
3428 	}
3429 }
3430 
3431 /* When gd 1.x was first created, floating point was to be avoided.
3432    These days it is often faster than table lookups or integer
3433    arithmetic. The routine below is shamelessly, gloriously
3434    floating point. TBB */
3435 
3436 /* 2.0.10: cast instead of floor() yields 35% performance improvement.
3437 	Thanks to John Buckman. */
3438 
3439 #define floor2(exp) ((long) exp)
3440 /*#define floor2(exp) floor(exp)*/
3441 
3442 /**
3443  * Function: gdImageCopyResampled
3444  *
3445  * Copy a resampled area from an image to another image
3446  *
3447  * If the source and destination area differ in size, the area will be resized
3448  * using bilinear interpolation for truecolor images, and nearest-neighbor
3449  * interpolation for palette images.
3450  *
3451  * Parameters:
3452  *   dst  - The destination image.
3453  *   src  - The source image.
3454  *   dstX - The x-coordinate of the upper left corner to copy to.
3455  *   dstY - The y-coordinate of the upper left corner to copy to.
3456  *   srcX - The x-coordinate of the upper left corner to copy from.
3457  *   srcY - The y-coordinate of the upper left corner to copy from.
3458  *   dstW - The width of the area to copy to.
3459  *   dstH - The height of the area to copy to.
3460  *   srcW - The width of the area to copy from.
3461  *   srcH - The height of the area to copy from.
3462  *
3463  * See also:
3464  *   - <gdImageCopyResized>
3465  *   - <gdImageScale>
3466  */
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)3467 BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst,
3468 										gdImagePtr src,
3469 										int dstX, int dstY,
3470 										int srcX, int srcY,
3471 										int dstW, int dstH, int srcW, int srcH)
3472 {
3473 	int x, y;
3474 	double sy1, sy2, sx1, sx2;
3475 
3476 	if (!dst->trueColor) {
3477 		gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
3478 		return;
3479 	}
3480 	for (y = dstY; (y < dstY + dstH); y++) {
3481 		sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
3482 		sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
3483 		for (x = dstX; (x < dstX + dstW); x++) {
3484 			double sx, sy;
3485 			double spixels = 0;
3486 			double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
3487 			double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
3488 			sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
3489 			sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
3490 			sy = sy1;
3491 			do {
3492 				double yportion;
3493 				if (floor_cast(sy) == floor_cast(sy1)) {
3494 					yportion = 1.0f - (sy - floor_cast(sy));
3495 					if (yportion > sy2 - sy1) {
3496 						yportion = sy2 - sy1;
3497 					}
3498 					sy = floor_cast(sy);
3499 				} else if (sy == floorf(sy2)) {
3500 					yportion = sy2 - floor_cast(sy2);
3501 				} else {
3502 					yportion = 1.0f;
3503 				}
3504 				sx = sx1;
3505 				do {
3506 					double xportion;
3507 					double pcontribution;
3508 					int p;
3509 					if (floorf(sx) == floor_cast(sx1)) {
3510 						xportion = 1.0f - (sx - floor_cast(sx));
3511 						if (xportion > sx2 - sx1) {
3512 							xportion = sx2 - sx1;
3513 						}
3514 						sx = floor_cast(sx);
3515 					} else if (sx == floorf(sx2)) {
3516 						xportion = sx2 - floor_cast(sx2);
3517 					} else {
3518 						xportion = 1.0f;
3519 					}
3520 					pcontribution = xportion * yportion;
3521 					p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
3522 
3523 					alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
3524 					red += gdTrueColorGetRed (p) * alpha_factor;
3525 					green += gdTrueColorGetGreen (p) * alpha_factor;
3526 					blue += gdTrueColorGetBlue (p) * alpha_factor;
3527 					alpha += gdTrueColorGetAlpha (p) * pcontribution;
3528 					alpha_sum += alpha_factor;
3529 					contrib_sum += pcontribution;
3530 					spixels += xportion * yportion;
3531 					sx += 1.0f;
3532 				}
3533 				while (sx < sx2);
3534 
3535 				sy += 1.0f;
3536 			}
3537 
3538 			while (sy < sy2);
3539 
3540 			if (spixels != 0.0f) {
3541 				red /= spixels;
3542 				green /= spixels;
3543 				blue /= spixels;
3544 				alpha /= spixels;
3545 				alpha += 0.5;
3546 			}
3547 			if ( alpha_sum != 0.0f) {
3548 				if( contrib_sum != 0.0f) {
3549 					alpha_sum /= contrib_sum;
3550 				}
3551 				red /= alpha_sum;
3552 				green /= alpha_sum;
3553 				blue /= alpha_sum;
3554 			}
3555 			/* Clamping to allow for rounding errors above */
3556 			if (red > 255.0f) {
3557 				red = 255.0f;
3558 			}
3559 			if (green > 255.0f) {
3560 				green = 255.0f;
3561 			}
3562 			if (blue > 255.0f) {
3563 				blue = 255.0f;
3564 			}
3565 			if (alpha > gdAlphaMax) {
3566 				alpha = gdAlphaMax;
3567 			}
3568 			gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha));
3569 		}
3570 	}
3571 }
3572 
3573 /**
3574  * Group: Polygons
3575  */
3576 
3577 /**
3578  * Function: gdImagePolygon
3579  *
3580  * Draws a closed polygon
3581  *
3582  * Parameters:
3583  *   im - The image.
3584  *   p  - The vertices as array of <gdPoint>s.
3585  *   n  - The number of vertices.
3586  *   c  - The color.
3587  *
3588  * See also:
3589  *   - <gdImageOpenPolygon>
3590  *   - <gdImageFilledPolygon>
3591  */
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)3592 BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
3593 {
3594 	if (n <= 0) {
3595 		return;
3596 	}
3597 
3598 
3599 	gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
3600 	gdImageOpenPolygon (im, p, n, c);
3601 }
3602 
3603 /**
3604  * Function: gdImageOpenPolygon
3605  *
3606  * Draws an open polygon
3607  *
3608  * Parameters:
3609  *   im - The image.
3610  *   p  - The vertices as array of <gdPoint>s.
3611  *   n  - The number of vertices.
3612  *   c  - The color
3613  *
3614  * See also:
3615  *   - <gdImagePolygon>
3616  */
gdImageOpenPolygon(gdImagePtr im,gdPointPtr p,int n,int c)3617 BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
3618 {
3619 	int i;
3620 	int lx, ly;
3621 	if (n <= 0) {
3622 		return;
3623 	}
3624 
3625 
3626 	lx = p->x;
3627 	ly = p->y;
3628 	for (i = 1; (i < n); i++) {
3629 		p++;
3630 		gdImageLine (im, lx, ly, p->x, p->y, c);
3631 		lx = p->x;
3632 		ly = p->y;
3633 	}
3634 
3635 }
3636 
3637 /* THANKS to Kirsten Schulz for the polygon fixes! */
3638 
3639 /* The intersection finding technique of this code could be improved  */
3640 /* by remembering the previous intertersection, and by using the slope. */
3641 /* That could help to adjust intersections  to produce a nice */
3642 /* interior_extrema. */
3643 
3644 /**
3645  * Function: gdImageFilledPolygon
3646  *
3647  * Draws a filled polygon
3648  *
3649  * The polygon is filled using the even-odd fillrule what can leave unfilled
3650  * regions inside of self-intersecting polygons. This behavior might change in
3651  * a future version.
3652  *
3653  * Parameters:
3654  *   im - The image.
3655  *   p  - The vertices as array of <gdPoint>s.
3656  *   n  - The number of vertices.
3657  *   c  - The color
3658  *
3659  * See also:
3660  *   - <gdImagePolygon>
3661  */
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)3662 BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
3663 {
3664 	int i;
3665 	int j;
3666 	int index;
3667 	int y;
3668 	int miny, maxy, pmaxy;
3669 	int x1, y1;
3670 	int x2, y2;
3671 	int ind1, ind2;
3672 	int ints;
3673 	int fill_color;
3674 	if (n <= 0) {
3675 		return;
3676 	}
3677 
3678 	if (c == gdAntiAliased) {
3679 		fill_color = im->AA_color;
3680 	} else {
3681 		fill_color = c;
3682 	}
3683 	if (!im->polyAllocated) {
3684 		if (overflow2(sizeof (int), n)) {
3685 			return;
3686 		}
3687 		im->polyInts = (int *) gdMalloc (sizeof (int) * n);
3688 		if (!im->polyInts) {
3689 			return;
3690 		}
3691 		im->polyAllocated = n;
3692 	}
3693 	if (im->polyAllocated < n) {
3694 		while (im->polyAllocated < n) {
3695 			im->polyAllocated *= 2;
3696 		}
3697 		if (overflow2(sizeof (int), im->polyAllocated)) {
3698 			return;
3699 		}
3700 		im->polyInts = (int *) gdReallocEx (im->polyInts,
3701 						    sizeof (int) * im->polyAllocated);
3702 		if (!im->polyInts) {
3703 			return;
3704 		}
3705 	}
3706 	miny = p[0].y;
3707 	maxy = p[0].y;
3708 	for (i = 1; (i < n); i++) {
3709 		if (p[i].y < miny) {
3710 			miny = p[i].y;
3711 		}
3712 		if (p[i].y > maxy) {
3713 			maxy = p[i].y;
3714 		}
3715 	}
3716 	/* necessary special case: horizontal line */
3717 	if (n > 1 && miny == maxy) {
3718 		x1 = x2 = p[0].x;
3719 		for (i = 1; (i < n); i++) {
3720 			if (p[i].x < x1) {
3721 				x1 = p[i].x;
3722 			} else if (p[i].x > x2) {
3723 				x2 = p[i].x;
3724 			}
3725 		}
3726 		gdImageLine(im, x1, miny, x2, miny, c);
3727 		return;
3728 	}
3729 	pmaxy = maxy;
3730 	/* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
3731 	/* 2.0.26: clipping rectangle is even better */
3732 	if (miny < im->cy1) {
3733 		miny = im->cy1;
3734 	}
3735 	if (maxy > im->cy2) {
3736 		maxy = im->cy2;
3737 	}
3738 	/* Fix in 1.3: count a vertex only once */
3739 	for (y = miny; (y <= maxy); y++) {
3740 		ints = 0;
3741 		for (i = 0; (i < n); i++) {
3742 			if (!i) {
3743 				ind1 = n - 1;
3744 				ind2 = 0;
3745 			} else {
3746 				ind1 = i - 1;
3747 				ind2 = i;
3748 			}
3749 			y1 = p[ind1].y;
3750 			y2 = p[ind2].y;
3751 			if (y1 < y2) {
3752 				x1 = p[ind1].x;
3753 				x2 = p[ind2].x;
3754 			} else if (y1 > y2) {
3755 				y2 = p[ind1].y;
3756 				y1 = p[ind2].y;
3757 				x2 = p[ind1].x;
3758 				x1 = p[ind2].x;
3759 			} else {
3760 				continue;
3761 			}
3762 
3763 			/* Do the following math as float intermediately, and round to ensure
3764 			 * that Polygon and FilledPolygon for the same set of points have the
3765 			 * same footprint. */
3766 
3767 			if ((y >= y1) && (y < y2)) {
3768 				im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) /
3769 				                              (float) (y2 - y1) + 0.5 + x1);
3770 			} else if ((y == pmaxy) && (y == y2)) {
3771 				im->polyInts[ints++] = x2;
3772 			}
3773 		}
3774 		/*
3775 		  2.0.26: polygons pretty much always have less than 100 points,
3776 		  and most of the time they have considerably less. For such trivial
3777 		  cases, insertion sort is a good choice. Also a good choice for
3778 		  future implementations that may wish to indirect through a table.
3779 		*/
3780 		for (i = 1; (i < ints); i++) {
3781 			index = im->polyInts[i];
3782 			j = i;
3783 			while ((j > 0) && (im->polyInts[j - 1] > index)) {
3784 				im->polyInts[j] = im->polyInts[j - 1];
3785 				j--;
3786 			}
3787 			im->polyInts[j] = index;
3788 		}
3789 		for (i = 0; (i < (ints-1)); i += 2) {
3790 			/* 2.0.29: back to gdImageLine to prevent segfaults when
3791 			  performing a pattern fill */
3792 			gdImageLine (im, im->polyInts[i], y, im->polyInts[i + 1], y,
3793 			             fill_color);
3794 		}
3795 	}
3796 	/* If we are drawing this AA, then redraw the border with AA lines. */
3797 	/* This doesn't work as well as I'd like, but it doesn't clash either. */
3798 	if (c == gdAntiAliased) {
3799 		gdImagePolygon (im, p, n, c);
3800 	}
3801 }
3802 
3803 /**
3804  * Group: other
3805  */
3806 
3807 static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t);
3808 
3809 /**
3810  * Function: gdImageSetStyle
3811  *
3812  * Sets the style for following drawing operations
3813  *
3814  * Parameters:
3815  *   im        - The image.
3816  *   style     - An array of color values.
3817  *   noOfPixel - The number of color values.
3818  */
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)3819 BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
3820 {
3821 	if (im->style) {
3822 		gdFree (im->style);
3823 	}
3824 	if (overflow2(sizeof (int), noOfPixels)) {
3825 		return;
3826 	}
3827 	im->style = (int *) gdMalloc (sizeof (int) * noOfPixels);
3828 	if (!im->style) {
3829 		return;
3830 	}
3831 	memcpy (im->style, style, sizeof (int) * noOfPixels);
3832 	im->styleLength = noOfPixels;
3833 	im->stylePos = 0;
3834 }
3835 
3836 /**
3837  * Function: gdImageSetThickness
3838  *
3839  * Sets the thickness for following drawing operations
3840  *
3841  * Parameters:
3842  *   im        - The image.
3843  *   thickness - The thickness in pixels.
3844  */
gdImageSetThickness(gdImagePtr im,int thickness)3845 BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness)
3846 {
3847 	im->thick = thickness;
3848 }
3849 
3850 /**
3851  * Function: gdImageSetBrush
3852  *
3853  * Sets the brush for following drawing operations
3854  *
3855  * Parameters:
3856  *   im    - The image.
3857  *   brush - The brush image.
3858  */
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)3859 BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
3860 {
3861 	int i;
3862 	im->brush = brush;
3863 	if ((!im->trueColor) && (!im->brush->trueColor)) {
3864 		for (i = 0; (i < gdImageColorsTotal (brush)); i++) {
3865 			int index;
3866 			index = gdImageColorResolveAlpha (im,
3867 			                                  gdImageRed (brush, i),
3868 			                                  gdImageGreen (brush, i),
3869 			                                  gdImageBlue (brush, i),
3870 			                                  gdImageAlpha (brush, i));
3871 			im->brushColorMap[i] = index;
3872 		}
3873 	}
3874 }
3875 
3876 /*
3877 	Function: gdImageSetTile
3878 */
gdImageSetTile(gdImagePtr im,gdImagePtr tile)3879 BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile)
3880 {
3881 	int i;
3882 	im->tile = tile;
3883 	if ((!im->trueColor) && (!im->tile->trueColor)) {
3884 		for (i = 0; (i < gdImageColorsTotal (tile)); i++) {
3885 			int index;
3886 			index = gdImageColorResolveAlpha (im,
3887 			                                  gdImageRed (tile, i),
3888 			                                  gdImageGreen (tile, i),
3889 			                                  gdImageBlue (tile, i),
3890 			                                  gdImageAlpha (tile, i));
3891 			im->tileColorMap[i] = index;
3892 		}
3893 	}
3894 }
3895 
3896 /**
3897  * Function: gdImageSetAntiAliased
3898  *
3899  * Set the color for subsequent anti-aliased drawing
3900  *
3901  * If <gdAntiAliased> is passed as color to drawing operations that support
3902  * anti-aliased drawing (such as <gdImageLine> and <gdImagePolygon>), the actual
3903  * color to be used can be set with this function.
3904  *
3905  * Example: draw an anti-aliased blue line:
3906  * | gdImageSetAntiAliased(im, gdTrueColorAlpha(0, 0, gdBlueMax, gdAlphaOpaque));
3907  * | gdImageLine(im, 10,10, 20,20, gdAntiAliased);
3908  *
3909  * Parameters:
3910  *   im - The image.
3911  *   c  - The color.
3912  *
3913  * See also:
3914  *   - <gdImageSetAntiAliasedDontBlend>
3915  */
gdImageSetAntiAliased(gdImagePtr im,int c)3916 BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c)
3917 {
3918 	im->AA = 1;
3919 	im->AA_color = c;
3920 	im->AA_dont_blend = -1;
3921 }
3922 
3923 /**
3924  * Function: gdImageSetAntiAliasedDontBlend
3925  *
3926  * Set the color and "dont_blend" color for subsequent anti-aliased drawing
3927  *
3928  * This extended variant of <gdImageSetAntiAliased> allows to also specify a
3929  * (background) color that will not be blended in anti-aliased drawing
3930  * operations.
3931  *
3932  * Parameters:
3933  *   im         - The image.
3934  *   c          - The color.
3935  *   dont_blend - Whether to blend.
3936  */
gdImageSetAntiAliasedDontBlend(gdImagePtr im,int c,int dont_blend)3937 BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
3938 {
3939 	im->AA = 1;
3940 	im->AA_color = c;
3941 	im->AA_dont_blend = dont_blend;
3942 }
3943 
3944 /**
3945  * Function: gdImageInterlace
3946  *
3947  * Sets whether an image is interlaced
3948  *
3949  * This is relevant only when saving the image in a format that supports
3950  * interlacing.
3951  *
3952  * Parameters:
3953  *   im           - The image.
3954  *   interlaceArg - Whether the image is interlaced.
3955  *
3956  * See also:
3957  *   - <gdImageGetInterlaced>
3958 */
gdImageInterlace(gdImagePtr im,int interlaceArg)3959 BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg)
3960 {
3961 	im->interlace = interlaceArg;
3962 }
3963 
3964 /**
3965  * Function: gdImageCompare
3966  *
3967  * Compare two images
3968  *
3969  * Parameters:
3970  *   im1 - An image.
3971  *   im2 - Another image.
3972  *
3973  * Returns:
3974  *   A bitmask of <Image Comparison> flags where each set flag signals
3975  *   which attributes of the images are different.
3976  */
gdImageCompare(gdImagePtr im1,gdImagePtr im2)3977 BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2)
3978 {
3979 	int x, y;
3980 	int p1, p2;
3981 	int cmpStatus = 0;
3982 	int sx, sy;
3983 
3984 	if (im1->interlace != im2->interlace) {
3985 		cmpStatus |= GD_CMP_INTERLACE;
3986 	}
3987 
3988 	if (im1->transparent != im2->transparent) {
3989 		cmpStatus |= GD_CMP_TRANSPARENT;
3990 	}
3991 
3992 	if (im1->trueColor != im2->trueColor) {
3993 		cmpStatus |= GD_CMP_TRUECOLOR;
3994 	}
3995 
3996 	sx = im1->sx;
3997 	if (im1->sx != im2->sx) {
3998 		cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
3999 		if (im2->sx < im1->sx) {
4000 			sx = im2->sx;
4001 		}
4002 	}
4003 
4004 	sy = im1->sy;
4005 	if (im1->sy != im2->sy) {
4006 		cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
4007 		if (im2->sy < im1->sy) {
4008 			sy = im2->sy;
4009 		}
4010 	}
4011 
4012 	if (im1->colorsTotal != im2->colorsTotal) {
4013 		cmpStatus |= GD_CMP_NUM_COLORS;
4014 	}
4015 
4016 	for (y = 0; (y < sy); y++) {
4017 		for (x = 0; (x < sx); x++) {
4018 			p1 =
4019 			    im1->trueColor ? gdImageTrueColorPixel (im1, x,
4020 			            y) :
4021 			    gdImagePalettePixel (im1, x, y);
4022 			p2 =
4023 			    im2->trueColor ? gdImageTrueColorPixel (im2, x,
4024 			            y) :
4025 			    gdImagePalettePixel (im2, x, y);
4026 			if (gdImageRed (im1, p1) != gdImageRed (im2, p2)) {
4027 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4028 				break;
4029 			}
4030 			if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2)) {
4031 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4032 				break;
4033 			}
4034 			if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2)) {
4035 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4036 				break;
4037 			}
4038 #if 0
4039 			/* Soon we'll add alpha channel to palettes */
4040 			if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2)) {
4041 				cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
4042 				break;
4043 			}
4044 #endif
4045 		}
4046 		if (cmpStatus & GD_CMP_COLOR) {
4047 			break;
4048 		};
4049 	}
4050 
4051 	return cmpStatus;
4052 }
4053 
4054 
4055 /* Thanks to Frank Warmerdam for this superior implementation
4056 	of gdAlphaBlend(), which merges alpha in the
4057 	destination color much better. */
4058 
4059 /**
4060  * Function: gdAlphaBlend
4061  *
4062  * Blend two colors
4063  *
4064  * Parameters:
4065  *   dst - The color to blend onto.
4066  *   src - The color to blend.
4067  *
4068  * See also:
4069  *   - <gdImageAlphaBlending>
4070  *   - <gdLayerOverlay>
4071  *   - <gdLayerMultiply>
4072  */
gdAlphaBlend(int dst,int src)4073 BGD_DECLARE(int) gdAlphaBlend (int dst, int src)
4074 {
4075 	int src_alpha = gdTrueColorGetAlpha(src);
4076 	int dst_alpha, alpha, red, green, blue;
4077 	int src_weight, dst_weight, tot_weight;
4078 
4079 	/* -------------------------------------------------------------------- */
4080 	/*      Simple cases we want to handle fast.                            */
4081 	/* -------------------------------------------------------------------- */
4082 	if( src_alpha == gdAlphaOpaque )
4083 		return src;
4084 
4085 	dst_alpha = gdTrueColorGetAlpha(dst);
4086 	if( src_alpha == gdAlphaTransparent )
4087 		return dst;
4088 	if( dst_alpha == gdAlphaTransparent )
4089 		return src;
4090 
4091 	/* -------------------------------------------------------------------- */
4092 	/*      What will the source and destination alphas be?  Note that      */
4093 	/*      the destination weighting is substantially reduced as the       */
4094 	/*      overlay becomes quite opaque.                                   */
4095 	/* -------------------------------------------------------------------- */
4096 	src_weight = gdAlphaTransparent - src_alpha;
4097 	dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
4098 	tot_weight = src_weight + dst_weight;
4099 
4100 	/* -------------------------------------------------------------------- */
4101 	/*      What red, green and blue result values will we use?             */
4102 	/* -------------------------------------------------------------------- */
4103 	alpha = src_alpha * dst_alpha / gdAlphaMax;
4104 
4105 	red = (gdTrueColorGetRed(src) * src_weight
4106 	       + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
4107 	green = (gdTrueColorGetGreen(src) * src_weight
4108 	         + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
4109 	blue = (gdTrueColorGetBlue(src) * src_weight
4110 	        + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
4111 
4112 	/* -------------------------------------------------------------------- */
4113 	/*      Return merged result.                                           */
4114 	/* -------------------------------------------------------------------- */
4115 	return ((alpha << 24) + (red << 16) + (green << 8) + blue);
4116 }
4117 
4118 static int gdAlphaOverlayColor (int src, int dst, int max );
4119 
4120 /**
4121  * Function: gdLayerOverlay
4122  *
4123  * Overlay two colors
4124  *
4125  * Parameters:
4126  *   dst - The color to overlay onto.
4127  *   src - The color to overlay.
4128  *
4129  * See also:
4130  *   - <gdImageAlphaBlending>
4131  *   - <gdAlphaBlend>
4132  *   - <gdLayerMultiply>
4133  */
gdLayerOverlay(int dst,int src)4134 BGD_DECLARE(int) gdLayerOverlay (int dst, int src)
4135 {
4136 	int a1, a2;
4137 	a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
4138 	a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
4139 	return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
4140 		(gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
4141 		(gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
4142 		(gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
4143 		);
4144 }
4145 
4146 /* Apply 'overlay' effect - background pixels are colourised by the foreground colour */
gdAlphaOverlayColor(int src,int dst,int max)4147 static int gdAlphaOverlayColor (int src, int dst, int max )
4148 {
4149 	dst = dst << 1;
4150 	if( dst > max ) {
4151 		/* in the "light" zone */
4152 		return dst + (src << 1) - (dst * src / max) - max;
4153 	} else {
4154 		/* in the "dark" zone */
4155 		return dst * src / max;
4156 	}
4157 }
4158 
4159 /**
4160  * Function: gdLayerMultiply
4161  *
4162  * Overlay two colors with multiply effect
4163  *
4164  * Parameters:
4165  *   dst - The color to overlay onto.
4166  *   src - The color to overlay.
4167  *
4168  * See also:
4169  *   - <gdImageAlphaBlending>
4170  *   - <gdAlphaBlend>
4171  *   - <gdLayerOverlay>
4172  */
gdLayerMultiply(int dst,int src)4173 BGD_DECLARE(int) gdLayerMultiply (int dst, int src)
4174 {
4175 	int a1, a2, r1, r2, g1, g2, b1, b2;
4176 	a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
4177 	a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
4178 
4179 	r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
4180 	r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
4181 	g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
4182 	g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
4183 	b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
4184 	b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
4185 
4186 	a1 = gdAlphaMax - a1;
4187 	a2 = gdAlphaMax - a2;
4188 	return ( ((a1*a2/gdAlphaMax) << 24) +
4189 			 ((r1*r2/gdRedMax) << 16) +
4190 			 ((g1*g2/gdGreenMax) << 8) +
4191 			 ((b1*b2/gdBlueMax))
4192 		);
4193 }
4194 
4195 /**
4196  *	Function: gdImageAlphaBlending
4197  *
4198  *	Set the effect for subsequent drawing operations
4199  *
4200  *	Note that the effect is used for truecolor images only.
4201  *
4202  * Parameters:
4203  *   im               - The image.
4204  *   alphaBlendingArg - The effect.
4205  *
4206  * See also:
4207  *   - <Effects>
4208  */
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)4209 BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
4210 {
4211 	im->alphaBlendingFlag = alphaBlendingArg;
4212 }
4213 
4214 /**
4215  * Function: gdImageSaveAlpha
4216  *
4217  * Sets the save alpha flag
4218  *
4219  * The save alpha flag specifies whether the alpha channel of the pixels should
4220  * be saved. This is supported only for image formats that support full alpha
4221  * transparency, e.g. PNG.
4222  */
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)4223 BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
4224 {
4225 	im->saveAlphaFlag = saveAlphaArg;
4226 }
4227 
4228 /**
4229  * Function: gdImageSetClip
4230  *
4231  * Sets the clipping rectangle
4232  *
4233  * The clipping rectangle restricts the drawing area for following drawing
4234  * operations.
4235  *
4236  * Parameters:
4237  *   im - The image.
4238  *   x1 - The x-coordinate of the upper left corner.
4239  *   y1 - The y-coordinate of the upper left corner.
4240  *   x2 - The x-coordinate of the lower right corner.
4241  *   y2 - The y-coordinate of the lower right corner.
4242  *
4243  * See also:
4244  *   - <gdImageGetClip>
4245  */
gdImageSetClip(gdImagePtr im,int x1,int y1,int x2,int y2)4246 BGD_DECLARE(void) gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
4247 {
4248 	if (x1 < 0) {
4249 		x1 = 0;
4250 	}
4251 	if (x1 >= im->sx) {
4252 		x1 = im->sx - 1;
4253 	}
4254 	if (x2 < 0) {
4255 		x2 = 0;
4256 	}
4257 	if (x2 >= im->sx) {
4258 		x2 = im->sx - 1;
4259 	}
4260 	if (y1 < 0) {
4261 		y1 = 0;
4262 	}
4263 	if (y1 >= im->sy) {
4264 		y1 = im->sy - 1;
4265 	}
4266 	if (y2 < 0) {
4267 		y2 = 0;
4268 	}
4269 	if (y2 >= im->sy) {
4270 		y2 = im->sy - 1;
4271 	}
4272 	im->cx1 = x1;
4273 	im->cy1 = y1;
4274 	im->cx2 = x2;
4275 	im->cy2 = y2;
4276 }
4277 
4278 /**
4279  * Function: gdImageGetClip
4280  *
4281  * Gets the current clipping rectangle
4282  *
4283  * Parameters:
4284  *   im - The image.
4285  *   x1P - (out) The x-coordinate of the upper left corner.
4286  *   y1P - (out) The y-coordinate of the upper left corner.
4287  *   x2P - (out) The x-coordinate of the lower right corner.
4288  *   y2P - (out) The y-coordinate of the lower right corner.
4289  *
4290  * See also:
4291  *   - <gdImageSetClip>
4292  */
gdImageGetClip(gdImagePtr im,int * x1P,int * y1P,int * x2P,int * y2P)4293 BGD_DECLARE(void) gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
4294 {
4295 	*x1P = im->cx1;
4296 	*y1P = im->cy1;
4297 	*x2P = im->cx2;
4298 	*y2P = im->cy2;
4299 }
4300 
4301 /**
4302  * Function: gdImageSetResolution
4303  *
4304  * Sets the resolution of an image.
4305  *
4306  * Parameters:
4307  *   im    - The image.
4308  *   res_x - The horizontal resolution in DPI.
4309  *   res_y - The vertical resolution in DPI.
4310  *
4311  * See also:
4312  *   - <gdImageResolutionX>
4313  *   - <gdImageResolutionY>
4314  */
gdImageSetResolution(gdImagePtr im,const unsigned int res_x,const unsigned int res_y)4315 BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
4316 {
4317 	if (res_x > 0) im->res_x = res_x;
4318 	if (res_y > 0) im->res_y = res_y;
4319 }
4320 
4321 /*
4322  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
4323  * */
4324 #define BLEND_COLOR(a, nc, c, cc) \
4325 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
4326 
gdImageSetAAPixelColor(gdImagePtr im,int x,int y,int color,int t)4327 static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
4328 {
4329 	int dr,dg,db,p,r,g,b;
4330 
4331 	/* 2.0.34: watch out for out of range calls */
4332 	if (!gdImageBoundsSafeMacro(im, x, y)) {
4333 		return;
4334 	}
4335 	p = gdImageGetPixel(im,x,y);
4336 	/* TBB: we have to implement the dont_blend stuff to provide
4337 	  the full feature set of the old implementation */
4338 	if ((p == color)
4339 	        || ((p == im->AA_dont_blend)
4340 	            && (t != 0x00))) {
4341 		return;
4342 	}
4343 	dr = gdTrueColorGetRed(color);
4344 	dg = gdTrueColorGetGreen(color);
4345 	db = gdTrueColorGetBlue(color);
4346 
4347 	r = gdTrueColorGetRed(p);
4348 	g = gdTrueColorGetGreen(p);
4349 	b = gdTrueColorGetBlue(p);
4350 
4351 	BLEND_COLOR(t, dr, r, dr);
4352 	BLEND_COLOR(t, dg, g, dg);
4353 	BLEND_COLOR(t, db, b, db);
4354 	im->tpixels[y][x] = gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque);
4355 }
4356 
gdImageAALine(gdImagePtr im,int x1,int y1,int x2,int y2,int col)4357 static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
4358 {
4359 	/* keep them as 32bits */
4360 	long x, y, inc, frac;
4361 	long dx, dy,tmp;
4362 	int w, wid, wstart;
4363 	int thick = im->thick;
4364 
4365 	if (!im->trueColor) {
4366 		/* TBB: don't crash when the image is of the wrong type */
4367 		gdImageLine(im, x1, y1, x2, y2, col);
4368 		return;
4369 	}
4370 
4371 	/* TBB: use the clipping rectangle */
4372 	if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
4373 		return;
4374 	if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
4375 		return;
4376 
4377 	dx = x2 - x1;
4378 	dy = y2 - y1;
4379 
4380 	if (dx == 0 && dy == 0) {
4381 		/* TBB: allow setting points */
4382 		gdImageSetPixel(im, x1, y1, col);
4383 		return;
4384 	} else {
4385 		double ag;
4386 		/* Cast the long to an int to avoid compiler warnings about truncation.
4387 		 * This isn't a problem as computed dy/dx values came from ints above. */
4388 		ag = fabs(abs((int)dy) < abs((int)dx) ? cos(atan2(dy, dx)) : sin(atan2(dy, dx)));
4389 		if (ag != 0) {
4390 			wid = thick / ag;
4391 		} else {
4392 			wid = 1;
4393 		}
4394 		if (wid == 0) {
4395 			wid = 1;
4396 		}
4397 	}
4398 
4399 	/* Axis aligned lines */
4400 	if (dx == 0) {
4401 		gdImageVLine(im, x1, y1, y2, col);
4402 		return;
4403 	} else if (dy == 0) {
4404 		gdImageHLine(im, y1, x1, x2, col);
4405 		return;
4406 	}
4407 
4408 	if (abs((int)dx) > abs((int)dy)) {
4409 		if (dx < 0) {
4410 			tmp = x1;
4411 			x1 = x2;
4412 			x2 = tmp;
4413 			tmp = y1;
4414 			y1 = y2;
4415 			y2 = tmp;
4416 			dx = x2 - x1;
4417 			dy = y2 - y1;
4418 		}
4419 		y = y1;
4420 		inc = (dy * 65536) / dx;
4421 		frac = 0;
4422 		/* TBB: set the last pixel for consistency (<=) */
4423 		for (x = x1 ; x <= x2 ; x++) {
4424 			wstart = y - wid / 2;
4425 			for (w = wstart; w < wstart + wid; w++) {
4426 			    gdImageSetAAPixelColor(im, x , w , col , (frac >> 8) & 0xFF);
4427 			    gdImageSetAAPixelColor(im, x , w + 1 , col, (~frac >> 8) & 0xFF);
4428 			}
4429 			frac += inc;
4430 			if (frac >= 65536) {
4431 				frac -= 65536;
4432 				y++;
4433 			} else if (frac < 0) {
4434 				frac += 65536;
4435 				y--;
4436 			}
4437 		}
4438 	} else {
4439 		if (dy < 0) {
4440 			tmp = x1;
4441 			x1 = x2;
4442 			x2 = tmp;
4443 			tmp = y1;
4444 			y1 = y2;
4445 			y2 = tmp;
4446 			dx = x2 - x1;
4447 			dy = y2 - y1;
4448 		}
4449 		x = x1;
4450 		inc = (dx * 65536) / dy;
4451 		frac = 0;
4452 		/* TBB: set the last pixel for consistency (<=) */
4453 		for (y = y1 ; y <= y2 ; y++) {
4454 			wstart = x - wid / 2;
4455 			for (w = wstart; w < wstart + wid; w++) {
4456 			    gdImageSetAAPixelColor(im, w , y  , col, (frac >> 8) & 0xFF);
4457 			    gdImageSetAAPixelColor(im, w + 1, y, col, (~frac >> 8) & 0xFF);
4458 			}
4459 			frac += inc;
4460 			if (frac >= 65536) {
4461 				frac -= 65536;
4462 				x++;
4463 			} else if (frac < 0) {
4464 				frac += 65536;
4465 				x--;
4466 			}
4467 		}
4468 	}
4469 }
4470 
4471 
4472 /**
4473  * Function: gdImagePaletteToTrueColor
4474  *
4475  * Convert a palette image to true color
4476  *
4477  * Parameters:
4478  *   src - The image.
4479  *
4480  * Returns:
4481  *   Non-zero if the conversion succeeded, zero otherwise.
4482  *
4483  * See also:
4484  *   - <gdImageTrueColorToPalette>
4485  */
gdImagePaletteToTrueColor(gdImagePtr src)4486 BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src)
4487 {
4488 	unsigned int y;
4489 	unsigned int yy;
4490 
4491 	if (src == NULL) {
4492 		return 0;
4493 	}
4494 
4495 	if (src->trueColor == 1) {
4496 		return 1;
4497 	} else {
4498 		unsigned int x;
4499 		const unsigned int sy = gdImageSY(src);
4500 		const unsigned int sx = gdImageSX(src);
4501 
4502 		src->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
4503 		if (src->tpixels == NULL) {
4504 			return 0;
4505 		}
4506 
4507 		for (y = 0; y < sy; y++) {
4508 			const unsigned char *src_row = src->pixels[y];
4509 			int * dst_row;
4510 
4511 			/* no need to calloc it, we overwrite all pxl anyway */
4512 			src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int));
4513 			if (src->tpixels[y] == NULL) {
4514 				goto clean_on_error;
4515 			}
4516 
4517 			dst_row = src->tpixels[y];
4518 			for (x = 0; x < sx; x++) {
4519 				const unsigned char c = *(src_row + x);
4520 				if (c == src->transparent) {
4521 					*(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
4522 				} else {
4523 					*(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
4524 				}
4525 			}
4526 		}
4527 	}
4528 
4529 	/* free old palette buffer (y is sy) */
4530 	for (yy = 0; yy < y; yy++) {
4531 		gdFree(src->pixels[yy]);
4532 	}
4533 	gdFree(src->pixels);
4534 	src->trueColor = 1;
4535 	src->pixels = NULL;
4536 	src->alphaBlendingFlag = 0;
4537 	src->saveAlphaFlag = 1;
4538 
4539 	if (src->transparent >= 0) {
4540 		const unsigned char c = src->transparent;
4541 		src->transparent =  gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
4542 	}
4543 
4544 	return 1;
4545 
4546 clean_on_error:
4547 	/* free new true color buffer (y is not allocated, have failed) */
4548 	for (yy = 0; yy < y; yy++) {
4549 		gdFree(src->tpixels[yy]);
4550 	}
4551 	gdFree(src->tpixels);
4552 	return 0;
4553 }
4554