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