1 /* $Id: gd.c,v 1.49.2.16 2007/06/19 20:25:51 pajoye Exp $ */
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
9 #include <stdlib.h>
10 /* 2.03: don't include zlib here or we can't build without PNG */
11 #include "gd.h"
12 #include "gdhelpers.h"
13 
14 /* 2.0.12: this now checks the clipping rectangle */
15 #define gdImageBoundsSafeMacro(im, x, y) (!((((y) < (im)->cy1) || ((y) > (im)->cy2)) || (((x) < (im)->cx1) || ((x) > (im)->cx2))))
16 
17 #ifdef _OSD_POSIX		/* BS2000 uses the EBCDIC char set instead of ASCII */
18 #define CHARSET_EBCDIC
19 #define __attribute__(any)	/*nothing */
20 #endif
21 /*_OSD_POSIX*/
22 
23 #ifndef CHARSET_EBCDIC
24 #define ASC(ch)  ch
25 #else /*CHARSET_EBCDIC */
26 #define ASC(ch) gd_toascii[(unsigned char)ch]
27 static const unsigned char gd_toascii[256] = {
28 /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
29   0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,	/*................ */
30 /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
31   0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f,	/*................ */
32 /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
33   0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,	/*................ */
34 /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
35   0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,	/*................ */
36 /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
37   0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,	/* .........`.<(+| */
38 /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
39   0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f,	/*&.........!$*);. */
40 /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
41   0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
42 /*-/........^,%_>?*/
43 /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
44   0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,	/*..........:#@'=" */
45 /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
46   0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1,	/*.abcdefghi...... */
47 /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
48   0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4,	/*.jklmnopqr...... */
49 /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
50   0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae,	/*..stuvwxyz...... */
51 /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
52   0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7,	/*...........[\].. */
53 /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
54   0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5,	/*.ABCDEFGHI...... */
55 /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
56   0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff,	/*.JKLMNOPQR...... */
57 /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
58   0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5,	/*..STUVWXYZ...... */
59 /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
60   0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e	/*0123456789.{.}.~ */
61 };
62 #endif /*CHARSET_EBCDIC */
63 
64 extern int gdCosT[];
65 extern int gdSinT[];
66 
67 static void gdImageBrushApply (gdImagePtr im, int x, int y);
68 static void gdImageTileApply (gdImagePtr im, int x, int y);
69 BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
70 
gdImageCreate(int sx,int sy)71 BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
72 {
73   int i;
74   gdImagePtr im;
75 
76   if (overflow2(sizeof (unsigned char *), sy)) {
77 		return NULL;
78   }
79   if (overflow2(sizeof (unsigned char *), sx)) {
80 		return NULL;
81   }
82 
83   im = (gdImage *) gdMalloc (sizeof (gdImage));
84 	if (!im) {
85 		return NULL;
86 	}
87 
88   memset (im, 0, sizeof (gdImage));
89   /* Row-major ever since gd 1.3 */
90   im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy);
91 	if (!im->pixels) {
92 		gdFree(im);
93 		return NULL;
94 	}
95 
96   im->polyInts = 0;
97   im->polyAllocated = 0;
98   im->brush = 0;
99   im->tile = 0;
100   im->style = 0;
101   for (i = 0; (i < sy); i++)
102     {
103       /* Row-major ever since gd 1.3 */
104       im->pixels[i] = (unsigned char *) gdCalloc (sx, sizeof (unsigned char));
105 			if (!im->pixels[i])
106 			{
107 				for (--i ; i >= 0; i--)
108 				{
109 					gdFree(im->pixels[i]);
110 				}
111 				gdFree(im->pixels);
112 				gdFree(im);
113 				return NULL;
114 			}
115 
116     }
117   im->sx = sx;
118   im->sy = sy;
119   im->colorsTotal = 0;
120   im->transparent = (-1);
121   im->interlace = 0;
122   im->thick = 1;
123   im->AA = 0;
124   for (i = 0; (i < gdMaxColors); i++)
125     {
126       im->open[i] = 1;
127       im->red[i] = 0;
128       im->green[i] = 0;
129       im->blue[i] = 0;
130     };
131   im->trueColor = 0;
132   im->tpixels = 0;
133   im->cx1 = 0;
134   im->cy1 = 0;
135   im->cx2 = im->sx - 1;
136   im->cy2 = im->sy - 1;
137   return im;
138 }
139 
gdImageCreateTrueColor(int sx,int sy)140 BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
141 {
142   int i;
143   gdImagePtr im;
144 
145   if (overflow2(sx, sy)) {
146     return NULL;
147   }
148 
149   if (overflow2(sizeof (int *), sy)) {
150     return 0;
151   }
152 
153   if (overflow2(sizeof(int), sx)) {
154     return NULL;
155   }
156 
157   im = (gdImage *) gdMalloc (sizeof (gdImage));
158   if (!im) {
159     return 0;
160   }
161   memset (im, 0, sizeof (gdImage));
162 
163   im->tpixels = (int **) gdMalloc (sizeof (int *) * sy);
164   if (!im->tpixels) {
165     gdFree(im);
166     return 0;
167   }
168   im->polyInts = 0;
169   im->polyAllocated = 0;
170   im->brush = 0;
171   im->tile = 0;
172   im->style = 0;
173   for (i = 0; (i < sy); i++)
174     {
175       im->tpixels[i] = (int *) gdCalloc (sx, sizeof (int));
176       if (!im->tpixels[i]) {
177         /* 2.0.34 */
178         i--;
179         while (i >= 0) {
180           gdFree(im->tpixels[i]);
181           i--;
182         }
183         gdFree(im->tpixels);
184         gdFree(im);
185         return 0;
186       }
187     }
188   im->sx = sx;
189   im->sy = sy;
190   im->transparent = (-1);
191   im->interlace = 0;
192   im->trueColor = 1;
193   /* 2.0.2: alpha blending is now on by default, and saving of alpha is
194      off by default. This allows font antialiasing to work as expected
195      on the first try in JPEGs -- quite important -- and also allows
196      for smaller PNGs when saving of alpha channel is not really
197      desired, which it usually isn't! */
198   im->saveAlphaFlag = 0;
199   im->alphaBlendingFlag = 1;
200   im->thick = 1;
201   im->AA = 0;
202   im->cx1 = 0;
203   im->cy1 = 0;
204   im->cx2 = im->sx - 1;
205   im->cy2 = im->sy - 1;
206   return im;
207 }
208 
gdImageDestroy(gdImagePtr im)209 BGD_DECLARE(void) gdImageDestroy (gdImagePtr im)
210 {
211   int i;
212   if (im->pixels)
213     {
214       for (i = 0; (i < im->sy); i++)
215 	{
216 	  gdFree (im->pixels[i]);
217 	}
218       gdFree (im->pixels);
219     }
220   if (im->tpixels)
221     {
222       for (i = 0; (i < im->sy); i++)
223 	{
224 	  gdFree (im->tpixels[i]);
225 	}
226       gdFree (im->tpixels);
227     }
228   if (im->polyInts)
229     {
230       gdFree (im->polyInts);
231     }
232   if (im->style)
233     {
234       gdFree (im->style);
235     }
236   gdFree (im);
237 }
238 
gdImageColorClosest(gdImagePtr im,int r,int g,int b)239 BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b)
240 {
241   return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
242 }
243 
gdImageColorClosestAlpha(gdImagePtr im,int r,int g,int b,int a)244 BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
245 {
246   int i;
247   long rd, gd, bd, ad;
248   int ct = (-1);
249   int first = 1;
250   long mindist = 0;
251   if (im->trueColor)
252     {
253       return gdTrueColorAlpha (r, g, b, a);
254     }
255   for (i = 0; (i < (im->colorsTotal)); i++)
256     {
257       long dist;
258       if (im->open[i])
259 	{
260 	  continue;
261 	}
262       rd = (im->red[i] - r);
263       gd = (im->green[i] - g);
264       bd = (im->blue[i] - b);
265       /* gd 2.02: whoops, was - b (thanks to David Marwood) */
266       /* gd 2.16: was blue rather than alpha! Geez! Thanks to
267          Artur Jakub Jerzak */
268       ad = (im->alpha[i] - a);
269       dist = rd * rd + gd * gd + bd * bd + ad * ad;
270       if (first || (dist < mindist))
271 	{
272 	  mindist = dist;
273 	  ct = i;
274 	  first = 0;
275 	}
276     }
277   return ct;
278 }
279 
280 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
281  * on colour conversion to/from RBG and HWB colour systems.
282  * It has been modified to return the converted value as a * parameter.
283  */
284 
285 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
286 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
287 #define HWB_UNDEFINED -1
288 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;}
289 
290 #define MIN(a,b) ((a)<(b)?(a):(b))
291 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
292 #define MAX(a,b) ((a)<(b)?(b):(a))
293 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
294 
295 
296 /*
297  * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
298  * red always maps to 6 in this implementation. Therefore UNDEFINED can be
299  * defined as 0 in situations where only unsigned numbers are desired.
300  */
301 typedef struct
302 {
303   float R, G, B;
304 }
305 RGBType;
306 typedef struct
307 {
308   float H, W, B;
309 }
310 HWBType;
311 
312 static HWBType *
RGB_to_HWB(RGBType RGB,HWBType * HWB)313 RGB_to_HWB (RGBType RGB, HWBType * HWB)
314 {
315 
316   /*
317    * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
318    * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
319    */
320 
321   float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
322   int i;
323 
324   w = MIN3 (R, G, B);
325   v = MAX3 (R, G, B);
326   b = 1 - v;
327   if (v == w)
328     RETURN_HWB (HWB_UNDEFINED, w, b);
329   f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
330   i = (R == w) ? 3 : ((G == w) ? 5 : 1);
331   RETURN_HWB (i - f / (v - w), w, b);
332 
333 }
334 
335 static float
HWB_Diff(int r1,int g1,int b1,int r2,int g2,int b2)336 HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
337 {
338   RGBType RGB1, RGB2;
339   HWBType HWB1, HWB2;
340   float diff;
341 
342   SETUP_RGB (RGB1, r1, g1, b1);
343   SETUP_RGB (RGB2, r2, g2, b2);
344 
345   RGB_to_HWB (RGB1, &HWB1);
346   RGB_to_HWB (RGB2, &HWB2);
347 
348   /*
349    * I made this bit up; it seems to produce OK results, and it is certainly
350    * more visually correct than the current RGB metric. (PJW)
351    */
352 
353   if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED))
354     {
355       diff = 0;			/* Undefined hues always match... */
356     }
357   else
358     {
359       diff = fabs (HWB1.H - HWB2.H);
360       if (diff > 3)
361 	{
362 	  diff = 6 - diff;	/* Remember, it's a colour circle */
363 	}
364     }
365 
366   diff =
367     diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B -
368 							   HWB2.B) * (HWB1.B -
369 								      HWB2.B);
370 
371   return diff;
372 }
373 
374 
375 #if 0
376 /*
377  * This is not actually used, but is here for completeness, in case someone wants to
378  * use the HWB stuff for anything else...
379  */
380 static RGBType *
381 HWB_to_RGB (HWBType HWB, RGBType * RGB)
382 {
383 
384   /*
385    * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
386    * RGB are each returned on [0, 1].
387    */
388 
389   float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
390   int i;
391 
392   v = 1 - b;
393   if (h == HWB_UNDEFINED)
394     RETURN_RGB (v, v, v);
395   i = floor (h);
396   f = h - i;
397   if (i & 1)
398     f = 1 - f;			/* if i is odd */
399   n = w + f * (v - w);		/* linear interpolation between w and v */
400   switch (i)
401     {
402     case 6:
403     case 0:
404       RETURN_RGB (v, n, w);
405     case 1:
406       RETURN_RGB (n, v, w);
407     case 2:
408       RETURN_RGB (w, v, n);
409     case 3:
410       RETURN_RGB (w, n, v);
411     case 4:
412       RETURN_RGB (n, w, v);
413     case 5:
414       RETURN_RGB (v, w, n);
415     }
416 
417   return RGB;
418 
419 }
420 #endif
421 
gdImageColorClosestHWB(gdImagePtr im,int r,int g,int b)422 BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
423 {
424   int i;
425   /* long rd, gd, bd; */
426   int ct = (-1);
427   int first = 1;
428   float mindist = 0;
429   if (im->trueColor)
430     {
431       return gdTrueColor (r, g, b);
432     }
433   for (i = 0; (i < (im->colorsTotal)); i++)
434     {
435       float dist;
436       if (im->open[i])
437 	{
438 	  continue;
439 	}
440       dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b);
441       if (first || (dist < mindist))
442 	{
443 	  mindist = dist;
444 	  ct = i;
445 	  first = 0;
446 	}
447     }
448   return ct;
449 }
450 
gdImageColorExact(gdImagePtr im,int r,int g,int b)451 BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b)
452 {
453   return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
454 }
455 
gdImageColorExactAlpha(gdImagePtr im,int r,int g,int b,int a)456 BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
457 {
458   int i;
459   if (im->trueColor)
460     {
461       return gdTrueColorAlpha (r, g, b, a);
462     }
463   for (i = 0; (i < (im->colorsTotal)); i++)
464     {
465       if (im->open[i])
466 	{
467 	  continue;
468 	}
469       if ((im->red[i] == r) &&
470 	  (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a))
471 	{
472 	  return i;
473 	}
474     }
475   return -1;
476 }
477 
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)478 BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
479 {
480   return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
481 }
482 
gdImageColorAllocateAlpha(gdImagePtr im,int r,int g,int b,int a)483 BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
484 {
485   int i;
486   int ct = (-1);
487   if (im->trueColor)
488     {
489       return gdTrueColorAlpha (r, g, b, a);
490     }
491   for (i = 0; (i < (im->colorsTotal)); i++)
492     {
493       if (im->open[i])
494 	{
495 	  ct = i;
496 	  break;
497 	}
498     }
499   if (ct == (-1))
500     {
501       ct = im->colorsTotal;
502       if (ct == gdMaxColors)
503 	{
504 	  return -1;
505 	}
506       im->colorsTotal++;
507     }
508   im->red[ct] = r;
509   im->green[ct] = g;
510   im->blue[ct] = b;
511   im->alpha[ct] = a;
512   im->open[ct] = 0;
513   return ct;
514 }
515 
516 /*
517  * gdImageColorResolve is an alternative for the code fragment:
518  *
519  *      if ((color=gdImageColorExact(im,R,G,B)) < 0)
520  *        if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
521  *          color=gdImageColorClosest(im,R,G,B);
522  *
523  * in a single function.    Its advantage is that it is guaranteed to
524  * return a color index in one search over the color table.
525  */
526 
gdImageColorResolve(gdImagePtr im,int r,int g,int b)527 BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b)
528 {
529   return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);
530 }
531 
gdImageColorResolveAlpha(gdImagePtr im,int r,int g,int b,int a)532 BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
533 {
534   int c;
535   int ct = -1;
536   int op = -1;
537   long rd, gd, bd, ad, dist;
538   long mindist = 4 * 255 * 255;	/* init to max poss dist */
539   if (im->trueColor)
540     {
541       return gdTrueColorAlpha (r, g, b, a);
542     }
543 
544   for (c = 0; c < im->colorsTotal; c++)
545     {
546       if (im->open[c])
547 	{
548 	  op = c;		/* Save open slot */
549 	  continue;		/* Color not in use */
550 	}
551       if (c == im->transparent)
552 	{
553 	  /* don't ever resolve to the color that has
554 	   * been designated as the transparent color */
555 	  continue;
556 	}
557       rd = (long) (im->red[c] - r);
558       gd = (long) (im->green[c] - g);
559       bd = (long) (im->blue[c] - b);
560       ad = (long) (im->alpha[c] - a);
561       dist = rd * rd + gd * gd + bd * bd + ad * ad;
562       if (dist < mindist)
563 	{
564 	  if (dist == 0)
565 	    {
566 	      return c;		/* Return exact match color */
567 	    }
568 	  mindist = dist;
569 	  ct = c;
570 	}
571     }
572   /* no exact match.  We now know closest, but first try to allocate exact */
573   if (op == -1)
574     {
575       op = im->colorsTotal;
576       if (op == gdMaxColors)
577 	{			/* No room for more colors */
578 	  return ct;		/* Return closest available color */
579 	}
580       im->colorsTotal++;
581     }
582   im->red[op] = r;
583   im->green[op] = g;
584   im->blue[op] = b;
585   im->alpha[op] = a;
586   im->open[op] = 0;
587   return op;			/* Return newly allocated color */
588 }
589 
gdImageColorDeallocate(gdImagePtr im,int color)590 BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color)
591 {
592   if (im->trueColor)
593     {
594       return;
595     }
596   /* Mark it open. */
597   im->open[color] = 1;
598 }
599 
gdImageColorTransparent(gdImagePtr im,int color)600 BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color)
601 {
602   if (!im->trueColor)
603     {
604       if (im->transparent != -1)
605 	{
606 	  im->alpha[im->transparent] = gdAlphaOpaque;
607 	}
608       if (color != -1)
609 	{
610 	  im->alpha[color] = gdAlphaTransparent;
611 	}
612     }
613   im->transparent = color;
614 }
615 
gdImagePaletteCopy(gdImagePtr to,gdImagePtr from)616 BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
617 {
618   int i;
619   int x, y, p;
620   int xlate[256];
621   if (to->trueColor)
622     {
623       return;
624     }
625   if (from->trueColor)
626     {
627       return;
628     }
629 
630   for (i = 0; i < 256; i++)
631     {
632       xlate[i] = -1;
633     };
634 
635   for (x = 0; x < (to->sx); x++)
636     {
637       for (y = 0; y < (to->sy); y++)
638 	{
639           /* Optimization: no gdImageGetPixel */
640 	  p = to->pixels[y][x];
641 	  if (xlate[p] == -1)
642 	    {
643 	      /* This ought to use HWB, but we don't have an alpha-aware
644 	         version of that yet. */
645 	      xlate[p] =
646 		gdImageColorClosestAlpha (from, to->red[p], to->green[p],
647 					  to->blue[p], to->alpha[p]);
648 	      /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */
649 	      /*      p,  to->red[p], to->green[p], to->blue[p], to->alpha[p], */
650 	      /*      xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
651 	    };
652           /* Optimization: no gdImageSetPixel */
653 	  to->pixels[y][x] = xlate[p];
654 	};
655     };
656 
657   for (i = 0; (i < (from->colorsTotal)); i++)
658     {
659       /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */
660       to->red[i] = from->red[i];
661       to->blue[i] = from->blue[i];
662       to->green[i] = from->green[i];
663       to->alpha[i] = from->alpha[i];
664       to->open[i] = 0;
665     };
666 
667   for (i = from->colorsTotal; (i < to->colorsTotal); i++)
668     {
669       to->open[i] = 1;
670     };
671 
672   to->colorsTotal = from->colorsTotal;
673 
674 }
675 
676 /* 2.0.10: before the drawing routines, some code to clip points that are
677  * outside the drawing window.  Nick Atty (nick@canalplan.org.uk)
678  *
679  * This is the Sutherland Hodgman Algorithm, as implemented by
680  * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short.  See Dr Dobb's
681  * Journal, January 1996, pp107-110 and 116-117
682  *
683  * Given the end points of a line, and a bounding rectangle (which we
684  * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
685  * the edges of the rectangle if the line should be drawn at all,
686  * otherwise return a failure code */
687 
688 /* this does "one-dimensional" clipping: note that the second time it
689    is called, all the x parameters refer to height and the y to width
690    - the comments ignore this (if you can understand it when it's
691    looking at the X parameters, it should become clear what happens on
692    the second call!)  The code is simplified from that in the article,
693    as we know that gd images always start at (0,0) */
694 
695 /* 2.0.26, TBB: we now have to respect a clipping rectangle, it won't
696 	necessarily start at 0. */
697 
698 static int
clip_1d(int * x0,int * y0,int * x1,int * y1,int mindim,int maxdim)699 clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim)
700 {
701   double m;			/* gradient of line */
702   if (*x0 < mindim)
703     {				/* start of line is left of window */
704       if (*x1 < mindim)		/* as is the end, so the line never cuts the window */
705 	return 0;
706       m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
707       /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
708       *y0 -= m * (*x0 - mindim);
709       *x0 = mindim;
710       /* now, perhaps, adjust the far end of the line as well */
711       if (*x1 > maxdim)
712 	{
713 	  *y1 += m * (maxdim - *x1);
714 	  *x1 = maxdim;
715 	}
716       return 1;
717     }
718   if (*x0 > maxdim)
719     {				/* start of line is right of window -
720 				   complement of above */
721       if (*x1 > maxdim)		/* as is the end, so the line misses the window */
722 	return 0;
723       m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
724       *y0 += m * (maxdim - *x0);	/* adjust so point is on the right
725 					   boundary */
726       *x0 = maxdim;
727       /* now, perhaps, adjust the end of the line */
728       if (*x1 < mindim)
729 	{
730 	  *y1 -= m * (*x1 - mindim);
731 	  *x1 = mindim;
732 	}
733       return 1;
734     }
735   /* the final case - the start of the line is inside the window */
736   if (*x1 > maxdim)
737     {				/* other end is outside to the right */
738       m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
739       *y1 += m * (maxdim - *x1);
740       *x1 = maxdim;
741       return 1;
742     }
743   if (*x1 < mindim)
744     {				/* other end is outside to the left */
745       m = (*y1 - *y0) / (double) (*x1 - *x0);	/* calculate the slope of the line */
746       *y1 -= m * (*x1 - mindim);
747       *x1 = mindim;
748       return 1;
749     }
750   /* only get here if both points are inside the window */
751   return 1;
752 }
753 
754 /* end of line clipping code */
755 
gdImageSetPixel(gdImagePtr im,int x,int y,int color)756 BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color)
757 {
758   int p;
759   switch (color)
760     {
761     case gdStyled:
762       if (!im->style)
763 	{
764 	  /* Refuse to draw if no style is set. */
765 	  return;
766 	}
767       else
768 	{
769 	  p = im->style[im->stylePos++];
770 	}
771       if (p != (gdTransparent))
772 	{
773 	  gdImageSetPixel (im, x, y, p);
774 	}
775       im->stylePos = im->stylePos % im->styleLength;
776       break;
777     case gdStyledBrushed:
778       if (!im->style)
779 	{
780 	  /* Refuse to draw if no style is set. */
781 	  return;
782 	}
783       p = im->style[im->stylePos++];
784       if ((p != gdTransparent) && (p != 0))
785 	{
786 	  gdImageSetPixel (im, x, y, gdBrushed);
787 	}
788       im->stylePos = im->stylePos % im->styleLength;
789       break;
790     case gdBrushed:
791       gdImageBrushApply (im, x, y);
792       break;
793     case gdTiled:
794       gdImageTileApply (im, x, y);
795       break;
796     case gdAntiAliased:
797       /* This shouldn't happen (2.0.26) because we just call
798         gdImageAALine now, but do something sane. */
799       gdImageSetPixel(im, x, y, im->AA_color);
800       break;
801     default:
802       if (gdImageBoundsSafeMacro (im, x, y))
803 	{
804 	  if (im->trueColor)
805 	    {
806 	      if (im->alphaBlendingFlag)
807 		{
808 		  im->tpixels[y][x] = gdAlphaBlend (im->tpixels[y][x], color);
809 		}
810 	      else
811 		{
812 		  im->tpixels[y][x] = color;
813 		}
814 	    }
815 	  else
816 	    {
817 	      im->pixels[y][x] = color;
818 	    }
819 	}
820       break;
821     }
822 }
823 
824 static void
gdImageBrushApply(gdImagePtr im,int x,int y)825 gdImageBrushApply (gdImagePtr im, int x, int y)
826 {
827   int lx, ly;
828   int hy;
829   int hx;
830   int x1, y1, x2, y2;
831   int srcx, srcy;
832   if (!im->brush)
833     {
834       return;
835     }
836   hy = gdImageSY (im->brush) / 2;
837   y1 = y - hy;
838   y2 = y1 + gdImageSY (im->brush);
839   hx = gdImageSX (im->brush) / 2;
840   x1 = x - hx;
841   x2 = x1 + gdImageSX (im->brush);
842   srcy = 0;
843   if (im->trueColor)
844     {
845       if (im->brush->trueColor)
846 	{
847 	  for (ly = y1; (ly < y2); ly++)
848 	    {
849 	      srcx = 0;
850 	      for (lx = x1; (lx < x2); lx++)
851 		{
852 		  int p;
853 		  p = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
854 		  /* 2.0.9, Thomas Winzig: apply simple full transparency */
855 		  if (p != gdImageGetTransparent (im->brush))
856 		    {
857 		      gdImageSetPixel (im, lx, ly, p);
858 		    }
859 		  srcx++;
860 		}
861 	      srcy++;
862 	    }
863 	}
864       else
865 	{
866 	  /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger
867 	     for pointing out the issue) */
868 	  for (ly = y1; (ly < y2); ly++)
869 	    {
870 	      srcx = 0;
871 	      for (lx = x1; (lx < x2); lx++)
872 		{
873 		  int p, tc;
874 		  p = gdImageGetPixel (im->brush, srcx, srcy);
875 		  tc = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
876 		  /* 2.0.9, Thomas Winzig: apply simple full transparency */
877 		  if (p != gdImageGetTransparent (im->brush))
878 		    {
879 		      gdImageSetPixel (im, lx, ly, tc);
880 		    }
881 		  srcx++;
882 		}
883 	      srcy++;
884 	    }
885 	}
886     }
887   else
888     {
889       for (ly = y1; (ly < y2); ly++)
890 	{
891 	  srcx = 0;
892 	  for (lx = x1; (lx < x2); lx++)
893 	    {
894 	      int p;
895 	      p = gdImageGetPixel (im->brush, srcx, srcy);
896 	      /* Allow for non-square brushes! */
897 	      if (p != gdImageGetTransparent (im->brush))
898 		{
899 		  /* Truecolor brush. Very slow
900 		     on a palette destination. */
901 		  if (im->brush->trueColor)
902 		    {
903 		      gdImageSetPixel (im, lx, ly,
904 				       gdImageColorResolveAlpha (im,
905 								 gdTrueColorGetRed
906 								 (p),
907 								 gdTrueColorGetGreen
908 								 (p),
909 								 gdTrueColorGetBlue
910 								 (p),
911 								 gdTrueColorGetAlpha
912 								 (p)));
913 		    }
914 		  else
915 		    {
916 		      gdImageSetPixel (im, lx, ly, im->brushColorMap[p]);
917 		    }
918 		}
919 	      srcx++;
920 	    }
921 	  srcy++;
922 	}
923     }
924 }
925 
926 static void
gdImageTileApply(gdImagePtr im,int x,int y)927 gdImageTileApply (gdImagePtr im, int x, int y)
928 {
929   int srcx, srcy;
930   int p;
931   if (!im->tile)
932     {
933       return;
934     }
935   srcx = x % gdImageSX (im->tile);
936   srcy = y % gdImageSY (im->tile);
937   if (im->trueColor)
938     {
939       p = gdImageGetTrueColorPixel (im->tile, srcx, srcy);
940 			if (p != gdImageGetTransparent (im->tile)) {
941 	      gdImageSetPixel (im, x, y, p);
942 			}
943     }
944   else
945     {
946       p = gdImageGetPixel (im->tile, srcx, srcy);
947       /* Allow for transparency */
948       if (p != gdImageGetTransparent (im->tile))
949 	{
950 	  if (im->tile->trueColor)
951 	    {
952 	      /* Truecolor tile. Very slow
953 	         on a palette destination. */
954 	      gdImageSetPixel (im, x, y,
955 			       gdImageColorResolveAlpha (im,
956 							 gdTrueColorGetRed
957 							 (p),
958 							 gdTrueColorGetGreen
959 							 (p),
960 							 gdTrueColorGetBlue
961 							 (p),
962 							 gdTrueColorGetAlpha
963 							 (p)));
964 	    }
965 	  else
966 	    {
967 	      gdImageSetPixel (im, x, y, im->tileColorMap[p]);
968 	    }
969 	}
970     }
971 }
972 
gdImageGetPixel(gdImagePtr im,int x,int y)973 BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y)
974 {
975   if (gdImageBoundsSafeMacro (im, x, y))
976     {
977       if (im->trueColor)
978 	{
979 	  return im->tpixels[y][x];
980 	}
981       else
982 	{
983 	  return im->pixels[y][x];
984 	}
985     }
986   else
987     {
988       return 0;
989     }
990 }
991 
gdImageGetTrueColorPixel(gdImagePtr im,int x,int y)992 BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
993 {
994   int p = gdImageGetPixel (im, x, y);
995   if (!im->trueColor)
996     {
997       return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p],
998 			       (im->transparent == p) ? gdAlphaTransparent :
999 			       im->alpha[p]);
1000     }
1001   else
1002     {
1003       return p;
1004     }
1005 }
1006 
gdImageAABlend(gdImagePtr im)1007 BGD_DECLARE(void) gdImageAABlend (gdImagePtr im)
1008 {
1009   /* NO-OP, kept for library compatibility. */
1010 }
1011 
1012 static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col);
1013 
gdImageHLine(gdImagePtr im,int y,int x1,int x2,int col)1014 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
1015 {
1016 	if (im->thick > 1) {
1017 		int thickhalf = im->thick >> 1;
1018 		gdImageFilledRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
1019 	} else {
1020 		if (x2 < x1) {
1021 			int t = x2;
1022 			x2 = x1;
1023 			x1 = t;
1024 		}
1025 
1026 		for (;x1 <= x2; x1++) {
1027 			gdImageSetPixel(im, x1, y, col);
1028 		}
1029 	}
1030 	return;
1031 }
1032 
gdImageVLine(gdImagePtr im,int x,int y1,int y2,int col)1033 static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
1034 {
1035 	if (im->thick > 1) {
1036 		int thickhalf = im->thick >> 1;
1037 		gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
1038 	} else {
1039 		if (y2 < y1) {
1040 			int t = y1;
1041 			y1 = y2;
1042 			y2 = t;
1043 		}
1044 
1045 		for (;y1 <= y2; y1++) {
1046 			gdImageSetPixel(im, x, y1, col);
1047 		}
1048 	}
1049 	return;
1050 }
1051 
1052 /* Bresenham as presented in Foley & Van Dam */
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1053 BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1054 {
1055   int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1056   int wid;
1057   int w, wstart;
1058   int thick;
1059 
1060   if (color == gdAntiAliased)
1061     {
1062       /*
1063         gdAntiAliased passed as color: use the much faster, much cheaper
1064         and equally attractive gdImageAALine implementation. That
1065         clips too, so don't clip twice.
1066       */
1067       gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
1068       return;
1069     }
1070   /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no
1071      points need to be drawn. 2.0.26, TBB: clip to edges of clipping
1072      rectangle. We were getting away with this because gdImageSetPixel
1073      is used for actual drawing, but this is still more efficient and opens
1074      the way to skip per-pixel bounds checking in the future. */
1075 
1076   if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
1077     return;
1078   if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
1079     return;
1080   thick = im->thick;
1081 
1082   dx = abs (x2 - x1);
1083   dy = abs (y2 - y1);
1084 
1085 	if (dx == 0) {
1086 		gdImageVLine(im, x1, y1, y2, color);
1087 		return;
1088 	} else if (dy == 0) {
1089 		gdImageHLine(im, y1, x1, x2, color);
1090 		return;
1091 	}
1092 
1093   if (dy <= dx)
1094     {
1095       /* More-or-less horizontal. use wid for vertical stroke */
1096       /* Doug Claar: watch out for NaN in atan2 (2.0.5) */
1097       if ((dx == 0) && (dy == 0))
1098 	{
1099 	  wid = 1;
1100 	}
1101       else
1102 	{
1103 	  /* 2.0.12: Michael Schwartz: divide rather than multiply;
1104 	     TBB: but watch out for /0! */
1105 	  double ac = cos (atan2 (dy, dx));
1106 	  if (ac != 0)
1107 	    {
1108 	      wid = thick / ac;
1109 	    }
1110 	  else
1111 	    {
1112 	      wid = 1;
1113 	    }
1114 	  if (wid == 0)
1115 	    {
1116 	      wid = 1;
1117 	    }
1118 	}
1119       d = 2 * dy - dx;
1120       incr1 = 2 * dy;
1121       incr2 = 2 * (dy - dx);
1122       if (x1 > x2)
1123 	{
1124 	  x = x2;
1125 	  y = y2;
1126 	  ydirflag = (-1);
1127 	  xend = x1;
1128 	}
1129       else
1130 	{
1131 	  x = x1;
1132 	  y = y1;
1133 	  ydirflag = 1;
1134 	  xend = x2;
1135 	}
1136 
1137       /* Set up line thickness */
1138       wstart = y - wid / 2;
1139       for (w = wstart; w < wstart + wid; w++)
1140 	gdImageSetPixel (im, x, w, color);
1141 
1142       if (((y2 - y1) * ydirflag) > 0)
1143 	{
1144 	  while (x < xend)
1145 	    {
1146 	      x++;
1147 	      if (d < 0)
1148 		{
1149 		  d += incr1;
1150 		}
1151 	      else
1152 		{
1153 		  y++;
1154 		  d += incr2;
1155 		}
1156 	      wstart = y - wid / 2;
1157 	      for (w = wstart; w < wstart + wid; w++)
1158 		gdImageSetPixel (im, x, w, color);
1159 	    }
1160 	}
1161       else
1162 	{
1163 	  while (x < xend)
1164 	    {
1165 	      x++;
1166 	      if (d < 0)
1167 		{
1168 		  d += incr1;
1169 		}
1170 	      else
1171 		{
1172 		  y--;
1173 		  d += incr2;
1174 		}
1175 	      wstart = y - wid / 2;
1176 	      for (w = wstart; w < wstart + wid; w++)
1177 		gdImageSetPixel (im, x, w, color);
1178 	    }
1179 	}
1180     }
1181   else
1182     {
1183       /* More-or-less vertical. use wid for horizontal stroke */
1184       /* 2.0.12: Michael Schwartz: divide rather than multiply;
1185          TBB: but watch out for /0! */
1186       double as = sin (atan2 (dy, dx));
1187       if (as != 0)
1188 	{
1189 	  wid = thick / as;
1190 	}
1191       else
1192 	{
1193 	  wid = 1;
1194 	}
1195       if (wid == 0)
1196 	wid = 1;
1197 
1198       d = 2 * dx - dy;
1199       incr1 = 2 * dx;
1200       incr2 = 2 * (dx - dy);
1201       if (y1 > y2)
1202 	{
1203 	  y = y2;
1204 	  x = x2;
1205 	  yend = y1;
1206 	  xdirflag = (-1);
1207 	}
1208       else
1209 	{
1210 	  y = y1;
1211 	  x = x1;
1212 	  yend = y2;
1213 	  xdirflag = 1;
1214 	}
1215 
1216       /* Set up line thickness */
1217       wstart = x - wid / 2;
1218       for (w = wstart; w < wstart + wid; w++)
1219 	gdImageSetPixel (im, w, y, color);
1220 
1221       if (((x2 - x1) * xdirflag) > 0)
1222 	{
1223 	  while (y < yend)
1224 	    {
1225 	      y++;
1226 	      if (d < 0)
1227 		{
1228 		  d += incr1;
1229 		}
1230 	      else
1231 		{
1232 		  x++;
1233 		  d += incr2;
1234 		}
1235 	      wstart = x - wid / 2;
1236 	      for (w = wstart; w < wstart + wid; w++)
1237 		gdImageSetPixel (im, w, y, color);
1238 	    }
1239 	}
1240       else
1241 	{
1242 	  while (y < yend)
1243 	    {
1244 	      y++;
1245 	      if (d < 0)
1246 		{
1247 		  d += incr1;
1248 		}
1249 	      else
1250 		{
1251 		  x--;
1252 		  d += incr2;
1253 		}
1254 	      wstart = x - wid / 2;
1255 	      for (w = wstart; w < wstart + wid; w++)
1256 		gdImageSetPixel (im, w, y, color);
1257 	    }
1258 	}
1259     }
1260 
1261 }
1262 static void dashedSet (gdImagePtr im, int x, int y, int color,
1263 		       int *onP, int *dashStepP, int wid, int vert);
1264 
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1265 BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1266 {
1267   int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1268   int dashStep = 0;
1269   int on = 1;
1270   int wid;
1271   int vert;
1272   int thick = im->thick;
1273 
1274   dx = abs (x2 - x1);
1275   dy = abs (y2 - y1);
1276   if (dy <= dx)
1277     {
1278       /* More-or-less horizontal. use wid for vertical stroke */
1279       /* 2.0.12: Michael Schwartz: divide rather than multiply;
1280          TBB: but watch out for /0! */
1281       double as = sin (atan2 (dy, dx));
1282       if (as != 0)
1283 	{
1284 	  wid = thick / as;
1285 	}
1286       else
1287 	{
1288 	  wid = 1;
1289 	}
1290       vert = 1;
1291 
1292       d = 2 * dy - dx;
1293       incr1 = 2 * dy;
1294       incr2 = 2 * (dy - dx);
1295       if (x1 > x2)
1296 	{
1297 	  x = x2;
1298 	  y = y2;
1299 	  ydirflag = (-1);
1300 	  xend = x1;
1301 	}
1302       else
1303 	{
1304 	  x = x1;
1305 	  y = y1;
1306 	  ydirflag = 1;
1307 	  xend = x2;
1308 	}
1309       dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1310       if (((y2 - y1) * ydirflag) > 0)
1311 	{
1312 	  while (x < xend)
1313 	    {
1314 	      x++;
1315 	      if (d < 0)
1316 		{
1317 		  d += incr1;
1318 		}
1319 	      else
1320 		{
1321 		  y++;
1322 		  d += incr2;
1323 		}
1324 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1325 	    }
1326 	}
1327       else
1328 	{
1329 	  while (x < xend)
1330 	    {
1331 	      x++;
1332 	      if (d < 0)
1333 		{
1334 		  d += incr1;
1335 		}
1336 	      else
1337 		{
1338 		  y--;
1339 		  d += incr2;
1340 		}
1341 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1342 	    }
1343 	}
1344     }
1345   else
1346     {
1347       /* 2.0.12: Michael Schwartz: divide rather than multiply;
1348          TBB: but watch out for /0! */
1349       double as = sin (atan2 (dy, dx));
1350       if (as != 0)
1351 	{
1352 	  wid = thick / as;
1353 	}
1354       else
1355 	{
1356 	  wid = 1;
1357 	}
1358       vert = 0;
1359 
1360       d = 2 * dx - dy;
1361       incr1 = 2 * dx;
1362       incr2 = 2 * (dx - dy);
1363       if (y1 > y2)
1364 	{
1365 	  y = y2;
1366 	  x = x2;
1367 	  yend = y1;
1368 	  xdirflag = (-1);
1369 	}
1370       else
1371 	{
1372 	  y = y1;
1373 	  x = x1;
1374 	  yend = y2;
1375 	  xdirflag = 1;
1376 	}
1377       dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1378       if (((x2 - x1) * xdirflag) > 0)
1379 	{
1380 	  while (y < yend)
1381 	    {
1382 	      y++;
1383 	      if (d < 0)
1384 		{
1385 		  d += incr1;
1386 		}
1387 	      else
1388 		{
1389 		  x++;
1390 		  d += incr2;
1391 		}
1392 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1393 	    }
1394 	}
1395       else
1396 	{
1397 	  while (y < yend)
1398 	    {
1399 	      y++;
1400 	      if (d < 0)
1401 		{
1402 		  d += incr1;
1403 		}
1404 	      else
1405 		{
1406 		  x--;
1407 		  d += incr2;
1408 		}
1409 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1410 	    }
1411 	}
1412     }
1413 }
1414 
1415 static void
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1416 dashedSet (gdImagePtr im, int x, int y, int color,
1417 	   int *onP, int *dashStepP, int wid, int vert)
1418 {
1419   int dashStep = *dashStepP;
1420   int on = *onP;
1421   int w, wstart;
1422 
1423   dashStep++;
1424   if (dashStep == gdDashSize)
1425     {
1426       dashStep = 0;
1427       on = !on;
1428     }
1429   if (on)
1430     {
1431       if (vert)
1432 	{
1433 	  wstart = y - wid / 2;
1434 	  for (w = wstart; w < wstart + wid; w++)
1435 	    gdImageSetPixel (im, x, w, color);
1436 	}
1437       else
1438 	{
1439 	  wstart = x - wid / 2;
1440 	  for (w = wstart; w < wstart + wid; w++)
1441 	    gdImageSetPixel (im, w, y, color);
1442 	}
1443     }
1444   *dashStepP = dashStep;
1445   *onP = on;
1446 }
1447 
gdImageBoundsSafe(gdImagePtr im,int x,int y)1448 BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y)
1449 {
1450   return gdImageBoundsSafeMacro (im, x, y);
1451 }
1452 
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1453 BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1454 {
1455   int cx, cy;
1456   int px, py;
1457   int fline;
1458   cx = 0;
1459   cy = 0;
1460 #ifdef CHARSET_EBCDIC
1461   c = ASC (c);
1462 #endif /*CHARSET_EBCDIC */
1463   if ((c < f->offset) || (c >= (f->offset + f->nchars)))
1464     {
1465       return;
1466     }
1467   fline = (c - f->offset) * f->h * f->w;
1468   for (py = y; (py < (y + f->h)); py++)
1469     {
1470       for (px = x; (px < (x + f->w)); px++)
1471 	{
1472 	  if (f->data[fline + cy * f->w + cx])
1473 	    {
1474 	      gdImageSetPixel (im, px, py, color);
1475 	    }
1476 	  cx++;
1477 	}
1478       cx = 0;
1479       cy++;
1480     }
1481 }
1482 
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1483 BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
1484 {
1485   int cx, cy;
1486   int px, py;
1487   int fline;
1488   cx = 0;
1489   cy = 0;
1490 #ifdef CHARSET_EBCDIC
1491   c = ASC (c);
1492 #endif /*CHARSET_EBCDIC */
1493   if ((c < f->offset) || (c >= (f->offset + f->nchars)))
1494     {
1495       return;
1496     }
1497   fline = (c - f->offset) * f->h * f->w;
1498   for (py = y; (py > (y - f->w)); py--)
1499     {
1500       for (px = x; (px < (x + f->h)); px++)
1501 	{
1502 	  if (f->data[fline + cy * f->w + cx])
1503 	    {
1504 	      gdImageSetPixel (im, px, py, color);
1505 	    }
1506 	  cy++;
1507 	}
1508       cy = 0;
1509       cx++;
1510     }
1511 }
1512 
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1513 BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f,
1514 	       int x, int y, unsigned char *s, int color)
1515 {
1516   int i;
1517   int l;
1518   l = strlen ((char *) s);
1519   for (i = 0; (i < l); i++)
1520     {
1521       gdImageChar (im, f, x, y, s[i], color);
1522       x += f->w;
1523     }
1524 }
1525 
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1526 BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f,
1527 		 int x, int y, unsigned char *s, int color)
1528 {
1529   int i;
1530   int l;
1531   l = strlen ((char *) s);
1532   for (i = 0; (i < l); i++)
1533     {
1534       gdImageCharUp (im, f, x, y, s[i], color);
1535       y -= f->w;
1536     }
1537 }
1538 
1539 static int strlen16 (unsigned short *s);
1540 
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1541 BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f,
1542 		 int x, int y, unsigned short *s, int color)
1543 {
1544   int i;
1545   int l;
1546   l = strlen16 (s);
1547   for (i = 0; (i < l); i++)
1548     {
1549       gdImageChar (im, f, x, y, s[i], color);
1550       x += f->w;
1551     }
1552 }
1553 
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1554 BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f,
1555 		   int x, int y, unsigned short *s, int color)
1556 {
1557   int i;
1558   int l;
1559   l = strlen16 (s);
1560   for (i = 0; (i < l); i++)
1561     {
1562       gdImageCharUp (im, f, x, y, s[i], color);
1563       y -= f->w;
1564     }
1565 }
1566 
1567 static int
strlen16(unsigned short * s)1568 strlen16 (unsigned short *s)
1569 {
1570   int len = 0;
1571   while (*s)
1572     {
1573       s++;
1574       len++;
1575     }
1576   return len;
1577 }
1578 
1579 #ifndef HAVE_LSQRT
1580 /* If you don't have a nice square root function for longs, you can use
1581    ** this hack
1582  */
1583 long
lsqrt(long n)1584 lsqrt (long n)
1585 {
1586   long result = (long) sqrt ((double) n);
1587   return result;
1588 }
1589 #endif
1590 
1591 /* s and e are integers modulo 360 (degrees), with 0 degrees
1592    being the rightmost extreme and degrees changing clockwise.
1593    cx and cy are the center in pixels; w and h are the horizontal
1594    and vertical diameter in pixels. Nice interface, but slow.
1595    See gd_arc_f_buggy.c for a better version that doesn't
1596    seem to be bug-free yet. */
1597 
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)1598 BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
1599 	    int color)
1600 {
1601   gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill);
1602 }
1603 
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)1604 BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
1605 		  int color, int style)
1606 {
1607   gdPoint pts[3];
1608   int i;
1609   int lx = 0, ly = 0;
1610   int fx = 0, fy = 0;
1611 
1612   if ((s % 360)  == (e % 360)) {
1613 	  s = 0; e = 360;
1614   } else {
1615 	  if (s > 360) {
1616 		  s = s % 360;
1617 	  }
1618 
1619 	  if (e > 360) {
1620 		  e = e % 360;
1621 	  }
1622 
1623 	  while (s < 0) {
1624 		  s += 360;
1625 	  }
1626 
1627 	  while (e < s) {
1628 		  e += 360;
1629 	  }
1630 
1631 	  if (s == e) {
1632 		  s = 0; e = 360;
1633 	  }
1634   }
1635 
1636   for (i = s; (i <= e); i++)
1637     {
1638       int x, y;
1639       x = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
1640       y = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
1641       if (i != s)
1642 	{
1643 	  if (!(style & gdChord))
1644 	    {
1645 		if (style & gdNoFill)
1646 		{
1647 		  gdImageLine (im, lx, ly, x, y, color);
1648 		}
1649 	      else
1650 		{
1651 		  /* This is expensive! */
1652 		  pts[0].x = lx;
1653 		  pts[0].y = ly;
1654 		  pts[1].x = x;
1655 		  pts[1].y = y;
1656 		  pts[2].x = cx;
1657 		  pts[2].y = cy;
1658 		  gdImageFilledPolygon (im, pts, 3, color);
1659 		}
1660 	    }
1661 	}
1662       else
1663 	{
1664 	  fx = x;
1665 	  fy = y;
1666 	}
1667       lx = x;
1668       ly = y;
1669     }
1670   if (style & gdChord)
1671     {
1672       if (style & gdNoFill)
1673 	{
1674 	  if (style & gdEdged)
1675 	    {
1676 	      gdImageLine (im, cx, cy, lx, ly, color);
1677 	      gdImageLine (im, cx, cy, fx, fy, color);
1678 	    }
1679 	  gdImageLine (im, fx, fy, lx, ly, color);
1680 	}
1681       else
1682 	{
1683 	  pts[0].x = fx;
1684 	  pts[0].y = fy;
1685 	  pts[1].x = lx;
1686 	  pts[1].y = ly;
1687 	  pts[2].x = cx;
1688 	  pts[2].y = cy;
1689 	  gdImageFilledPolygon (im, pts, 3, color);
1690 	}
1691     }
1692   else
1693     {
1694       if (style & gdNoFill)
1695 	{
1696 	  if (style & gdEdged)
1697 	    {
1698 	      gdImageLine (im, cx, cy, lx, ly, color);
1699 	      gdImageLine (im, cx, cy, fx, fy, color);
1700 	    }
1701 	}
1702     }
1703 }
1704 
gdImageFilledEllipse(gdImagePtr im,int mx,int my,int w,int h,int c)1705 BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
1706 {
1707 	int x=0,mx1=0,mx2=0,my1=0,my2=0;
1708 	long aq,bq,dx,dy,r,rx,ry,a,b;
1709 	int i;
1710 	int old_y1,old_y2;
1711 
1712 	a=w>>1;
1713 	b=h>>1;
1714 
1715 	gdImageLine(im, mx-a, my, mx+a, my, c);
1716 
1717 	mx1 = mx-a;my1 = my;
1718 	mx2 = mx+a;my2 = my;
1719 
1720 	aq = a * a;
1721 	bq = b * b;
1722 	dx = aq << 1;
1723 	dy = bq << 1;
1724 	r  = a * bq;
1725 	rx = r << 1;
1726 	ry = 0;
1727 	x = a;
1728 	old_y2=-2;
1729 	old_y1=-2;
1730 	while (x > 0){
1731 		if (r > 0) {
1732 			my1++;my2--;
1733 			ry +=dx;
1734 			r  -=ry;
1735 		}
1736 		if (r <= 0){
1737 			x--;
1738 			mx1++;mx2--;
1739 			rx -=dy;
1740 			r  +=rx;
1741 		}
1742 		if(old_y2!=my2){
1743 			for(i=mx1;i<=mx2;i++){
1744 				gdImageSetPixel(im,i,my1,c);
1745 			}
1746 		}
1747 		if(old_y2!=my2){
1748 			for(i=mx1;i<=mx2;i++){
1749 				gdImageSetPixel(im,i,my2,c);
1750 			}
1751 		}
1752 		old_y2 = my2;
1753 		old_y1 = my1;
1754 	}
1755 }
1756 
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)1757 BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
1758 {
1759   int lastBorder;
1760   /* Seek left */
1761   int leftLimit, rightLimit;
1762   int i;
1763 	int restoreAlphaBleding;
1764 
1765   if (border < 0)
1766     {
1767       /* Refuse to fill to a non-solid border */
1768       return;
1769     }
1770 
1771 	leftLimit = (-1);
1772 
1773 	restoreAlphaBleding = im->alphaBlendingFlag;
1774 	im->alphaBlendingFlag = 0;
1775 
1776   for (i = x; (i >= 0); i--)
1777     {
1778       if (gdImageGetPixel (im, i, y) == border)
1779 	{
1780 	  break;
1781 	}
1782       gdImageSetPixel (im, i, y, color);
1783       leftLimit = i;
1784     }
1785   if (leftLimit == (-1))
1786     {
1787 			im->alphaBlendingFlag = restoreAlphaBleding;
1788       return;
1789     }
1790   /* Seek right */
1791   rightLimit = x;
1792   for (i = (x + 1); (i < im->sx); i++)
1793     {
1794       if (gdImageGetPixel (im, i, y) == border)
1795 	{
1796 	  break;
1797 	}
1798       gdImageSetPixel (im, i, y, color);
1799       rightLimit = i;
1800     }
1801   /* Look at lines above and below and start paints */
1802   /* Above */
1803   if (y > 0)
1804     {
1805       lastBorder = 1;
1806       for (i = leftLimit; (i <= rightLimit); i++)
1807 	{
1808 	  int c;
1809 	  c = gdImageGetPixel (im, i, y - 1);
1810 	  if (lastBorder)
1811 	    {
1812 	      if ((c != border) && (c != color))
1813 		{
1814 		  gdImageFillToBorder (im, i, y - 1, border, color);
1815 		  lastBorder = 0;
1816 		}
1817 	    }
1818 	  else if ((c == border) || (c == color))
1819 	    {
1820 	      lastBorder = 1;
1821 	    }
1822 	}
1823     }
1824   /* Below */
1825   if (y < ((im->sy) - 1))
1826     {
1827       lastBorder = 1;
1828       for (i = leftLimit; (i <= rightLimit); i++)
1829 	{
1830 	  int c = gdImageGetPixel (im, i, y + 1);
1831 	  if (lastBorder)
1832 	    {
1833 	      if ((c != border) && (c != color))
1834 		{
1835 		  gdImageFillToBorder (im, i, y + 1, border, color);
1836 		  lastBorder = 0;
1837 		}
1838 	    }
1839 	  else if ((c == border) || (c == color))
1840 	    {
1841 	      lastBorder = 1;
1842 	    }
1843 	}
1844     }
1845 	im->alphaBlendingFlag = restoreAlphaBleding;
1846 }
1847 
1848 /*
1849  * set the pixel at (x,y) and its 4-connected neighbors
1850  * with the same pixel value to the new pixel value nc (new color).
1851  * A 4-connected neighbor:  pixel above, below, left, or right of a pixel.
1852  * ideas from comp.graphics discussions.
1853  * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
1854  * contain the same color as the color to fill. To do not bloat normal filling
1855  * code I added a 2nd private function.
1856  */
1857 
gdImageTileGet(gdImagePtr im,int x,int y)1858 static int gdImageTileGet (gdImagePtr im, int x, int y)
1859 {
1860 	int srcx, srcy;
1861 	int tileColor,p;
1862 	if (!im->tile) {
1863 		return -1;
1864 	}
1865 	srcx = x % gdImageSX(im->tile);
1866 	srcy = y % gdImageSY(im->tile);
1867 	p = gdImageGetPixel(im->tile, srcx, srcy);
1868 	if (p == im->tile->transparent) {
1869 		tileColor = im->transparent;
1870 	} else if (im->trueColor) {
1871 		if (im->tile->trueColor) {
1872 			tileColor = p;
1873 		} else {
1874 			tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
1875 		}
1876 	} else {
1877 		if (im->tile->trueColor) {
1878 			tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
1879 		} else {
1880 			tileColor = p;
1881 			tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
1882 		}
1883 	}
1884 	return tileColor;
1885 }
1886 
1887 
1888 
1889 /* horizontal segment of scan line y */
1890 struct seg {int y, xl, xr, dy;};
1891 
1892 /* max depth of stack */
1893 #define FILL_MAX 1200000
1894 #define FILL_PUSH(Y, XL, XR, DY) \
1895     if (sp<stack+FILL_MAX*10 && Y+(DY)>=0 && Y+(DY)<wy2) \
1896     {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
1897 
1898 #define FILL_POP(Y, XL, XR, DY) \
1899     {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
1900 
1901 void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
gdImageFill(gdImagePtr im,int x,int y,int nc)1902 BGD_DECLARE(void) gdImageFill(gdImagePtr im, int x, int y, int nc)
1903 {
1904 	int l, x1, x2, dy;
1905 	int oc;   /* old pixel value */
1906 	int wx2,wy2;
1907 
1908 	int alphablending_bak;
1909 
1910 	/* stack of filled segments */
1911 	/* struct seg stack[FILL_MAX],*sp = stack;; */
1912 	struct seg *stack;
1913 	struct seg *sp;
1914 
1915 	if (!im->trueColor && nc > (im->colorsTotal - 1)) {
1916 		return;
1917 	}
1918 
1919 	alphablending_bak = im->alphaBlendingFlag;
1920 	im->alphaBlendingFlag = 0;
1921 
1922 	if (nc==gdTiled) {
1923 		_gdImageFillTiled(im,x,y,nc);
1924 		im->alphaBlendingFlag = alphablending_bak;
1925 		return;
1926 	}
1927 
1928 	wx2=im->sx;wy2=im->sy;
1929 	oc = gdImageGetPixel(im, x, y);
1930 	if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
1931 		im->alphaBlendingFlag = alphablending_bak;
1932 		return;
1933 	}
1934 
1935 	/* Do not use the 4 neighbors implementation with
1936    * small images
1937    */
1938 	if (im->sx < 4) {
1939 		int ix = x, iy = y, c;
1940 		do {
1941 			c = gdImageGetPixel(im, ix, iy);
1942 			if (c != oc) {
1943 				goto done;
1944 			}
1945 			gdImageSetPixel(im, ix, iy, nc);
1946 		} while(ix++ < (im->sx -1));
1947 		ix = x; iy = y + 1;
1948 		do {
1949 			c = gdImageGetPixel(im, ix, iy);
1950 			if (c != oc) {
1951 				goto done;
1952 			}
1953 			gdImageSetPixel(im, ix, iy, nc);
1954 		} while(ix++ < (im->sx -1));
1955 		goto done;
1956 	}
1957 
1958 	stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
1959 	if (!stack) {
1960 		return;
1961 	}
1962 	sp = stack;
1963 
1964 	/* required! */
1965 	FILL_PUSH(y,x,x,1);
1966 	/* seed segment (popped 1st) */
1967  	FILL_PUSH(y+1, x, x, -1);
1968 	while (sp>stack) {
1969 		FILL_POP(y, x1, x2, dy);
1970 
1971 		for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
1972 			gdImageSetPixel(im,x, y, nc);
1973 		}
1974 		if (x>=x1) {
1975 			goto skip;
1976 		}
1977 		l = x+1;
1978 
1979                 /* leak on left? */
1980 		if (l<x1) {
1981 			FILL_PUSH(y, l, x1-1, -dy);
1982 		}
1983 		x = x1+1;
1984 		do {
1985 			for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
1986 				gdImageSetPixel(im, x, y, nc);
1987 			}
1988 			FILL_PUSH(y, l, x-1, dy);
1989 			/* leak on right? */
1990 			if (x>x2+1) {
1991 				FILL_PUSH(y, x2+1, x-1, -dy);
1992 			}
1993 skip:			for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
1994 
1995 			l = x;
1996 		} while (x<=x2);
1997 	}
1998 
1999 	gdFree(stack);
2000 
2001 done:
2002 	im->alphaBlendingFlag = alphablending_bak;
2003 }
2004 
_gdImageFillTiled(gdImagePtr im,int x,int y,int nc)2005 void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
2006 {
2007 	int i,l, x1, x2, dy;
2008 	int oc;   /* old pixel value */
2009 	int tiled;
2010 	int wx2,wy2;
2011 	/* stack of filled segments */
2012 	struct seg *stack;
2013 	struct seg *sp;
2014 
2015 	int **pts;
2016 	if(!im->tile){
2017 		return;
2018 	}
2019 
2020 	wx2=im->sx;wy2=im->sy;
2021 	tiled = nc==gdTiled;
2022 
2023 	nc =  gdImageTileGet(im,x,y);
2024 	pts = (int **) gdCalloc(sizeof(int *) * im->sy, sizeof(int));
2025 	if (!pts) {
2026 		return;
2027 	}
2028 
2029 	for (i=0; i<im->sy;i++) {
2030 		pts[i] = (int *) gdCalloc(im->sx, sizeof(int));
2031 
2032 		if (!pts[i]) {
2033 			for (--i ; i >= 0; i--) {
2034 				gdFree(pts[i]);
2035 			}
2036 			return;
2037 		}
2038 	}
2039 
2040 	stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
2041 	if (!stack) {
2042 		return;
2043 	}
2044 	sp = stack;
2045 
2046 	oc = gdImageGetPixel(im, x, y);
2047 
2048 	/* required! */
2049 	FILL_PUSH(y,x,x,1);
2050 	/* seed segment (popped 1st) */
2051  	FILL_PUSH(y+1, x, x, -1);
2052 	while (sp>stack) {
2053 		FILL_POP(y, x1, x2, dy);
2054 		for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) {
2055 			if (pts[y][x]){
2056 				/* we should never be here */
2057 				break;
2058 			}
2059 			nc = gdImageTileGet(im,x,y);
2060 			pts[y][x]=1;
2061 			gdImageSetPixel(im,x, y, nc);
2062 		}
2063 		if (x>=x1) {
2064 			goto skip;
2065 		}
2066 		l = x+1;
2067 
2068 		/* leak on left? */
2069 		if (l<x1) {
2070 			FILL_PUSH(y, l, x1-1, -dy);
2071 		}
2072 		x = x1+1;
2073 		do {
2074 			for (; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc) ; x++) {
2075 				if (pts[y][x]){
2076 					/* we should never be here */
2077 					break;
2078 				}
2079 				nc = gdImageTileGet(im,x,y);
2080 				pts[y][x]=1;
2081 				gdImageSetPixel(im, x, y, nc);
2082 			}
2083 			FILL_PUSH(y, l, x-1, dy);
2084 			/* leak on right? */
2085 			if (x>x2+1) {
2086 				FILL_PUSH(y, x2+1, x-1, -dy);
2087 			}
2088 skip:			for (x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++);
2089 			l = x;
2090 		} while (x<=x2);
2091 	}
2092 	for (i=0; i<im->sy;i++) {
2093 		gdFree(pts[i]);
2094 	}
2095 	gdFree(pts);
2096 	gdFree(stack);
2097 }
2098 
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2099 BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
2100 {
2101 	int x1h = x1, x1v = x1, y1h = y1, y1v = y1, x2h = x2, x2v = x2, y2h = y2, y2v = y2;
2102 	int thick = im->thick;
2103 	int half1 = 1;
2104 	int t;
2105 
2106 	if (y2 < y1) {
2107 		t=y1;
2108 		y1 = y2;
2109 		y2 = t;
2110 
2111 		t = x1;
2112 		x1 = x2;
2113 		x2 = t;
2114 	}
2115 
2116 	x1h = x1; x1v = x1; y1h = y1; y1v = y1; x2h = x2; x2v = x2; y2h = y2; y2v = y2;
2117 	if (thick > 1) {
2118 		int cx, cy, x1ul, y1ul, x2lr, y2lr;
2119 		int half = thick >> 1;
2120 		half1 = thick - half;
2121 		x1ul = x1 - half;
2122 		y1ul = y1 - half;
2123 
2124 		x2lr = x2 + half;
2125 		y2lr = y2 + half;
2126 
2127 		cy = y1ul + thick;
2128 		while (cy-- > y1ul) {
2129 			cx = x1ul - 1;
2130 			while (cx++ < x2lr) {
2131 				gdImageSetPixel(im, cx, cy, color);
2132 			}
2133 		}
2134 
2135 		cy = y2lr - thick;
2136 		while (cy++ < y2lr) {
2137 			cx = x1ul - 1;
2138 			while (cx++ < x2lr) {
2139 				gdImageSetPixel(im, cx, cy, color);
2140 			}
2141 		}
2142 
2143 		cy = y1ul + thick - 1;
2144 		while (cy++ < y2lr -thick) {
2145 			cx = x1ul - 1;
2146 			while (cx++ < x1ul + thick) {
2147 				gdImageSetPixel(im, cx, cy, color);
2148 			}
2149 		}
2150 
2151 		cy = y1ul + thick - 1;
2152 		while (cy++ < y2lr -thick) {
2153 			cx = x2lr - thick - 1;
2154 			while (cx++ < x2lr) {
2155 				gdImageSetPixel(im, cx, cy, color);
2156 			}
2157 		}
2158 
2159 		return;
2160 	} else {
2161 		y1v = y1h + 1;
2162 		y2v = y2h - 1;
2163 		gdImageLine(im, x1h, y1h, x2h, y1h, color);
2164 		gdImageLine(im, x1h, y2h, x2h, y2h, color);
2165 		gdImageLine(im, x1v, y1v, x1v, y2v, color);
2166 		gdImageLine(im, x2v, y1v, x2v, y2v, color);
2167 	}
2168 }
2169 
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)2170 BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
2171 			int color)
2172 {
2173   int x, y;
2174   /* Nick Atty: limit the points at the edge.  Note that this also
2175      nicely kills any plotting for rectangles completely outside the
2176      window as it makes the tests in the for loops fail */
2177   if (x1 < 0)
2178 	  x1 = 0;
2179   if (x1 > gdImageSX (im))
2180 	  x1 = gdImageSX (im);
2181   if (y1 < 0)
2182 	  y1 = 0;
2183   if (y1 > gdImageSY (im))
2184 	  y1 = gdImageSY (im);
2185 
2186   if (x1 > x2) {
2187 	  x = x1;
2188 	  x1 = x2;
2189 	  x2 = x;
2190   }
2191   if (y1 > y2) {
2192 	  y = y1;
2193 	  y1 = y2;
2194 	  y2 = y;
2195   }
2196 
2197   for (y = y1; (y <= y2); y++)
2198     {
2199       for (x = x1; (x <= x2); x++)
2200 	{
2201 	  gdImageSetPixel (im, x, y, color);
2202 	}
2203     }
2204 }
2205 
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)2206 BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX,
2207 	     int srcY, int w, int h)
2208 {
2209   int c;
2210   int x, y;
2211   int tox, toy;
2212   int i;
2213   int colorMap[gdMaxColors];
2214 
2215   if (dst->trueColor) {
2216 	  /* 2.0: much easier when the destination is truecolor. */
2217 	  /* 2.0.10: needs a transparent-index check that is still valid if
2218 	   *          * the source is not truecolor. Thanks to Frank Warmerdam.
2219 	   */
2220 
2221 	  if (src->trueColor) {
2222 		  for (y = 0; (y < h); y++) {
2223 			  for (x = 0; (x < w); x++) {
2224 				  int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
2225 				  gdImageSetPixel (dst, dstX + x, dstY + y, c);
2226 			  }
2227 		  }
2228 	  } else {
2229 		  /* source is palette based */
2230 		  for (y = 0; (y < h); y++) {
2231 			  for (x = 0; (x < w); x++) {
2232 				  int c = gdImageGetPixel (src, srcX + x, srcY + y);
2233 				  if (c != src->transparent) {
2234 					  gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
2235 				  }
2236 			  }
2237 		  }
2238 	  }
2239 	  return;
2240   }
2241 
2242   for (i = 0; (i < gdMaxColors); i++)
2243   {
2244 	  colorMap[i] = (-1);
2245   }
2246   toy = dstY;
2247   for (y = srcY; (y < (srcY + h)); y++)
2248   {
2249 	  tox = dstX;
2250 	  for (x = srcX; (x < (srcX + w)); x++)
2251 	  {
2252 		  int nc;
2253 		  int mapTo;
2254 		  c = gdImageGetPixel (src, x, y);
2255 		  /* Added 7/24/95: support transparent copies */
2256 		  if (gdImageGetTransparent (src) == c)
2257 		  {
2258 			  tox++;
2259 			  continue;
2260 		  }
2261 		  /* Have we established a mapping for this color? */
2262 		  if (src->trueColor)
2263 		  {
2264 			  /* 2.05: remap to the palette available in the
2265 				 destination image. This is slow and
2266 				 works badly, but it beats crashing! Thanks
2267 				 to Padhrig McCarthy. */
2268 	      mapTo = gdImageColorResolveAlpha (dst,
2269 						gdTrueColorGetRed (c),
2270 						gdTrueColorGetGreen (c),
2271 						gdTrueColorGetBlue (c),
2272 						gdTrueColorGetAlpha (c));
2273 	    }
2274 	  else if (colorMap[c] == (-1))
2275 	    {
2276 	      /* If it's the same image, mapping is trivial */
2277 	      if (dst == src)
2278 		{
2279 		  nc = c;
2280 		}
2281 	      else
2282 		{
2283 		  /* Get best match possible. This
2284 		     function never returns error. */
2285 		  nc = gdImageColorResolveAlpha (dst,
2286 						 src->red[c], src->green[c],
2287 						 src->blue[c], src->alpha[c]);
2288 		}
2289 	      colorMap[c] = nc;
2290 	      mapTo = colorMap[c];
2291 	    }
2292 	  else
2293 	    {
2294 	      mapTo = colorMap[c];
2295 	    }
2296 	  gdImageSetPixel (dst, tox, toy, mapTo);
2297 	  tox++;
2298 	}
2299       toy++;
2300     }
2301 }
2302 
2303 /* This function is a substitute for real alpha channel operations,
2304    so it doesn't pay attention to the alpha channel. */
gdImageCopyMerge(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)2305 BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
2306 		  int srcX, int srcY, int w, int h, int pct)
2307 {
2308 
2309   int c, dc;
2310   int x, y;
2311   int tox, toy;
2312   int ncR, ncG, ncB;
2313   toy = dstY;
2314   for (y = srcY; (y < (srcY + h)); y++)
2315     {
2316       tox = dstX;
2317       for (x = srcX; (x < (srcX + w)); x++)
2318 	{
2319 	  int nc;
2320 	  c = gdImageGetPixel (src, x, y);
2321 	  /* Added 7/24/95: support transparent copies */
2322 	  if (gdImageGetTransparent (src) == c)
2323 	    {
2324 	      tox++;
2325 	      continue;
2326 	    }
2327 	  /* If it's the same image, mapping is trivial */
2328 	  if (dst == src)
2329 	    {
2330 	      nc = c;
2331 	    }
2332 	  else
2333 	    {
2334 	      dc = gdImageGetPixel (dst, tox, toy);
2335 
2336 	      ncR = gdImageRed (src, c) * (pct / 100.0)
2337 		+ gdImageRed (dst, dc) * ((100 - pct) / 100.0);
2338 	      ncG = gdImageGreen (src, c) * (pct / 100.0)
2339 		+ gdImageGreen (dst, dc) * ((100 - pct) / 100.0);
2340 	      ncB = gdImageBlue (src, c) * (pct / 100.0)
2341 		+ gdImageBlue (dst, dc) * ((100 - pct) / 100.0);
2342 
2343 	      /* Find a reasonable color */
2344 	      nc = gdImageColorResolve (dst, ncR, ncG, ncB);
2345 	    }
2346 	  gdImageSetPixel (dst, tox, toy, nc);
2347 	  tox++;
2348 	}
2349       toy++;
2350     }
2351 }
2352 
2353 /* This function is a substitute for real alpha channel operations,
2354    so it doesn't pay attention to the alpha channel. */
gdImageCopyMergeGray(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)2355 BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
2356 		      int srcX, int srcY, int w, int h, int pct)
2357 {
2358 
2359   int c, dc;
2360   int x, y;
2361   int tox, toy;
2362   int ncR, ncG, ncB;
2363   float g;
2364   toy = dstY;
2365   for (y = srcY; (y < (srcY + h)); y++)
2366     {
2367       tox = dstX;
2368       for (x = srcX; (x < (srcX + w)); x++)
2369 	{
2370 	  int nc;
2371 	  c = gdImageGetPixel (src, x, y);
2372 	  /* Added 7/24/95: support transparent copies */
2373 	  if (gdImageGetTransparent (src) == c)
2374 	    {
2375 	      tox++;
2376 	      continue;
2377 	    }
2378 	  /*
2379 	   * If it's the same image, mapping is NOT trivial since we
2380 	   * merge with greyscale target, but if pct is 100, the grey
2381 	   * value is not used, so it becomes trivial. pjw 2.0.12.
2382 	   */
2383 	  if (dst == src && pct == 100)
2384 	    {
2385 	      nc = c;
2386 	    }
2387 	  else
2388 	    {
2389 	      dc = gdImageGetPixel (dst, tox, toy);
2390 	      g = 0.29900 * gdImageRed(dst, dc)
2391 		+ 0.58700 * gdImageGreen(dst, dc) + 0.11400 * gdImageBlue(dst, dc);
2392 
2393 	      ncR = gdImageRed (src, c) * (pct / 100.0)
2394 		+ g * ((100 - pct) / 100.0);
2395 	      ncG = gdImageGreen (src, c) * (pct / 100.0)
2396 		+ g * ((100 - pct) / 100.0);
2397 	      ncB = gdImageBlue (src, c) * (pct / 100.0)
2398 		+ g * ((100 - pct) / 100.0);
2399 
2400 	      /* First look for an exact match */
2401 	      nc = gdImageColorExact (dst, ncR, ncG, ncB);
2402 	      if (nc == (-1))
2403 		{
2404 		  /* No, so try to allocate it */
2405 		  nc = gdImageColorAllocate (dst, ncR, ncG, ncB);
2406 		  /* If we're out of colors, go for the
2407 		     closest color */
2408 		  if (nc == (-1))
2409 		    {
2410 		      nc = gdImageColorClosest (dst, ncR, ncG, ncB);
2411 		    }
2412 		}
2413 	    }
2414 	  gdImageSetPixel (dst, tox, toy, nc);
2415 	  tox++;
2416 	}
2417       toy++;
2418     }
2419 }
2420 
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2421 BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
2422 		    int srcX, int srcY, int dstW, int dstH, int srcW,
2423 		    int srcH)
2424 {
2425   int c;
2426   int x, y;
2427   int tox, toy;
2428   int ydest;
2429   int i;
2430   int colorMap[gdMaxColors];
2431   /* Stretch vectors */
2432   int *stx;
2433   int *sty;
2434   /* We only need to use floating point to determine the correct
2435      stretch vector for one line's worth. */
2436   if (overflow2(sizeof (int), srcW)) {
2437     return;
2438   }
2439   if (overflow2(sizeof (int), srcH)) {
2440     return;
2441   }
2442   stx = (int *) gdMalloc (sizeof (int) * srcW);
2443 	if (!stx) {
2444 		return;
2445 	}
2446 
2447   sty = (int *) gdMalloc (sizeof (int) * srcH);
2448 	if (!sty) {
2449 		return;
2450 	}
2451 
2452   /* Fixed by Mao Morimoto 2.0.16 */
2453   for (i = 0; (i < srcW); i++)
2454     {
2455       stx[i] = dstW * (i + 1) / srcW - dstW * i / srcW;
2456     }
2457   for (i = 0; (i < srcH); i++)
2458     {
2459       sty[i] = dstH * (i + 1) / srcH - dstH * i / srcH;
2460     }
2461   for (i = 0; (i < gdMaxColors); i++)
2462     {
2463       colorMap[i] = (-1);
2464     }
2465   toy = dstY;
2466   for (y = srcY; (y < (srcY + srcH)); y++)
2467     {
2468       for (ydest = 0; (ydest < sty[y - srcY]); ydest++)
2469 	{
2470 	  tox = dstX;
2471 	  for (x = srcX; (x < (srcX + srcW)); x++)
2472 	    {
2473 	      int nc = 0;
2474 	      int mapTo;
2475 	      if (!stx[x - srcX])
2476 		{
2477 		  continue;
2478 		}
2479 	      if (dst->trueColor)
2480 		{
2481 		  /* 2.0.9: Thorben Kundinger: Maybe the source image is not
2482 		     a truecolor image */
2483 		  if (!src->trueColor)
2484 		    {
2485 		      int tmp = gdImageGetPixel (src, x, y);
2486 		      mapTo = gdImageGetTrueColorPixel (src, x, y);
2487 		      if (gdImageGetTransparent (src) == tmp)
2488 			{
2489 			  /* 2.0.21, TK: not tox++ */
2490 			  tox += stx[x - srcX];
2491 			  continue;
2492 			}
2493 		    }
2494 		  else
2495 		    {
2496 		      /* TK: old code follows */
2497 		      mapTo = gdImageGetTrueColorPixel (src, x, y);
2498 		      /* Added 7/24/95: support transparent copies */
2499 		      if (gdImageGetTransparent (src) == mapTo)
2500 			{
2501 			  /* 2.0.21, TK: not tox++ */
2502 			  tox += stx[x - srcX];
2503 			  continue;
2504 			}
2505 		    }
2506 		}
2507 	      else
2508 		{
2509 		  c = gdImageGetPixel (src, x, y);
2510 		  /* Added 7/24/95: support transparent copies */
2511 		  if (gdImageGetTransparent (src) == c)
2512 		    {
2513 		      tox += stx[x - srcX];
2514 		      continue;
2515 		    }
2516 		  if (src->trueColor)
2517 		    {
2518 		      /* Remap to the palette available in the
2519 		         destination image. This is slow and
2520 		         works badly. */
2521 		      mapTo = gdImageColorResolveAlpha (dst,
2522 							gdTrueColorGetRed (c),
2523 							gdTrueColorGetGreen
2524 							(c),
2525 							gdTrueColorGetBlue
2526 							(c),
2527 							gdTrueColorGetAlpha
2528 							(c));
2529 		    }
2530 		  else
2531 		    {
2532 		      /* Have we established a mapping for this color? */
2533 		      if (colorMap[c] == (-1))
2534 			{
2535 			  /* If it's the same image, mapping is trivial */
2536 			  if (dst == src)
2537 			    {
2538 			      nc = c;
2539 			    }
2540 			  else
2541 			    {
2542 			      /* Find or create the best match */
2543 			      /* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
2544 			      nc = gdImageColorResolveAlpha (dst,
2545 							     gdImageRed (src,
2546 									 c),
2547 							     gdImageGreen
2548 							     (src, c),
2549 							     gdImageBlue (src,
2550 									  c),
2551 							     gdImageAlpha
2552 							     (src, c));
2553 			    }
2554 			  colorMap[c] = nc;
2555 			}
2556 		      mapTo = colorMap[c];
2557 		    }
2558 		}
2559 	      for (i = 0; (i < stx[x - srcX]); i++)
2560 		{
2561 		  gdImageSetPixel (dst, tox, toy, mapTo);
2562 		  tox++;
2563 		}
2564 	    }
2565 	  toy++;
2566 	}
2567     }
2568   gdFree (stx);
2569   gdFree (sty);
2570 }
2571 
2572 /* gd 2.0.8: gdImageCopyRotated is added. Source
2573 	is a rectangle, with its upper left corner at
2574 	srcX and srcY. Destination is the *center* of
2575         the rotated copy. Angle is in degrees, same as
2576         gdImageArc. Floating point destination center
2577 	coordinates allow accurate rotation of
2578 	objects of odd-numbered width or height. */
2579 
gdImageCopyRotated(gdImagePtr dst,gdImagePtr src,double dstX,double dstY,int srcX,int srcY,int srcWidth,int srcHeight,int angle)2580 BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst,
2581 		    gdImagePtr src,
2582 		    double dstX, double dstY,
2583 		    int srcX, int srcY,
2584 		    int srcWidth, int srcHeight, int angle)
2585 {
2586   double dx, dy;
2587   double radius = sqrt (srcWidth * srcWidth + srcHeight * srcHeight);
2588   double aCos = cos (angle * .0174532925);
2589   double aSin = sin (angle * .0174532925);
2590   double scX = srcX + ((double) srcWidth) / 2;
2591   double scY = srcY + ((double) srcHeight) / 2;
2592   int cmap[gdMaxColors];
2593   int i;
2594 
2595 	/*
2596 		 2.0.34: transparency preservation. The transparentness of
2597 		 the transparent color is more important than its hue.
2598 	*/
2599 	if (src->transparent != -1) {
2600 		if (dst->transparent == -1) {
2601 			dst->transparent = src->transparent;
2602 		}
2603 	}
2604 
2605   for (i = 0; (i < gdMaxColors); i++)
2606     {
2607       cmap[i] = (-1);
2608     }
2609   for (dy = dstY - radius; (dy <= dstY + radius); dy++)
2610     {
2611       for (dx = dstX - radius; (dx <= dstX + radius); dx++)
2612 	{
2613 	  double sxd = (dx - dstX) * aCos - (dy - dstY) * aSin;
2614 	  double syd = (dy - dstY) * aCos + (dx - dstX) * aSin;
2615 	  int sx = sxd + scX;
2616 	  int sy = syd + scY;
2617 	  if ((sx >= srcX) && (sx < srcX + srcWidth) &&
2618 	      (sy >= srcY) && (sy < srcY + srcHeight))
2619 	    {
2620 				int c = gdImageGetPixel (src, sx, sy);
2621 				/* 2.0.34: transparency wins */
2622 				if (c == src->transparent)
2623 				{
2624 					gdImageSetPixel (dst, dx, dy, dst->transparent);
2625 				}
2626 					else if (!src->trueColor)
2627 				{
2628 		  /* Use a table to avoid an expensive
2629 		     lookup on every single pixel */
2630 		  if (cmap[c] == -1)
2631 		    {
2632 		      cmap[c] = gdImageColorResolveAlpha (dst,
2633 							  gdImageRed (src, c),
2634 							  gdImageGreen (src,
2635 									c),
2636 							  gdImageBlue (src,
2637 								       c),
2638 							  gdImageAlpha (src,
2639 									c));
2640 		    }
2641 		  gdImageSetPixel (dst, dx, dy, cmap[c]);
2642 		}
2643 	      else
2644 		{
2645 		  gdImageSetPixel (dst,
2646 				   dx, dy,
2647 				   gdImageColorResolveAlpha (dst,
2648 							     gdImageRed (src,
2649 									 c),
2650 							     gdImageGreen
2651 							     (src, c),
2652 							     gdImageBlue (src,
2653 									  c),
2654 							     gdImageAlpha
2655 							     (src, c)));
2656 		}
2657 	    }
2658 	}
2659     }
2660 }
2661 
2662 /* When gd 1.x was first created, floating point was to be avoided.
2663    These days it is often faster than table lookups or integer
2664    arithmetic. The routine below is shamelessly, gloriously
2665    floating point. TBB */
2666 
2667 /* 2.0.10: cast instead of floor() yields 35% performance improvement.
2668 	Thanks to John Buckman. */
2669 
2670 #define floor2(exp) ((long) exp)
2671 /*#define floor2(exp) floor(exp)*/
2672 
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2673 BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst,
2674 		      gdImagePtr src,
2675 		      int dstX, int dstY,
2676 		      int srcX, int srcY,
2677 		      int dstW, int dstH, int srcW, int srcH)
2678 {
2679   int x, y;
2680   double sy1, sy2, sx1, sx2;
2681   if (!dst->trueColor)
2682     {
2683       gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH,
2684 			  srcW, srcH);
2685       return;
2686     }
2687   for (y = dstY; (y < dstY + dstH); y++)
2688     {
2689       sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
2690       sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH /
2691 	(double) dstH;
2692       for (x = dstX; (x < dstX + dstW); x++)
2693 	{
2694 	  double sx, sy;
2695 	  double spixels = 0;
2696 	  double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
2697 	  sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
2698 	  sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
2699 	  sy = sy1;
2700 	  do
2701 	    {
2702 	      double yportion;
2703 	      if (floor2 (sy) == floor2 (sy1))
2704 		{
2705 		  yportion = 1.0 - (sy - floor2 (sy));
2706 		  if (yportion > sy2 - sy1)
2707 		    {
2708 		      yportion = sy2 - sy1;
2709 		    }
2710 		  sy = floor2 (sy);
2711 		}
2712 	      else if (sy == floor2 (sy2))
2713 		{
2714 		  yportion = sy2 - floor2 (sy2);
2715 		}
2716 	      else
2717 		{
2718 		  yportion = 1.0;
2719 		}
2720 	      sx = sx1;
2721 	      do
2722 		{
2723 		  double xportion;
2724 		  double pcontribution;
2725 		  int p;
2726 		  if (floor2 (sx) == floor2 (sx1))
2727 		    {
2728 		      xportion = 1.0 - (sx - floor2 (sx));
2729 		      if (xportion > sx2 - sx1)
2730 			{
2731 			  xportion = sx2 - sx1;
2732 			}
2733 		      sx = floor2 (sx);
2734 		    }
2735 		  else if (sx == floor2 (sx2))
2736 		    {
2737 		      xportion = sx2 - floor2 (sx2);
2738 		    }
2739 		  else
2740 		    {
2741 		      xportion = 1.0;
2742 		    }
2743 		  pcontribution = xportion * yportion;
2744 		  /* 2.08: previously srcX and srcY were ignored.
2745 		     Andrew Pattison */
2746 		  p = gdImageGetTrueColorPixel (src,
2747 						(int) sx + srcX,
2748 						(int) sy + srcY);
2749 		  red += gdTrueColorGetRed (p) * pcontribution;
2750 		  green += gdTrueColorGetGreen (p) * pcontribution;
2751 		  blue += gdTrueColorGetBlue (p) * pcontribution;
2752 		  alpha += gdTrueColorGetAlpha (p) * pcontribution;
2753 		  spixels += xportion * yportion;
2754 		  sx += 1.0;
2755 		}
2756 	      while (sx < sx2);
2757 	      sy += 1.0;
2758 	    }
2759 	  while (sy < sy2);
2760 	  if (spixels != 0.0)
2761 	    {
2762 	      red /= spixels;
2763 	      green /= spixels;
2764 	      blue /= spixels;
2765 	      alpha /= spixels;
2766 	    }
2767 	  /* Clamping to allow for rounding errors above */
2768 	  if (red > 255.0)
2769 	    {
2770 	      red = 255.0;
2771 	    }
2772 	  if (green > 255.0)
2773 	    {
2774 	      green = 255.0;
2775 	    }
2776 	  if (blue > 255.0)
2777 	    {
2778 	      blue = 255.0;
2779 	    }
2780 	  if (alpha > gdAlphaMax)
2781 	    {
2782 	      alpha = gdAlphaMax;
2783 	    }
2784 	  gdImageSetPixel (dst,
2785 			   x, y,
2786 			   gdTrueColorAlpha ((int) red,
2787 					     (int) green,
2788 					     (int) blue, (int) alpha));
2789 	}
2790     }
2791 }
2792 
gdImageCreateFromXbm(FILE * fd)2793 BGD_DECLARE(gdImagePtr) gdImageCreateFromXbm (FILE * fd)
2794 {
2795   gdImagePtr im;
2796   int bit;
2797   int w, h;
2798   int bytes;
2799   int ch;
2800   int i, x, y;
2801   char *sp;
2802   char s[161];
2803   if (!fgets (s, 160, fd))
2804     {
2805       return 0;
2806     }
2807   sp = &s[0];
2808   /* Skip #define */
2809   sp = strchr (sp, ' ');
2810   if (!sp)
2811     {
2812       return 0;
2813     }
2814   /* Skip width label */
2815   sp++;
2816   sp = strchr (sp, ' ');
2817   if (!sp)
2818     {
2819       return 0;
2820     }
2821   /* Get width */
2822   w = atoi (sp + 1);
2823   if (!w)
2824     {
2825       return 0;
2826     }
2827   if (!fgets (s, 160, fd))
2828     {
2829       return 0;
2830     }
2831   sp = s;
2832   /* Skip #define */
2833   sp = strchr (sp, ' ');
2834   if (!sp)
2835     {
2836       return 0;
2837     }
2838   /* Skip height label */
2839   sp++;
2840   sp = strchr (sp, ' ');
2841   if (!sp)
2842     {
2843       return 0;
2844     }
2845   /* Get height */
2846   h = atoi (sp + 1);
2847   if (!h)
2848     {
2849       return 0;
2850     }
2851   /* Skip declaration line */
2852   if (!fgets (s, 160, fd))
2853     {
2854       return 0;
2855     }
2856   bytes = (w * h / 8) + 1;
2857   im = gdImageCreate (w, h);
2858   if (!im) {
2859     return 0;
2860   }
2861 
2862   gdImageColorAllocate (im, 255, 255, 255);
2863   gdImageColorAllocate (im, 0, 0, 0);
2864   x = 0;
2865   y = 0;
2866   for (i = 0; (i < bytes); i++)
2867     {
2868       char h[3];
2869       unsigned int b;
2870       /* Skip spaces, commas, CRs, 0x */
2871       while (1)
2872 	{
2873 	  ch = getc (fd);
2874 	  if (ch == EOF)
2875 	    {
2876 	      goto fail;
2877 	    }
2878 	  if (ch == 'x')
2879 	    {
2880 	      break;
2881 	    }
2882 	}
2883       /* Get hex value */
2884       ch = getc (fd);
2885       if (ch == EOF)
2886 	{
2887 	  goto fail;
2888 	}
2889       h[0] = ch;
2890       ch = getc (fd);
2891       if (ch == EOF)
2892 	{
2893 	  goto fail;
2894 	}
2895       h[1] = ch;
2896       h[2] = '\0';
2897       sscanf (h, "%x", &b);
2898       for (bit = 1; (bit <= 128); (bit = bit << 1))
2899 	{
2900 	  gdImageSetPixel (im, x++, y, (b & bit) ? 1 : 0);
2901 	  if (x == im->sx)
2902 	    {
2903 	      x = 0;
2904 	      y++;
2905 	      if (y == im->sy)
2906 		{
2907 		  return im;
2908 		}
2909 	      /* Fix 8/8/95 */
2910 	      break;
2911 	    }
2912 	}
2913     }
2914   /* Shouldn't happen */
2915   fprintf (stderr, "Error: bug in gdImageCreateFromXbm!\n");
2916   return 0;
2917 fail:
2918   gdImageDestroy (im);
2919   return 0;
2920 }
2921 
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)2922 BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2923 {
2924   if (!n)
2925     {
2926       return;
2927     }
2928 
2929 
2930   gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
2931   gdImageOpenPolygon (im, p, n, c);
2932 }
2933 
gdImageOpenPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2934 BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2935 {
2936   int i;
2937   int lx, ly;
2938   if (!n)
2939     {
2940       return;
2941     }
2942 
2943 
2944   lx = p->x;
2945   ly = p->y;
2946   for (i = 1; (i < n); i++)
2947     {
2948       p++;
2949       gdImageLine (im, lx, ly, p->x, p->y, c);
2950       lx = p->x;
2951       ly = p->y;
2952     }
2953 
2954 }
2955 
2956 /* THANKS to Kirsten Schulz for the polygon fixes! */
2957 
2958 /* The intersection finding technique of this code could be improved  */
2959 /* by remembering the previous intertersection, and by using the slope. */
2960 /* That could help to adjust intersections  to produce a nice */
2961 /* interior_extrema. */
2962 
2963 #if 0
2964 static void horizontalLine(gdImagePtr im, int minx, int maxx, int y,
2965 	int fill_color);
2966 #endif
2967 
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2968 BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2969 {
2970   int i;
2971   int j;
2972   int index;
2973   int y;
2974   int miny, maxy;
2975   int x1, y1;
2976   int x2, y2;
2977   int ind1, ind2;
2978   int ints;
2979   int fill_color;
2980   if (!n)
2981     {
2982       return;
2983     }
2984 
2985 
2986   if (!im->polyAllocated)
2987     {
2988       if (overflow2(sizeof (int), n)) {
2989         return;
2990       }
2991       im->polyInts = (int *) gdMalloc (sizeof (int) * n);
2992 			if (!im->polyInts) {
2993 				return;
2994 			}
2995       im->polyAllocated = n;
2996     }
2997   if (im->polyAllocated < n)
2998     {
2999       while (im->polyAllocated < n)
3000 	{
3001 	  im->polyAllocated *= 2;
3002 	}
3003       if (overflow2(sizeof (int), im->polyAllocated)) {
3004         return;
3005       }
3006       im->polyInts = (int *) gdRealloc (im->polyInts,
3007 					sizeof (int) * im->polyAllocated);
3008 			if (!im->polyInts) {
3009 				return;
3010 			}
3011     }
3012   miny = p[0].y;
3013   maxy = p[0].y;
3014   for (i = 1; (i < n); i++)
3015     {
3016       if (p[i].y < miny)
3017 	{
3018 	  miny = p[i].y;
3019 	}
3020       if (p[i].y > maxy)
3021 	{
3022 	  maxy = p[i].y;
3023 	}
3024     }
3025   /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
3026   /* 2.0.26: clipping rectangle is even better */
3027   if (miny < im->cy1)
3028     {
3029       miny = im->cy1;
3030     }
3031   if (maxy > im->cy2)
3032     {
3033       maxy = im->cy2;
3034     }
3035   /* Fix in 1.3: count a vertex only once */
3036   for (y = miny; (y <= maxy); y++)
3037     {
3038 /*1.4           int interLast = 0; */
3039 /*              int dirLast = 0; */
3040 /*              int interFirst = 1; */
3041 /* 2.0.26+      int yshift = 0; */
3042       if (c == gdAntiAliased) {
3043         fill_color = im->AA_color;
3044       } else {
3045         fill_color = c;
3046       }
3047       ints = 0;
3048       for (i = 0; (i < n); i++)
3049 	{
3050 	  if (!i)
3051 	    {
3052 	      ind1 = n - 1;
3053 	      ind2 = 0;
3054 	    }
3055 	  else
3056 	    {
3057 	      ind1 = i - 1;
3058 	      ind2 = i;
3059 	    }
3060 	  y1 = p[ind1].y;
3061 	  y2 = p[ind2].y;
3062 	  if (y1 < y2)
3063 	    {
3064 	      x1 = p[ind1].x;
3065 	      x2 = p[ind2].x;
3066 	    }
3067 	  else if (y1 > y2)
3068 	    {
3069 	      y2 = p[ind1].y;
3070 	      y1 = p[ind2].y;
3071 	      x2 = p[ind1].x;
3072 	      x1 = p[ind2].x;
3073 	    }
3074 	  else
3075 	    {
3076 	      continue;
3077 	    }
3078 
3079 	  /* Do the following math as float intermediately, and round to ensure
3080 	   * that Polygon and FilledPolygon for the same set of points have the
3081 	   * same footprint. */
3082 
3083 	  if ((y >= y1) && (y < y2))
3084 	    {
3085 	      im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) /
3086 		(float) (y2 - y1) + 0.5 + x1);
3087 	    }
3088 	  else if ((y == maxy) && (y > y1) && (y <= y2))
3089 	    {
3090 	      im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) /
3091 		(float) (y2 - y1) + 0.5 + x1);
3092 	    }
3093 	}
3094       /*
3095         2.0.26: polygons pretty much always have less than 100 points,
3096         and most of the time they have considerably less. For such trivial
3097         cases, insertion sort is a good choice. Also a good choice for
3098         future implementations that may wish to indirect through a table.
3099       */
3100       for (i = 1; (i < ints); i++) {
3101         index = im->polyInts[i];
3102         j = i;
3103         while ((j > 0) && (im->polyInts[j - 1] > index)) {
3104           im->polyInts[j] = im->polyInts[j - 1];
3105           j--;
3106         }
3107         im->polyInts[j] = index;
3108       }
3109       for (i = 0; (i < (ints)); i += 2)
3110 	{
3111 #if 0
3112           int minx = im->polyInts[i];
3113           int maxx = im->polyInts[i + 1];
3114 #endif
3115           /* 2.0.29: back to gdImageLine to prevent segfaults when
3116             performing a pattern fill */
3117           gdImageLine (im, im->polyInts[i], y, im->polyInts[i + 1], y,
3118             fill_color);
3119 	}
3120     }
3121   /* If we are drawing this AA, then redraw the border with AA lines. */
3122   /* This doesn't work as well as I'd like, but it doesn't clash either. */
3123   if (c == gdAntiAliased) {
3124     gdImagePolygon (im, p, n, c);
3125   }
3126 }
3127 
3128 #if 0
3129 static void horizontalLine(gdImagePtr im, int minx, int maxx, int y,
3130 	int fill_color)
3131 {
3132   /* 2.0.27: potential corruption fixed by John Ellson */
3133   if (minx < im->cx1) minx = im->cx1;
3134   if (maxx < minx) maxx = minx;
3135   if (maxx > im->cx2) maxx = im->cx2;
3136   if (minx > maxx) minx = maxx;
3137 
3138   if (y < im->cy1) y = im->cy1;
3139   if (y > im->cy2) y = im->cy2;
3140 
3141   if (im->trueColor) {
3142     while (minx <= maxx) {
3143       im->tpixels[y][minx++] = fill_color;
3144     }
3145   } else {
3146     while (minx <= maxx) {
3147       im->pixels[y][minx++] = fill_color;
3148     }
3149   }
3150 }
3151 #endif
3152 
3153 static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t);
3154 
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)3155 BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
3156 {
3157   if (im->style)
3158     {
3159       gdFree (im->style);
3160     }
3161   if (overflow2(sizeof (int), noOfPixels)) {
3162     return;
3163   }
3164   im->style = (int *) gdMalloc (sizeof (int) * noOfPixels);
3165 	if (!im->style) {
3166 		return;
3167 	}
3168   memcpy (im->style, style, sizeof (int) * noOfPixels);
3169   im->styleLength = noOfPixels;
3170   im->stylePos = 0;
3171 }
3172 
gdImageSetThickness(gdImagePtr im,int thickness)3173 BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness)
3174 {
3175   im->thick = thickness;
3176 }
3177 
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)3178 BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
3179 {
3180   int i;
3181   im->brush = brush;
3182   if ((!im->trueColor) && (!im->brush->trueColor))
3183     {
3184       for (i = 0; (i < gdImageColorsTotal (brush)); i++)
3185 	{
3186 	  int index;
3187 	  index = gdImageColorResolveAlpha (im,
3188 					    gdImageRed (brush, i),
3189 					    gdImageGreen (brush, i),
3190 					    gdImageBlue (brush, i),
3191 					    gdImageAlpha (brush, i));
3192 	  im->brushColorMap[i] = index;
3193 	}
3194     }
3195 }
3196 
gdImageSetTile(gdImagePtr im,gdImagePtr tile)3197 BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile)
3198 {
3199   int i;
3200   im->tile = tile;
3201   if ((!im->trueColor) && (!im->tile->trueColor))
3202     {
3203       for (i = 0; (i < gdImageColorsTotal (tile)); i++)
3204 	{
3205 	  int index;
3206 	  index = gdImageColorResolveAlpha (im,
3207 					    gdImageRed (tile, i),
3208 					    gdImageGreen (tile, i),
3209 					    gdImageBlue (tile, i),
3210 					    gdImageAlpha (tile, i));
3211 	  im->tileColorMap[i] = index;
3212 	}
3213     }
3214 }
3215 
gdImageSetAntiAliased(gdImagePtr im,int c)3216 BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c)
3217 {
3218   im->AA = 1;
3219   im->AA_color = c;
3220   im->AA_dont_blend = -1;
3221 }
3222 
gdImageSetAntiAliasedDontBlend(gdImagePtr im,int c,int dont_blend)3223 BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
3224 {
3225   im->AA = 1;
3226   im->AA_color = c;
3227   im->AA_dont_blend = dont_blend;
3228 }
3229 
gdImageInterlace(gdImagePtr im,int interlaceArg)3230 BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg)
3231 {
3232   im->interlace = interlaceArg;
3233 }
3234 
gdImageCompare(gdImagePtr im1,gdImagePtr im2)3235 BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2)
3236 {
3237   int x, y;
3238   int p1, p2;
3239   int cmpStatus = 0;
3240   int sx, sy;
3241 
3242   if (im1->interlace != im2->interlace)
3243     {
3244       cmpStatus |= GD_CMP_INTERLACE;
3245     }
3246 
3247   if (im1->transparent != im2->transparent)
3248     {
3249       cmpStatus |= GD_CMP_TRANSPARENT;
3250     }
3251 
3252   if (im1->trueColor != im2->trueColor)
3253     {
3254       cmpStatus |= GD_CMP_TRUECOLOR;
3255     }
3256 
3257   sx = im1->sx;
3258   if (im1->sx != im2->sx)
3259     {
3260       cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
3261       if (im2->sx < im1->sx)
3262 	{
3263 	  sx = im2->sx;
3264 	}
3265     }
3266 
3267   sy = im1->sy;
3268   if (im1->sy != im2->sy)
3269     {
3270       cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
3271       if (im2->sy < im1->sy)
3272 	{
3273 	  sy = im2->sy;
3274 	}
3275     }
3276 
3277   if (im1->colorsTotal != im2->colorsTotal)
3278     {
3279       cmpStatus |= GD_CMP_NUM_COLORS;
3280     }
3281 
3282   for (y = 0; (y < sy); y++)
3283     {
3284       for (x = 0; (x < sx); x++)
3285 	{
3286 	  p1 =
3287 	    im1->trueColor ? gdImageTrueColorPixel (im1, x,
3288 						    y) :
3289 	    gdImagePalettePixel (im1, x, y);
3290 	  p2 =
3291 	    im2->trueColor ? gdImageTrueColorPixel (im2, x,
3292 						    y) :
3293 	    gdImagePalettePixel (im2, x, y);
3294 	  if (gdImageRed (im1, p1) != gdImageRed (im2, p2))
3295 	    {
3296 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
3297 	      break;
3298 	    }
3299 	  if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2))
3300 	    {
3301 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
3302 	      break;
3303 	    }
3304 	  if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2))
3305 	    {
3306 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
3307 	      break;
3308 	    }
3309 #if 0
3310 	  /* Soon we'll add alpha channel to palettes */
3311 	  if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2))
3312 	    {
3313 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
3314 	      break;
3315 	    }
3316 #endif
3317 	}
3318       if (cmpStatus & GD_CMP_COLOR)
3319 	{
3320 	  break;
3321 	};
3322     }
3323 
3324   return cmpStatus;
3325 }
3326 
3327 
3328 /* Thanks to Frank Warmerdam for this superior implementation
3329 	of gdAlphaBlend(), which merges alpha in the
3330 	destination color much better. */
3331 
gdAlphaBlend(int dst,int src)3332 BGD_DECLARE(int) gdAlphaBlend (int dst, int src)
3333 {
3334     int src_alpha = gdTrueColorGetAlpha(src);
3335     int dst_alpha, alpha, red, green, blue;
3336     int src_weight, dst_weight, tot_weight;
3337 
3338 /* -------------------------------------------------------------------- */
3339 /*      Simple cases we want to handle fast.                            */
3340 /* -------------------------------------------------------------------- */
3341     if( src_alpha == gdAlphaOpaque )
3342         return src;
3343 
3344     dst_alpha = gdTrueColorGetAlpha(dst);
3345     if( src_alpha == gdAlphaTransparent )
3346         return dst;
3347     if( dst_alpha == gdAlphaTransparent )
3348         return src;
3349 
3350 /* -------------------------------------------------------------------- */
3351 /*      What will the source and destination alphas be?  Note that      */
3352 /*      the destination weighting is substantially reduced as the       */
3353 /*      overlay becomes quite opaque.                                   */
3354 /* -------------------------------------------------------------------- */
3355     src_weight = gdAlphaTransparent - src_alpha;
3356     dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
3357     tot_weight = src_weight + dst_weight;
3358 
3359 /* -------------------------------------------------------------------- */
3360 /*      What red, green and blue result values will we use?             */
3361 /* -------------------------------------------------------------------- */
3362     alpha = src_alpha * dst_alpha / gdAlphaMax;
3363 
3364     red = (gdTrueColorGetRed(src) * src_weight
3365            + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
3366     green = (gdTrueColorGetGreen(src) * src_weight
3367            + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
3368     blue = (gdTrueColorGetBlue(src) * src_weight
3369            + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
3370 
3371 /* -------------------------------------------------------------------- */
3372 /*      Return merged result.                                           */
3373 /* -------------------------------------------------------------------- */
3374     return ((alpha << 24) + (red << 16) + (green << 8) + blue);
3375 }
3376 
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)3377 BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
3378 {
3379   im->alphaBlendingFlag = alphaBlendingArg;
3380 }
3381 
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)3382 BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
3383 {
3384   im->saveAlphaFlag = saveAlphaArg;
3385 }
3386 
gdImageSetClip(gdImagePtr im,int x1,int y1,int x2,int y2)3387 BGD_DECLARE(void) gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
3388 {
3389   if (x1 < 0)
3390     {
3391       x1 = 0;
3392     }
3393   if (x1 >= im->sx)
3394     {
3395       x1 = im->sx - 1;
3396     }
3397   if (x2 < 0)
3398     {
3399       x2 = 0;
3400     }
3401   if (x2 >= im->sx)
3402     {
3403       x2 = im->sx - 1;
3404     }
3405   if (y1 < 0)
3406     {
3407       y1 = 0;
3408     }
3409   if (y1 >= im->sy)
3410     {
3411       y1 = im->sy - 1;
3412     }
3413   if (y2 < 0)
3414     {
3415       y2 = 0;
3416     }
3417   if (y2 >= im->sy)
3418     {
3419       y2 = im->sy - 1;
3420     }
3421   im->cx1 = x1;
3422   im->cy1 = y1;
3423   im->cx2 = x2;
3424   im->cy2 = y2;
3425 }
3426 
gdImageGetClip(gdImagePtr im,int * x1P,int * y1P,int * x2P,int * y2P)3427 BGD_DECLARE(void) gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
3428 {
3429   *x1P = im->cx1;
3430   *y1P = im->cy1;
3431   *x2P = im->cx2;
3432   *y2P = im->cy2;
3433 }
3434 
3435 /*
3436  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
3437  * */
3438 #define BLEND_COLOR(a, nc, c, cc) \
3439 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
3440 
gdImageSetAAPixelColor(gdImagePtr im,int x,int y,int color,int t)3441 static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
3442 {
3443 	int dr,dg,db,p,r,g,b;
3444 
3445 	/* 2.0.34: watch out for out of range calls */
3446 	if (!gdImageBoundsSafeMacro(im, x, y)) {
3447 		return;
3448 	}
3449 	p = gdImageGetPixel(im,x,y);
3450         /* TBB: we have to implement the dont_blend stuff to provide
3451           the full feature set of the old implementation */
3452         if ((p == color)
3453 	  || ((p == im->AA_dont_blend)
3454 	      && (t != 0x00)))
3455         {
3456           return;
3457         }
3458 	dr = gdTrueColorGetRed(color);
3459 	dg = gdTrueColorGetGreen(color);
3460 	db = gdTrueColorGetBlue(color);
3461 
3462 	r = gdTrueColorGetRed(p);
3463 	g = gdTrueColorGetGreen(p);
3464 	b = gdTrueColorGetBlue(p);
3465 
3466 	BLEND_COLOR(t, dr, r, dr);
3467 	BLEND_COLOR(t, dg, g, dg);
3468 	BLEND_COLOR(t, db, b, db);
3469 	im->tpixels[y][x] = gdTrueColorAlpha(dr, dg, db,  gdAlphaOpaque);
3470 }
3471 
gdImageAALine(gdImagePtr im,int x1,int y1,int x2,int y2,int col)3472 static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
3473 {
3474 	/* keep them as 32bits */
3475 	long x, y, inc;
3476 	long dx, dy,tmp;
3477 
3478 	if (!im->trueColor) {
3479 		/* TBB: don't crash when the image is of the wrong type */
3480 		gdImageLine(im, x1, y1, x2, y2, col);
3481 		return;
3482 	}
3483         /* TBB: use the clipping rectangle */
3484         if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
3485           return;
3486         if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
3487           return;
3488 	dx = x2 - x1;
3489 	dy = y2 - y1;
3490 
3491 	/* Axis aligned lines */
3492 	if (dx == 0) {
3493 		gdImageVLine(im, x1, y1, y2, col);
3494 		return;
3495 	} else if (dy == 0) {
3496 		gdImageHLine(im, y1, x1, x2, col);
3497 		return;
3498 	}
3499 
3500 	if (dx == 0 && dy == 0) {
3501 		/* TBB: allow setting points */
3502 		gdImageSetAAPixelColor(im, x1, y1, col, 0xFF);
3503 		return;
3504 	}
3505 	if (abs(dx) > abs(dy)) {
3506 		if (dx < 0) {
3507 			tmp = x1;
3508 			x1 = x2;
3509 			x2 = tmp;
3510 			tmp = y1;
3511 			y1 = y2;
3512 			y2 = tmp;
3513 			dx = x2 - x1;
3514 			dy = y2 - y1;
3515 		}
3516 		x = x1 << 16;
3517 		y = y1 << 16;
3518 		inc = (dy * 65536) / dx;
3519 		/* TBB: set the last pixel for consistency (<=) */
3520 		while ((x >> 16) <= x2) {
3521 			gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (y >> 8) & 0xFF);
3522 			gdImageSetAAPixelColor(im, x >> 16, (y >> 16) + 1,col, (~y >> 8) & 0xFF);
3523 			x += (1 << 16);
3524 			y += inc;
3525 		}
3526 	} else {
3527 		if (dy < 0) {
3528 			tmp = x1;
3529 			x1 = x2;
3530 			x2 = tmp;
3531 			tmp = y1;
3532 			y1 = y2;
3533 			y2 = tmp;
3534 			dx = x2 - x1;
3535 			dy = y2 - y1;
3536 		}
3537 		x = x1 << 16;
3538 		y = y1 << 16;
3539 		inc = (dx * 65536) / dy;
3540 		/* TBB: set the last pixel for consistency (<=) */
3541 		while ((y>>16) <= y2) {
3542 			gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (x >> 8) & 0xFF);
3543 			gdImageSetAAPixelColor(im, (x >> 16) + 1, (y >> 16),col, (~x >> 8) & 0xFF);
3544 			x += inc;
3545 			y += (1<<16);
3546 		}
3547 	}
3548 }
3549