1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <zlib.h>
6 #include "gd.h"
7 #include "gdhelpers.h"
8 
9 #ifdef _OSD_POSIX		/* BS2000 uses the EBCDIC char set instead of ASCII */
10 #define CHARSET_EBCDIC
11 #define __attribute__(any)	/*nothing */
12 #endif
13 /*_OSD_POSIX*/
14 
15 #ifndef CHARSET_EBCDIC
16 #define ASC(ch)  ch
17 #else /*CHARSET_EBCDIC */
18 #define ASC(ch) gd_toascii[(unsigned char)ch]
19 static const unsigned char gd_toascii[256] =
20 {
21 /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
22   0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,	/*................ */
23 /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
24   0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f,	/*................ */
25 /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
26   0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,	/*................ */
27 /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
28   0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,	/*................ */
29 /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
30   0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,	/* .........`.<(+| */
31 /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
32   0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f,	/*&.........!$*);. */
33 /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
34   0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
35 /*-/........^,%_>?*/
36 /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
37   0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,	/*..........:#@'=" */
38 /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
39   0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1,	/*.abcdefghi...... */
40 /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
41   0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4,	/*.jklmnopqr...... */
42 /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
43   0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae,	/*..stuvwxyz...... */
44 /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
45   0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7,	/*...........[\].. */
46 /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
47   0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5,	/*.ABCDEFGHI...... */
48 /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
49   0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff,	/*.JKLMNOPQR...... */
50 /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
51   0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5,	/*..STUVWXYZ...... */
52 /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
53   0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e	/*0123456789.{.}.~ */
54 };
55 #endif /*CHARSET_EBCDIC */
56 
57 extern int gdCosT[];
58 extern int gdSinT[];
59 
60 static void gdImageBrushApply (gdImagePtr im, int x, int y);
61 static void gdImageTileApply (gdImagePtr im, int x, int y);
62 
63 gdImagePtr
gdImageCreate(int sx,int sy)64 gdImageCreate (int sx, int sy)
65 {
66   int i;
67   gdImagePtr im;
68 
69   if (overflow2(sx, sy)) {
70     return NULL;
71   }
72 
73   if (overflow2(sizeof (unsigned char *), sy)) {
74     return NULL;
75   }
76   if (overflow2(sizeof (unsigned char), sx)) {
77     return NULL;
78   }
79 
80   im = (gdImage *) gdMalloc (sizeof (gdImage));
81   memset (im, 0, sizeof (gdImage));
82   /* Row-major ever since gd 1.3 */
83   im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy);
84   im->polyInts = 0;
85   im->polyAllocated = 0;
86   im->brush = 0;
87   im->tile = 0;
88   im->style = 0;
89   for (i = 0; (i < sy); i++)
90     {
91       /* Row-major ever since gd 1.3 */
92       im->pixels[i] = (unsigned char *) gdCalloc (
93 						sx, sizeof (unsigned char));
94     }
95   im->sx = sx;
96   im->sy = sy;
97   im->colorsTotal = 0;
98   im->transparent = (-1);
99   im->interlace = 0;
100   im->thick = 1;
101   for (i = 0; (i < gdMaxColors); i++)
102     {
103       im->open[i] = 1;
104       im->red[i] = 0;
105       im->green[i] = 0;
106       im->blue[i] = 0;
107     };
108   im->trueColor = 0;
109   im->tpixels = 0;
110   im->clip = 0;
111   return im;
112 }
113 
114 gdImagePtr
gdImageCreateTrueColor(int sx,int sy)115 gdImageCreateTrueColor (int sx, int sy)
116 {
117   int i;
118   gdImagePtr im;
119   unsigned long cpa_size;
120 
121   if (overflow2(sx, sy)) {
122     return NULL;
123   }
124 
125   if (overflow2(sizeof (int *), sy)) {
126     return NULL;
127   }
128 
129   if (overflow2(sizeof(int), sx)) {
130     return NULL;
131   }
132 
133   im = (gdImage *) gdMalloc (sizeof (gdImage));
134   if (im == 0) return 0;
135   memset (im, 0, sizeof (gdImage));
136 
137   cpa_size = sizeof (int) * (unsigned long) sx * (unsigned long) sy;
138   im->_tpixels = (int *) gdMalloc (cpa_size);
139   if (im->_tpixels == 0)
140     {
141       gdFree (im);
142       return 0;
143     }
144   memset (im->_tpixels, 0, cpa_size);
145 
146   im->tpixels = (int **) gdMalloc (sizeof (int *) * sy);
147   if (im->tpixels == 0)
148     {
149       gdFree (im->_tpixels);
150       gdFree (im);
151       return 0;
152     }
153   for (i = 0; i < sy; i++) im->tpixels[i] = im->_tpixels + (i * sx);
154 
155   im->polyInts = 0;
156   im->polyAllocated = 0;
157   im->brush = 0;
158   im->tile = 0;
159   im->style = 0;
160   im->sx = sx;
161   im->sy = sy;
162   im->transparent = (-1);
163   im->interlace = 0;
164   im->trueColor = 1;
165   im->saveAlphaFlag = 1;
166   im->alphaBlendingFlag = 0;
167   im->thick = 1;
168   im->clip = 0;
169   return im;
170 }
171 
172 void
gdImageDestroy(gdImagePtr im)173 gdImageDestroy (gdImagePtr im)
174 {
175   int i;
176   if (im->pixels)
177     {
178       for (i = 0; (i < im->sy); i++)
179 	{
180 	  gdFree (im->pixels[i]);
181 	}
182       gdFree (im->pixels);
183     }
184   if (im->tpixels)
185     {
186       gdFree (im->_tpixels);
187       gdFree (im->tpixels);
188     }
189   if (im->polyInts)
190     {
191       gdFree (im->polyInts);
192     }
193   if (im->style)
194     {
195       gdFree (im->style);
196     }
197   if (im->clip)
198     {
199       gdClipSetFree (im);
200     }
201   gdFree (im);
202 }
203 
204 int
gdImageColorClosest(gdImagePtr im,int r,int g,int b)205 gdImageColorClosest (gdImagePtr im, int r, int g, int b)
206 {
207   return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
208 }
209 
210 int
gdImageColorClosestAlpha(gdImagePtr im,int r,int g,int b,int a)211 gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
212 {
213   int i;
214   long rd, gd, bd, ad;
215   int ct = (-1);
216   int first = 1;
217   long mindist = 0;
218   if (im->trueColor)
219     {
220       return gdTrueColorAlpha (r, g, b, a);
221     }
222   for (i = 0; (i < (im->colorsTotal)); i++)
223     {
224       long dist;
225       if (im->open[i])
226 	{
227 	  continue;
228 	}
229       rd = (im->red[i] - r);
230       gd = (im->green[i] - g);
231       bd = (im->blue[i] - b);
232       ad = (im->blue[i] - b);
233       dist = rd * rd + gd * gd + bd * bd + ad * ad;
234       if (first || (dist < mindist))
235 	{
236 	  mindist = dist;
237 	  ct = i;
238 	  first = 0;
239 	}
240     }
241   return ct;
242 }
243 
244 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
245  * on colour conversion to/from RBG and HWB colour systems.
246  * It has been modified to return the converted value as a * parameter.
247  */
248 
249 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
250 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
251 #define HWB_UNDEFINED -1
252 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;}
253 
254 #define MIN(a,b) ((a)<(b)?(a):(b))
255 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
256 #define MAX(a,b) ((a)<(b)?(b):(a))
257 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
258 
259 
260 /*
261  * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
262  * red always maps to 6 in this implementation. Therefore UNDEFINED can be
263  * defined as 0 in situations where only unsigned numbers are desired.
264  */
265 typedef struct
266 {
267   float R, G, B;
268 }
269 RGBType;
270 typedef struct
271   {
272     float H, W, B;
273   }
274 HWBType;
275 
276 #if 0
277 static HWBType *
278 RGB_to_HWB (RGBType RGB, HWBType * HWB)
279 {
280 
281   /*
282    * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
283    * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
284    */
285 
286   float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
287   int i;
288 
289   w = MIN3 (R, G, B);
290   v = MAX3 (R, G, B);
291   b = 1 - v;
292   if (v == w)
293     RETURN_HWB (HWB_UNDEFINED, w, b);
294   f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
295   i = (R == w) ? 3 : ((G == w) ? 5 : 1);
296   RETURN_HWB (i - f / (v - w), w, b);
297 
298 }
299 
300 static float
301 HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
302 {
303   RGBType RGB1, RGB2;
304   HWBType HWB1, HWB2;
305   float diff;
306 
307   SETUP_RGB (RGB1, r1, g1, b1);
308   SETUP_RGB (RGB2, r2, g2, b2);
309 
310   RGB_to_HWB (RGB1, &HWB1);
311   RGB_to_HWB (RGB2, &HWB2);
312 
313   /*
314    * I made this bit up; it seems to produce OK results, and it is certainly
315    * more visually correct than the current RGB metric. (PJW)
316    */
317 
318   if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED))
319     {
320       diff = 0;			/* Undefined hues always match... */
321     }
322   else
323     {
324       diff = abs (HWB1.H - HWB2.H);
325       if (diff > 3)
326 	{
327 	  diff = 6 - diff;	/* Remember, it's a colour circle */
328 	}
329     }
330 
331   diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
332 
333   return diff;
334 }
335 
336 /*
337  * This is not actually used, but is here for completeness, in case someone wants to
338  * use the HWB stuff for anything else...
339  */
340 static RGBType *
341 HWB_to_RGB (HWBType HWB, RGBType * RGB)
342 {
343 
344   /*
345    * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
346    * RGB are each returned on [0, 1].
347    */
348 
349   float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
350   int i;
351 
352   v = 1 - b;
353   if (h == HWB_UNDEFINED)
354     RETURN_RGB (v, v, v);
355   i = floor (h);
356   f = h - i;
357   if (i & 1)
358     f = 1 - f;			/* if i is odd */
359   n = w + f * (v - w);		/* linear interpolation between w and v */
360   switch (i)
361     {
362     case 6:
363     case 0:
364       RETURN_RGB (v, n, w);
365     case 1:
366       RETURN_RGB (n, v, w);
367     case 2:
368       RETURN_RGB (w, v, n);
369     case 3:
370       RETURN_RGB (w, n, v);
371     case 4:
372       RETURN_RGB (n, w, v);
373     case 5:
374       RETURN_RGB (v, w, n);
375     }
376 
377   return RGB;
378 
379 }
380 #endif
381 
382 #if 0
383 int
384 gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
385 {
386   int i;
387   /* long rd, gd, bd; */
388   int ct = (-1);
389   int first = 1;
390   float mindist = 0;
391   if (im->trueColor)
392     {
393       return gdTrueColor (r, g, b);
394     }
395   for (i = 0; (i < (im->colorsTotal)); i++)
396     {
397       float dist;
398       if (im->open[i])
399 	{
400 	  continue;
401 	}
402       dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b);
403       if (first || (dist < mindist))
404 	{
405 	  mindist = dist;
406 	  ct = i;
407 	  first = 0;
408 	}
409     }
410   return ct;
411 }
412 #endif
413 
414 int
gdImageColorExact(gdImagePtr im,int r,int g,int b)415 gdImageColorExact (gdImagePtr im, int r, int g, int b)
416 {
417   return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
418 }
419 
420 int
gdImageColorExactAlpha(gdImagePtr im,int r,int g,int b,int a)421 gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
422 {
423   int i;
424   if (im->trueColor)
425     {
426       return gdTrueColorAlpha (r, g, b, a);
427     }
428   for (i = 0; (i < (im->colorsTotal)); i++)
429     {
430       if (im->open[i])
431 	{
432 	  continue;
433 	}
434       if ((im->red[i] == r) &&
435 	  (im->green[i] == g) &&
436 	  (im->blue[i] == b) &&
437 	  (im->alpha[i] == a))
438 	{
439 	  return i;
440 	}
441     }
442   return -1;
443 }
444 
445 int
gdImageColorAllocate(gdImagePtr im,int r,int g,int b)446 gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
447 {
448   return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
449 }
450 
451 int
gdImageColorAllocateAlpha(gdImagePtr im,int r,int g,int b,int a)452 gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
453 {
454   int i;
455   int ct = (-1);
456   if (im->trueColor)
457     {
458       return gdTrueColorAlpha (r, g, b, a);
459     }
460   for (i = 0; (i < (im->colorsTotal)); i++)
461     {
462       if (im->open[i])
463 	{
464 	  ct = i;
465 	  break;
466 	}
467     }
468   if (ct == (-1))
469     {
470       ct = im->colorsTotal;
471       if (ct == gdMaxColors)
472 	{
473 	  return -1;
474 	}
475       im->colorsTotal++;
476     }
477   im->red[ct] = r;
478   im->green[ct] = g;
479   im->blue[ct] = b;
480   im->alpha[ct] = a;
481   im->open[ct] = 0;
482   return ct;
483 }
484 
485 /*
486  * gdImageColorResolve is an alternative for the code fragment:
487  *
488  *      if ((color=gdImageColorExact(im,R,G,B)) < 0)
489  *        if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
490  *          color=gdImageColorClosest(im,R,G,B);
491  *
492  * in a single function.    Its advantage is that it is guaranteed to
493  * return a color index in one search over the color table.
494  */
495 
496 int
gdImageColorResolve(gdImagePtr im,int r,int g,int b)497 gdImageColorResolve (gdImagePtr im, int r, int g, int b)
498 {
499   return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);
500 }
501 
502 int
gdImageColorResolveAlpha(gdImagePtr im,int r,int g,int b,int a)503 gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
504 {
505   int c;
506   int ct = -1;
507   int op = -1;
508   long rd, gd, bd, ad, dist;
509   long mindist = 4 * 255 * 255;	/* init to max poss dist */
510   if (im->trueColor)
511     {
512       return gdTrueColorAlpha (r, g, b, a);
513     }
514 
515   for (c = 0; c < im->colorsTotal; c++)
516     {
517       if (im->open[c])
518 	{
519 	  op = c;		/* Save open slot */
520 	  continue;		/* Color not in use */
521 	}
522       rd = (long) (im->red[c] - r);
523       gd = (long) (im->green[c] - g);
524       bd = (long) (im->blue[c] - b);
525       ad = (long) (im->alpha[c] - a);
526       dist = rd * rd + gd * gd + bd * bd + ad * ad;
527       if (dist < mindist)
528 	{
529 	  if (dist == 0)
530 	    {
531 	      return c;		/* Return exact match color */
532 	    }
533 	  mindist = dist;
534 	  ct = c;
535 	}
536     }
537   /* no exact match.  We now know closest, but first try to allocate exact */
538   if (op == -1)
539     {
540       op = im->colorsTotal;
541       if (op == gdMaxColors)
542 	{			/* No room for more colors */
543 	  return ct;		/* Return closest available color */
544 	}
545       im->colorsTotal++;
546     }
547   im->red[op] = r;
548   im->green[op] = g;
549   im->blue[op] = b;
550   im->alpha[op] = a;
551   im->open[op] = 0;
552   return op;			/* Return newly allocated color */
553 }
554 
555 void
gdImageColorDeallocate(gdImagePtr im,int color)556 gdImageColorDeallocate (gdImagePtr im, int color)
557 {
558   if (im->trueColor)
559     {
560       return;
561     }
562   /* Mark it open. */
563   im->open[color] = 1;
564 }
565 
566 void
gdImageColorTransparent(gdImagePtr im,int color)567 gdImageColorTransparent (gdImagePtr im, int color)
568 {
569   if (!im->trueColor)
570     {
571       if (im->transparent != -1)
572 	{
573 	  im->alpha[im->transparent] = gdAlphaOpaque;
574 	}
575       if (color != -1)
576 	{
577 	  im->alpha[color] = gdAlphaTransparent;
578 	}
579     }
580   im->transparent = color;
581 }
582 
583 void
gdImagePaletteCopy(gdImagePtr to,gdImagePtr from)584 gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
585 {
586   int i;
587   int x, y, p;
588   int xlate[256];
589   if (to->trueColor)
590     {
591       return;
592     }
593   if (from->trueColor)
594     {
595       return;
596     }
597 
598   for (i = 0; i < 256; i++)
599     {
600       xlate[i] = -1;
601     };
602 
603   for (x = 0; x < (to->sx); x++)
604     {
605       for (y = 0; y < (to->sy); y++)
606 	{
607 	  p = gdImageGetPixel (to, x, y);
608 	  if (xlate[p] == -1)
609 	    {
610 	      /* This ought to use HWB, but we don't have an alpha-aware
611 	         version of that yet. */
612 	      xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
613 	      /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */
614 	      /*      p,  to->red[p], to->green[p], to->blue[p], to->alpha[p], */
615 	      /*      xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
616 	    };
617 	  gdImageSetPixel (to, x, y, xlate[p]);
618 	};
619     };
620 
621   for (i = 0; (i < (from->colorsTotal)); i++)
622     {
623       /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */
624       to->red[i] = from->red[i];
625       to->blue[i] = from->blue[i];
626       to->green[i] = from->green[i];
627       to->alpha[i] = from->alpha[i];
628       to->open[i] = 0;
629     };
630 
631   for (i = from->colorsTotal; (i < to->colorsTotal); i++)
632     {
633       to->open[i] = 1;
634     };
635 
636   to->colorsTotal = from->colorsTotal;
637 
638 }
639 
640 void
gdImageSetPixel(gdImagePtr im,int x,int y,int color)641 gdImageSetPixel (gdImagePtr im, int x, int y, int color)
642 {
643   int p;
644   switch (color)
645     {
646     case gdStyled:
647       if (!im->style)
648 	{
649 	  /* Refuse to draw if no style is set. */
650 	  return;
651 	}
652       else
653 	{
654 	  p = im->style[im->stylePos++];
655 	}
656       if (p != (gdTransparent))
657 	{
658 	  gdImageSetPixel (im, x, y, p);
659 	}
660       im->stylePos = im->stylePos % im->styleLength;
661       break;
662     case gdStyledBrushed:
663       if (!im->style)
664 	{
665 	  /* Refuse to draw if no style is set. */
666 	  return;
667 	}
668       p = im->style[im->stylePos++];
669       if ((p != gdTransparent) && (p != 0))
670 	{
671 	  gdImageSetPixel (im, x, y, gdBrushed);
672 	}
673       im->stylePos = im->stylePos % im->styleLength;
674       break;
675     case gdBrushed:
676       gdImageBrushApply (im, x, y);
677       break;
678     case gdTiled:
679       gdImageTileApply (im, x, y);
680       break;
681     default:
682       if (gdImageBoundsSafe (im, x, y))
683 	{
684 	  if (im->trueColor)
685 	    {
686 	      if (im->alphaBlendingFlag)
687 		{
688 		  im->tpixels[y][x] =
689 		    gdAlphaBlend (im->tpixels[y][x],
690 				  color);
691 		}
692 	      else
693 		{
694 		  im->tpixels[y][x] = color;
695 		}
696 	    }
697 	  else
698 	    {
699 	      im->pixels[y][x] = color;
700 	    }
701 	}
702       break;
703     }
704 }
705 
706 static int
gdImageGetTrueColorPixel(gdImagePtr im,int x,int y)707 gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
708 {
709   int p = gdImageGetPixel (im, x, y);
710   if (!im->trueColor)
711     {
712       return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p],
713 			       (im->transparent == p) ? gdAlphaTransparent :
714 			       gdAlphaOpaque);
715     }
716   else
717     {
718       return p;
719     }
720 }
721 
722 static void
gdImageBrushApply(gdImagePtr im,int x,int y)723 gdImageBrushApply (gdImagePtr im, int x, int y)
724 {
725   int lx, ly;
726   int hy;
727   int hx;
728   int x1, y1, x2, y2;
729   int srcx, srcy;
730   if (!im->brush)
731     {
732       return;
733     }
734   hy = gdImageSY (im->brush) / 2;
735   y1 = y - hy;
736   y2 = y1 + gdImageSY (im->brush);
737   hx = gdImageSX (im->brush) / 2;
738   x1 = x - hx;
739   x2 = x1 + gdImageSX (im->brush);
740   srcy = 0;
741   if (im->trueColor)
742     {
743       for (ly = y1; (ly < y2); ly++)
744 	{
745 	  srcx = 0;
746 	  for (lx = x1; (lx < x2); lx++)
747 	    {
748 	      int p;
749 	      p = gdImageGetTrueColorPixel (
750 					     im->brush, srcx, srcy);
751 	      gdImageSetPixel (im, lx, ly,
752 			       p);
753 	      srcx++;
754 	    }
755 	  srcy++;
756 	}
757     }
758   else
759     {
760       for (ly = y1; (ly < y2); ly++)
761 	{
762 	  srcx = 0;
763 	  for (lx = x1; (lx < x2); lx++)
764 	    {
765 	      int p;
766 	      p = gdImageGetPixel (im->brush, srcx, srcy);
767 	      /* Allow for non-square brushes! */
768 	      if (p != gdImageGetTransparent (im->brush))
769 		{
770 		  /* Truecolor brush. Very slow
771 		     on a palette destination. */
772 		  if (im->brush->trueColor)
773 		    {
774 		      gdImageSetPixel (im, lx, ly,
775 				       gdImageColorResolveAlpha (
776 								  im,
777 						      gdTrueColorGetRed (p),
778 						    gdTrueColorGetGreen (p),
779 						     gdTrueColorGetBlue (p),
780 						  gdTrueColorGetAlpha (p)));
781 		    }
782 		  else
783 		    {
784 		      gdImageSetPixel (im, lx, ly,
785 				       im->brushColorMap[p]);
786 		    }
787 		}
788 	      srcx++;
789 	    }
790 	  srcy++;
791 	}
792     }
793 }
794 
795 static void
gdImageTileApply(gdImagePtr im,int x,int y)796 gdImageTileApply (gdImagePtr im, int x, int y)
797 {
798   int srcx, srcy;
799   int p=0;
800   if (!im->tile)
801     {
802       return;
803     }
804   srcx = x % gdImageSX (im->tile);
805   srcy = y % gdImageSY (im->tile);
806   if (im->trueColor)
807     {
808       p = gdImageGetTrueColorPixel (im->tile, srcx, srcy);
809       gdImageSetPixel (im, x, y, p);
810     }
811   else
812     {
813       /* Allow for transparency */
814       if (p != gdImageGetTransparent (im->tile))
815 	{
816 	  if (im->tile->trueColor)
817 	    {
818 	      /* Truecolor tile. Very slow
819 	         on a palette destination. */
820 	      gdImageSetPixel (im, x, y,
821 			       gdImageColorResolveAlpha (
822 							  im,
823 						      gdTrueColorGetRed (p),
824 						    gdTrueColorGetGreen (p),
825 						     gdTrueColorGetBlue (p),
826 						  gdTrueColorGetAlpha (p)));
827 	    }
828 	  else
829 	    {
830 	      gdImageSetPixel (im, x, y,
831 			       im->tileColorMap[p]);
832 	    }
833 	}
834     }
835 }
836 
837 int
gdImageGetPixel(gdImagePtr im,int x,int y)838 gdImageGetPixel (gdImagePtr im, int x, int y)
839 {
840   if (gdImageBoundsSafe (im, x, y))
841     {
842       if (im->trueColor)
843 	{
844 	  return im->tpixels[y][x];
845 	}
846       else
847 	{
848 	  return im->pixels[y][x];
849 	}
850     }
851   else
852     {
853       return 0;
854     }
855 }
856 
857 /* Bresenham as presented in Foley & Van Dam */
858 void
gdImageLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)859 gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
860 {
861   int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
862   int wid;
863   int w, wstart;
864   int thick = im->thick;
865   dx = abs (x2 - x1);
866   dy = abs (y2 - y1);
867   if (dy <= dx)
868     {
869       /* More-or-less horizontal. use wid for vertical stroke */
870       wid = thick * cos (atan2 (dy, dx));
871       if (wid == 0)
872 	wid = 1;
873 
874       d = 2 * dy - dx;
875       incr1 = 2 * dy;
876       incr2 = 2 * (dy - dx);
877       if (x1 > x2)
878 	{
879 	  x = x2;
880 	  y = y2;
881 	  ydirflag = (-1);
882 	  xend = x1;
883 	}
884       else
885 	{
886 	  x = x1;
887 	  y = y1;
888 	  ydirflag = 1;
889 	  xend = x2;
890 	}
891 
892       /* Set up line thickness */
893       wstart = y - wid / 2;
894       for (w = wstart; w < wstart + wid; w++)
895 	gdImageSetPixel (im, x, w, color);
896 
897       if (((y2 - y1) * ydirflag) > 0)
898 	{
899 	  while (x < xend)
900 	    {
901 	      x++;
902 	      if (d < 0)
903 		{
904 		  d += incr1;
905 		}
906 	      else
907 		{
908 		  y++;
909 		  d += incr2;
910 		}
911 	      wstart = y - wid / 2;
912 	      for (w = wstart; w < wstart + wid; w++)
913 		gdImageSetPixel (im, x, w, color);
914 	    }
915 	}
916       else
917 	{
918 	  while (x < xend)
919 	    {
920 	      x++;
921 	      if (d < 0)
922 		{
923 		  d += incr1;
924 		}
925 	      else
926 		{
927 		  y--;
928 		  d += incr2;
929 		}
930 	      wstart = y - wid / 2;
931 	      for (w = wstart; w < wstart + wid; w++)
932 		gdImageSetPixel (im, x, w, color);
933 	    }
934 	}
935     }
936   else
937     {
938       /* More-or-less vertical. use wid for horizontal stroke */
939       wid = thick * sin (atan2 (dy, dx));
940       if (wid == 0)
941 	wid = 1;
942 
943       d = 2 * dx - dy;
944       incr1 = 2 * dx;
945       incr2 = 2 * (dx - dy);
946       if (y1 > y2)
947 	{
948 	  y = y2;
949 	  x = x2;
950 	  yend = y1;
951 	  xdirflag = (-1);
952 	}
953       else
954 	{
955 	  y = y1;
956 	  x = x1;
957 	  yend = y2;
958 	  xdirflag = 1;
959 	}
960 
961       /* Set up line thickness */
962       wstart = x - wid / 2;
963       for (w = wstart; w < wstart + wid; w++)
964 	gdImageSetPixel (im, w, y, color);
965 
966       if (((x2 - x1) * xdirflag) > 0)
967 	{
968 	  while (y < yend)
969 	    {
970 	      y++;
971 	      if (d < 0)
972 		{
973 		  d += incr1;
974 		}
975 	      else
976 		{
977 		  x++;
978 		  d += incr2;
979 		}
980 	      wstart = x - wid / 2;
981 	      for (w = wstart; w < wstart + wid; w++)
982 		gdImageSetPixel (im, w, y, color);
983 	    }
984 	}
985       else
986 	{
987 	  while (y < yend)
988 	    {
989 	      y++;
990 	      if (d < 0)
991 		{
992 		  d += incr1;
993 		}
994 	      else
995 		{
996 		  x--;
997 		  d += incr2;
998 		}
999 	      wstart = x - wid / 2;
1000 	      for (w = wstart; w < wstart + wid; w++)
1001 		gdImageSetPixel (im, w, y, color);
1002 	    }
1003 	}
1004     }
1005 }
1006 static void dashedSet (gdImagePtr im, int x, int y, int color,
1007 		       int *onP, int *dashStepP, int wid, int vert);
1008 
1009 void
gdImageDashedLine(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1010 gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1011 {
1012   int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
1013   int dashStep = 0;
1014   int on = 1;
1015   int wid;
1016   int vert;
1017   int thick = im->thick;
1018 
1019   dx = abs (x2 - x1);
1020   dy = abs (y2 - y1);
1021   if (dy <= dx)
1022     {
1023       /* More-or-less horizontal. use wid for vertical stroke */
1024       wid = thick * sin (atan2 (dy, dx));
1025       vert = 1;
1026 
1027       d = 2 * dy - dx;
1028       incr1 = 2 * dy;
1029       incr2 = 2 * (dy - dx);
1030       if (x1 > x2)
1031 	{
1032 	  x = x2;
1033 	  y = y2;
1034 	  ydirflag = (-1);
1035 	  xend = x1;
1036 	}
1037       else
1038 	{
1039 	  x = x1;
1040 	  y = y1;
1041 	  ydirflag = 1;
1042 	  xend = x2;
1043 	}
1044       dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1045       if (((y2 - y1) * ydirflag) > 0)
1046 	{
1047 	  while (x < xend)
1048 	    {
1049 	      x++;
1050 	      if (d < 0)
1051 		{
1052 		  d += incr1;
1053 		}
1054 	      else
1055 		{
1056 		  y++;
1057 		  d += incr2;
1058 		}
1059 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1060 	    }
1061 	}
1062       else
1063 	{
1064 	  while (x < xend)
1065 	    {
1066 	      x++;
1067 	      if (d < 0)
1068 		{
1069 		  d += incr1;
1070 		}
1071 	      else
1072 		{
1073 		  y--;
1074 		  d += incr2;
1075 		}
1076 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1077 	    }
1078 	}
1079     }
1080   else
1081     {
1082       /* More-or-less vertical. use wid for horizontal stroke */
1083       wid = thick * sin (atan2 (dy, dx));
1084       vert = 0;
1085 
1086       d = 2 * dx - dy;
1087       incr1 = 2 * dx;
1088       incr2 = 2 * (dx - dy);
1089       if (y1 > y2)
1090 	{
1091 	  y = y2;
1092 	  x = x2;
1093 	  yend = y1;
1094 	  xdirflag = (-1);
1095 	}
1096       else
1097 	{
1098 	  y = y1;
1099 	  x = x1;
1100 	  yend = y2;
1101 	  xdirflag = 1;
1102 	}
1103       dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1104       if (((x2 - x1) * xdirflag) > 0)
1105 	{
1106 	  while (y < yend)
1107 	    {
1108 	      y++;
1109 	      if (d < 0)
1110 		{
1111 		  d += incr1;
1112 		}
1113 	      else
1114 		{
1115 		  x++;
1116 		  d += incr2;
1117 		}
1118 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1119 	    }
1120 	}
1121       else
1122 	{
1123 	  while (y < yend)
1124 	    {
1125 	      y++;
1126 	      if (d < 0)
1127 		{
1128 		  d += incr1;
1129 		}
1130 	      else
1131 		{
1132 		  x--;
1133 		  d += incr2;
1134 		}
1135 	      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
1136 	    }
1137 	}
1138     }
1139 }
1140 
1141 static void
dashedSet(gdImagePtr im,int x,int y,int color,int * onP,int * dashStepP,int wid,int vert)1142 dashedSet (gdImagePtr im, int x, int y, int color,
1143 	   int *onP, int *dashStepP, int wid, int vert)
1144 {
1145   int dashStep = *dashStepP;
1146   int on = *onP;
1147   int w, wstart;
1148 
1149   dashStep++;
1150   if (dashStep == gdDashSize)
1151     {
1152       dashStep = 0;
1153       on = !on;
1154     }
1155   if (on)
1156     {
1157       if (vert)
1158 	{
1159 	  wstart = y - wid / 2;
1160 	  for (w = wstart; w < wstart + wid; w++)
1161 	    gdImageSetPixel (im, x, w, color);
1162 	}
1163       else
1164 	{
1165 	  wstart = x - wid / 2;
1166 	  for (w = wstart; w < wstart + wid; w++)
1167 	    gdImageSetPixel (im, w, y, color);
1168 	}
1169     }
1170   *dashStepP = dashStep;
1171   *onP = on;
1172 }
1173 #ifdef ORIGINAL_BOUNDS_SAFE
1174 int
gdImageBoundsSafe(gdImagePtr im,int x,int y)1175 gdImageBoundsSafe (gdImagePtr im, int x, int y)
1176 {
1177   return (!(((y < 0) || (y >= im->sy)) ||
1178 	    ((x < 0) || (x >= im->sx))));
1179 }
1180 #endif /* ORIGINAL_BOUNDS_SAFE */
1181 void
gdImageChar(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1182 gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y,
1183 	     int c, int color)
1184 {
1185   int cx, cy;
1186   int px, py;
1187   int fline;
1188   cx = 0;
1189   cy = 0;
1190 #ifdef CHARSET_EBCDIC
1191   c = ASC (c);
1192 #endif /*CHARSET_EBCDIC */
1193   if ((c < f->offset) || (c >= (f->offset + f->nchars)))
1194     {
1195       return;
1196     }
1197   fline = (c - f->offset) * f->h * f->w;
1198   for (py = y; (py < (y + f->h)); py++)
1199     {
1200       for (px = x; (px < (x + f->w)); px++)
1201 	{
1202 	  if (f->data[fline + cy * f->w + cx])
1203 	    {
1204 	      gdImageSetPixel (im, px, py, color);
1205 	    }
1206 	  cx++;
1207 	}
1208       cx = 0;
1209       cy++;
1210     }
1211 }
1212 
1213 void
gdImageCharUp(gdImagePtr im,gdFontPtr f,int x,int y,int c,int color)1214 gdImageCharUp (gdImagePtr im, gdFontPtr f,
1215 	       int x, int y, int c, int color)
1216 {
1217   int cx, cy;
1218   int px, py;
1219   int fline;
1220   cx = 0;
1221   cy = 0;
1222 #ifdef CHARSET_EBCDIC
1223   c = ASC (c);
1224 #endif /*CHARSET_EBCDIC */
1225   if ((c < f->offset) || (c >= (f->offset + f->nchars)))
1226     {
1227       return;
1228     }
1229   fline = (c - f->offset) * f->h * f->w;
1230   for (py = y; (py > (y - f->w)); py--)
1231     {
1232       for (px = x; (px < (x + f->h)); px++)
1233 	{
1234 	  if (f->data[fline + cy * f->w + cx])
1235 	    {
1236 	      gdImageSetPixel (im, px, py, color);
1237 	    }
1238 	  cy++;
1239 	}
1240       cy = 0;
1241       cx++;
1242     }
1243 }
1244 
1245 void
gdImageString(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1246 gdImageString (gdImagePtr im, gdFontPtr f,
1247 	       int x, int y, unsigned char *s, int color)
1248 {
1249   int i;
1250   int l;
1251   l = strlen ((char *) s);
1252   for (i = 0; (i < l); i++)
1253     {
1254       gdImageChar (im, f, x, y, s[i], color);
1255       x += f->w;
1256     }
1257 }
1258 
1259 void
gdImageStringUp(gdImagePtr im,gdFontPtr f,int x,int y,unsigned char * s,int color)1260 gdImageStringUp (gdImagePtr im, gdFontPtr f,
1261 		 int x, int y, unsigned char *s, int color)
1262 {
1263   int i;
1264   int l;
1265   l = strlen ((char *) s);
1266   for (i = 0; (i < l); i++)
1267     {
1268       gdImageCharUp (im, f, x, y, s[i], color);
1269       y -= f->w;
1270     }
1271 }
1272 
1273 static int strlen16 (unsigned short *s);
1274 
1275 void
gdImageString16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1276 gdImageString16 (gdImagePtr im, gdFontPtr f,
1277 		 int x, int y, unsigned short *s, int color)
1278 {
1279   int i;
1280   int l;
1281   l = strlen16 (s);
1282   for (i = 0; (i < l); i++)
1283     {
1284       gdImageChar (im, f, x, y, s[i], color);
1285       x += f->w;
1286     }
1287 }
1288 
1289 void
gdImageStringUp16(gdImagePtr im,gdFontPtr f,int x,int y,unsigned short * s,int color)1290 gdImageStringUp16 (gdImagePtr im, gdFontPtr f,
1291 		   int x, int y, unsigned short *s, int color)
1292 {
1293   int i;
1294   int l;
1295   l = strlen16 (s);
1296   for (i = 0; (i < l); i++)
1297     {
1298       gdImageCharUp (im, f, x, y, s[i], color);
1299       y -= f->w;
1300     }
1301 }
1302 
1303 static int
strlen16(unsigned short * s)1304 strlen16 (unsigned short *s)
1305 {
1306   int len = 0;
1307   while (*s)
1308     {
1309       s++;
1310       len++;
1311     }
1312   return len;
1313 }
1314 
1315 #if 0
1316 /* If you don't have a nice square root function for longs, you can use
1317    ** this hack
1318  */
1319 static long
1320 lsqrt (long n)
1321 {
1322   long result = (long) sqrt ((double) n);
1323   return result;
1324 }
1325 #endif
1326 
1327 /* s and e are integers modulo 360 (degrees), with 0 degrees
1328    being the rightmost extreme and degrees changing clockwise.
1329    cx and cy are the center in pixels; w and h are the horizontal
1330    and vertical diameter in pixels. Nice interface, but slow.
1331    See gd_arc_f_buggy.c for a better version that doesn't
1332    seem to be bug-free yet. */
1333 
1334 void
gdImageArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color)1335 gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
1336 {
1337   gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill);
1338 }
1339 
1340 void
gdImageFilledArc(gdImagePtr im,int cx,int cy,int w,int h,int s,int e,int color,int style)1341 gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
1342 {
1343   gdPoint pts[3];
1344   int i;
1345   int lx = 0, ly = 0;
1346   int fx=0, fy=0;
1347   int w2, h2;
1348   w2 = w / 2;
1349   h2 = h / 2;
1350 
1351   if ((s % 360)  == (e % 360)) {
1352          s = 0; e = 360;
1353   } else {
1354          if (s > 360) {
1355                  s = s % 360;
1356          }
1357 
1358          if (e > 360) {
1359                  e = e % 360;
1360          }
1361 
1362          while (s < 0) {
1363                  s += 360;
1364          }
1365 
1366          while (e < s) {
1367                  e += 360;
1368          }
1369 
1370          if (s == e) {
1371                  s = 0; e = 360;
1372          }
1373   }
1374 
1375   for (i = s; (i <= e); i++)
1376     {
1377       int x, y;
1378       x = ((long) gdCosT[i % 360] * (long) w2 / 1024) + cx;
1379       y = ((long) gdSinT[i % 360] * (long) h2 / 1024) + cy;
1380       if (i != s)
1381 	{
1382 	  if (!(style & gdChord))
1383 	    {
1384 	      if (style & gdNoFill)
1385 		{
1386 		  gdImageLine (im, lx, ly, x, y, color);
1387 		}
1388 	      else
1389 		{
1390 		  /* This is expensive! */
1391 		  pts[0].x = lx;
1392 		  pts[0].y = ly;
1393 		  pts[1].x = x;
1394 		  pts[1].y = y;
1395 		  pts[2].x = cx;
1396 		  pts[2].y = cy;
1397 		  gdImageFilledPolygon (im, pts, 3, color);
1398 		}
1399 	    }
1400 	}
1401       else
1402 	{
1403 	  fx = x;
1404 	  fy = y;
1405 	}
1406       lx = x;
1407       ly = y;
1408     }
1409   if (style & gdChord)
1410     {
1411       if (style & gdNoFill)
1412 	{
1413 	  if (style & gdEdged)
1414 	    {
1415 	      gdImageLine (im, cx, cy, lx, ly, color);
1416 	      gdImageLine (im, cx, cy, fx, fy, color);
1417 	    }
1418 	  gdImageLine (im, fx, fy, lx, ly, color);
1419 	}
1420       else
1421 	{
1422 	  pts[0].x = fx;
1423 	  pts[0].y = fy;
1424 	  pts[1].x = lx;
1425 	  pts[1].y = ly;
1426 	  pts[2].x = cx;
1427 	  pts[2].y = cy;
1428 	  gdImageFilledPolygon (im, pts, 3, color);
1429 	}
1430     }
1431   else
1432     {
1433       if (style & gdNoFill)
1434 	{
1435 	  if (style & gdEdged)
1436 	    {
1437 	      gdImageLine (im, cx, cy, lx, ly, color);
1438 	      gdImageLine (im, cx, cy, fx, fy, color);
1439 	    }
1440 	}
1441     }
1442 }
1443 
1444 void
gdImageFilledEllipse(gdImagePtr im,int cx,int cy,int w,int h,int color)1445 gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int w, int h, int color)
1446 {
1447   gdImageFilledArc (im, cx, cy, w, h, 0, 360, color, gdPie);
1448 }
1449 
1450 void
gdImageFillToBorder(gdImagePtr im,int x,int y,int border,int color)1451 gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
1452 {
1453   int lastBorder;
1454   /* Seek left */
1455   int leftLimit, rightLimit;
1456   int i;
1457   if (!gdImageBoundsSafe (im, x, y)) return;
1458   leftLimit = (-1);
1459   if (border < 0)
1460     {
1461       /* Refuse to fill to a non-solid border */
1462       return;
1463     }
1464   for (i = x; (i >= 0); i--)
1465     {
1466       if (gdImageGetPixel (im, i, y) == border)
1467 	{
1468 	  break;
1469 	}
1470       gdImageSetPixel (im, i, y, color);
1471       leftLimit = i;
1472     }
1473   if (leftLimit == (-1))
1474     {
1475       return;
1476     }
1477   /* Seek right */
1478   rightLimit = x;
1479   for (i = (x + 1); (i < im->sx); i++)
1480     {
1481       if (gdImageGetPixel (im, i, y) == border)
1482 	{
1483 	  break;
1484 	}
1485       gdImageSetPixel (im, i, y, color);
1486       rightLimit = i;
1487     }
1488   /* Look at lines above and below and start paints */
1489   /* Above */
1490   if (y > 0)
1491     {
1492       lastBorder = 1;
1493       for (i = leftLimit; (i <= rightLimit); i++)
1494 	{
1495 	  int c;
1496 	  c = gdImageGetPixel (im, i, y - 1);
1497 	  if (lastBorder)
1498 	    {
1499 	      if ((c != border) && (c != color))
1500 		{
1501 		  gdImageFillToBorder (im, i, y - 1,
1502 				       border, color);
1503 		  lastBorder = 0;
1504 		}
1505 	    }
1506 	  else if ((c == border) || (c == color))
1507 	    {
1508 	      lastBorder = 1;
1509 	    }
1510 	}
1511     }
1512   /* Below */
1513   if (y < ((im->sy) - 1))
1514     {
1515       lastBorder = 1;
1516       for (i = leftLimit; (i <= rightLimit); i++)
1517 	{
1518 	  int c;
1519 	  c = gdImageGetPixel (im, i, y + 1);
1520 	  if (lastBorder)
1521 	    {
1522 	      if ((c != border) && (c != color))
1523 		{
1524 		  gdImageFillToBorder (im, i, y + 1,
1525 				       border, color);
1526 		  lastBorder = 0;
1527 		}
1528 	    }
1529 	  else if ((c == border) || (c == color))
1530 	    {
1531 	      lastBorder = 1;
1532 	    }
1533 	}
1534     }
1535 }
1536 
1537 void
gdImageFill(gdImagePtr im,int x,int y,int color)1538 gdImageFill (gdImagePtr im, int x, int y, int color)
1539 {
1540   int lastBorder;
1541   int old;
1542   int leftLimit, rightLimit;
1543   int i;
1544   if (!gdImageBoundsSafe (im, x, y)) return;
1545   old = gdImageGetPixel (im, x, y);
1546   if (color == gdTiled)
1547     {
1548       /* Tile fill -- got to watch out! */
1549       int p, tileColor;
1550       int srcx, srcy;
1551       if (!im->tile)
1552 	{
1553 	  return;
1554 	}
1555       /* Refuse to flood-fill with a transparent pattern --
1556          I can't do it without allocating another image */
1557       if (gdImageGetTransparent (im->tile) != (-1))
1558 	{
1559 	  return;
1560 	}
1561       srcx = x % gdImageSX (im->tile);
1562       srcy = y % gdImageSY (im->tile);
1563       p = gdImageGetPixel (im->tile, srcx, srcy);
1564       if (im->trueColor)
1565 	{
1566 	  tileColor = p;
1567 	}
1568       else
1569 	{
1570 	  if (im->tile->trueColor)
1571 	    {
1572 	      tileColor = gdImageColorResolveAlpha (im,
1573 						    gdTrueColorGetRed (p),
1574 						    gdTrueColorGetGreen (p),
1575 						    gdTrueColorGetBlue (p),
1576 						    gdTrueColorGetAlpha (p));
1577 	    }
1578 	  else
1579 	    {
1580 	      tileColor = im->tileColorMap[p];
1581 	    }
1582 	}
1583       if (old == tileColor)
1584 	{
1585 	  /* Nothing to be done */
1586 	  return;
1587 	}
1588     }
1589   else
1590     {
1591       if (old == color)
1592 	{
1593 	  /* Nothing to be done */
1594 	  return;
1595 	}
1596     }
1597   /* Seek left */
1598   leftLimit = (-1);
1599   for (i = x; (i >= 0); i--)
1600     {
1601       if (gdImageGetPixel (im, i, y) != old)
1602 	{
1603 	  break;
1604 	}
1605       gdImageSetPixel (im, i, y, color);
1606       leftLimit = i;
1607     }
1608   if (leftLimit == (-1))
1609     {
1610       return;
1611     }
1612   /* Seek right */
1613   rightLimit = x;
1614   for (i = (x + 1); (i < im->sx); i++)
1615     {
1616       if (gdImageGetPixel (im, i, y) != old)
1617 	{
1618 	  break;
1619 	}
1620       gdImageSetPixel (im, i, y, color);
1621       rightLimit = i;
1622     }
1623   /* Look at lines above and below and start paints */
1624   /* Above */
1625   if (y > 0)
1626     {
1627       lastBorder = 1;
1628       for (i = leftLimit; (i <= rightLimit); i++)
1629 	{
1630 	  int c;
1631 	  c = gdImageGetPixel (im, i, y - 1);
1632 	  if (lastBorder)
1633 	    {
1634 	      if (c == old)
1635 		{
1636 		  gdImageFill (im, i, y - 1, color);
1637 		  lastBorder = 0;
1638 		}
1639 	    }
1640 	  else if (c != old)
1641 	    {
1642 	      lastBorder = 1;
1643 	    }
1644 	}
1645     }
1646   /* Below */
1647   if (y < ((im->sy) - 1))
1648     {
1649       lastBorder = 1;
1650       for (i = leftLimit; (i <= rightLimit); i++)
1651 	{
1652 	  int c;
1653 	  c = gdImageGetPixel (im, i, y + 1);
1654 	  if (lastBorder)
1655 	    {
1656 	      if (c == old)
1657 		{
1658 		  gdImageFill (im, i, y + 1, color);
1659 		  lastBorder = 0;
1660 		}
1661 	    }
1662 	  else if (c != old)
1663 	    {
1664 	      lastBorder = 1;
1665 	    }
1666 	}
1667     }
1668 }
1669 
1670 void
gdImageRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1671 gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1672 {
1673   int x1h = x1, x1v = x1, y1h = y1, y1v = y1, x2h = x2, x2v = x2, y2h = y2,
1674     y2v = y2;
1675   int thick = im->thick;
1676   if (thick > 1)
1677     {
1678       int half = thick / 2;
1679       int half1 = thick - half;
1680 
1681       if (y1 < y2)
1682 	{
1683 	  y1v = y1h - half;
1684 	  y2v = y2h + half1 - 1;
1685 	}
1686       else
1687 	{
1688 	  y1v = y1h + half1 - 1;
1689 	  y2v = y2h - half;
1690 	}
1691     }
1692 
1693   gdImageLine (im, x1h, y1h, x2h, y1h, color);
1694   gdImageLine (im, x1h, y2h, x2h, y2h, color);
1695   gdImageLine (im, x1v, y1v, x1v, y2v, color);
1696   gdImageLine (im, x2v, y1v, x2v, y2v, color);
1697 }
1698 
1699 void
gdImageFilledRectangle(gdImagePtr im,int x1,int y1,int x2,int y2,int color)1700 gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1701 {
1702   int x, y;
1703   for (y = y1; (y <= y2); y++)
1704     {
1705       for (x = x1; (x <= x2); x++)
1706 	{
1707 	  gdImageSetPixel (im, x, y, color);
1708 	}
1709     }
1710 }
1711 
1712 void
gdImageCopy(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h)1713 gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
1714 {
1715   int c;
1716   int x, y;
1717   int tox, toy;
1718   int i;
1719   int colorMap[gdMaxColors];
1720   if (dst->trueColor)
1721     {
1722       /* 2.0: much easier when the destination is truecolor. */
1723       for (y = 0; (y < h); y++)
1724 	{
1725 	  for (x = 0; (x < w); x++)
1726 	    {
1727 	      int c = gdImageGetTrueColorPixel (src, srcX + x,
1728 						srcY + y);
1729 	      if (c != src->transparent)
1730 		{
1731 		  gdImageSetPixel (dst,
1732 				   dstX + x,
1733 				   dstY + y,
1734 				   c);
1735 		}
1736 	    }
1737 	}
1738       return;
1739     }
1740   for (i = 0; (i < gdMaxColors); i++)
1741     {
1742       colorMap[i] = (-1);
1743     }
1744   toy = dstY;
1745   for (y = srcY; (y < (srcY + h)); y++)
1746     {
1747       tox = dstX;
1748       for (x = srcX; (x < (srcX + w)); x++)
1749 	{
1750 	  int nc;
1751 	  c = gdImageGetPixel (src, x, y);
1752 	  /* Added 7/24/95: support transparent copies */
1753 	  if (gdImageGetTransparent (src) == c)
1754 	    {
1755 	      tox++;
1756 	      continue;
1757 	    }
1758 	  /* Have we established a mapping for this color? */
1759 	  if (colorMap[c] == (-1))
1760 	    {
1761 	      /* If it's the same image, mapping is trivial */
1762 	      if (dst == src)
1763 		{
1764 		  nc = c;
1765 		}
1766 	      else
1767 		{
1768 		  /* Get best match possible. This
1769 		     function never returns error. */
1770 		  nc = gdImageColorResolveAlpha (
1771 						  dst,
1772 						  src->red[c], src->green[c],
1773 					       src->blue[c], src->alpha[c]);
1774 		}
1775 	      colorMap[c] = nc;
1776 	    }
1777 	  gdImageSetPixel (dst, tox, toy, colorMap[c]);
1778 	  tox++;
1779 	}
1780       toy++;
1781     }
1782 }
1783 
1784 /* This function is a substitute for real alpha channel operations,
1785    so it doesn't pay attention to the alpha channel. */
1786 void
gdImageCopyMerge(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)1787 gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
1788 {
1789 
1790   int c, dc;
1791   int x, y;
1792   int tox, toy;
1793   int ncR, ncG, ncB;
1794   toy = dstY;
1795   for (y = srcY; (y < (srcY + h)); y++)
1796     {
1797       tox = dstX;
1798       for (x = srcX; (x < (srcX + w)); x++)
1799 	{
1800 	  int nc;
1801 	  c = gdImageGetPixel (src, x, y);
1802 	  /* Added 7/24/95: support transparent copies */
1803 	  if (gdImageGetTransparent (src) == c)
1804 	    {
1805 	      tox++;
1806 	      continue;
1807 	    }
1808 	  /* If it's the same image, mapping is trivial */
1809 	  if (dst == src)
1810 	    {
1811 	      nc = c;
1812 	    }
1813 	  else
1814 	    {
1815 	      dc = gdImageGetPixel (dst, tox, toy);
1816 
1817 	      ncR = gdImageRed (src, c) * (pct / 100.0)
1818 		+ gdImageRed (dst, dc) * ((100 - pct) / 100.0);
1819 	      ncG = gdImageGreen (src, c) * (pct / 100.0)
1820 		+ gdImageGreen (dst, dc) * ((100 - pct) / 100.0);
1821 	      ncB = gdImageBlue (src, c) * (pct / 100.0)
1822 		+ gdImageBlue (dst, dc) * ((100 - pct) / 100.0);
1823 
1824 	      /* Find a reasonable color */
1825 	      nc = gdImageColorResolve (dst, ncR, ncG, ncB);
1826 	    }
1827 	  gdImageSetPixel (dst, tox, toy, nc);
1828 	  tox++;
1829 	}
1830       toy++;
1831     }
1832 }
1833 
1834 /* This function is a substitute for real alpha channel operations,
1835    so it doesn't pay attention to the alpha channel. */
1836 void
gdImageCopyMergeGray(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int w,int h,int pct)1837 gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
1838 {
1839 
1840   int c, dc;
1841   int x, y;
1842   int tox, toy;
1843   int ncR, ncG, ncB;
1844   float g;
1845   toy = dstY;
1846   for (y = srcY; (y < (srcY + h)); y++)
1847     {
1848       tox = dstX;
1849       for (x = srcX; (x < (srcX + w)); x++)
1850 	{
1851 	  int nc;
1852 	  c = gdImageGetPixel (src, x, y);
1853 	  /* Added 7/24/95: support transparent copies */
1854 	  if (gdImageGetTransparent (src) == c)
1855 	    {
1856 	      tox++;
1857 	      continue;
1858 	    }
1859 	  /* If it's the same image, mapping is trivial */
1860 	  if (dst == src)
1861 	    {
1862 	      nc = c;
1863 	    }
1864 	  else
1865 	    {
1866 	      dc = gdImageGetPixel (dst, tox, toy);
1867 	      g = 0.29900 * dst->red[dc]
1868 		+ 0.58700 * dst->green[dc]
1869 		+ 0.11400 * dst->blue[dc];
1870 
1871 	      ncR = gdImageRed (src, c) * (pct / 100.0)
1872 		+ gdImageRed (dst, dc) * g *
1873 		((100 - pct) / 100.0);
1874 	      ncG = gdImageGreen (src, c) * (pct / 100.0)
1875 		+ gdImageGreen (dst, dc) * g *
1876 		((100 - pct) / 100.0);
1877 	      ncB = gdImageBlue (src, c) * (pct / 100.0)
1878 		+ gdImageBlue (dst, dc) * g *
1879 		((100 - pct) / 100.0);
1880 
1881 	      /* First look for an exact match */
1882 	      nc = gdImageColorExact (dst, ncR, ncG, ncB);
1883 	      if (nc == (-1))
1884 		{
1885 		  /* No, so try to allocate it */
1886 		  nc = gdImageColorAllocate (dst, ncR, ncG, ncB);
1887 		  /* If we're out of colors, go for the
1888 		     closest color */
1889 		  if (nc == (-1))
1890 		    {
1891 		      nc = gdImageColorClosest (dst, ncR, ncG, ncB);
1892 		    }
1893 		}
1894 	    }
1895 	  gdImageSetPixel (dst, tox, toy, nc);
1896 	  tox++;
1897 	}
1898       toy++;
1899     }
1900 }
1901 
1902 void
gdImageCopyResized(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)1903 gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
1904 {
1905   int c;
1906   int x, y;
1907   int tox, toy;
1908   int ydest;
1909   int i;
1910   int colorMap[gdMaxColors];
1911   /* Stretch vectors */
1912   int *stx;
1913   int *sty;
1914   /* We only need to use floating point to determine the correct
1915      stretch vector for one line's worth. */
1916   double accum;
1917   stx = (int *) gdMalloc (sizeof (int) * srcW);
1918   sty = (int *) gdMalloc (sizeof (int) * srcH);
1919   accum = 0;
1920   for (i = 0; (i < srcW); i++)
1921     {
1922       int got;
1923       accum += (double) dstW / (double) srcW;
1924       got = (int) floor (accum);
1925       stx[i] = got;
1926       accum -= got;
1927     }
1928   accum = 0;
1929   for (i = 0; (i < srcH); i++)
1930     {
1931       int got;
1932       accum += (double) dstH / (double) srcH;
1933       got = (int) floor (accum);
1934       sty[i] = got;
1935       accum -= got;
1936     }
1937   for (i = 0; (i < gdMaxColors); i++)
1938     {
1939       colorMap[i] = (-1);
1940     }
1941   toy = dstY;
1942   for (y = srcY; (y < (srcY + srcH)); y++)
1943     {
1944       for (ydest = 0; (ydest < sty[y - srcY]); ydest++)
1945 	{
1946 	  tox = dstX;
1947 	  for (x = srcX; (x < (srcX + srcW)); x++)
1948 	    {
1949 	      int nc=0;
1950 	      int mapTo;
1951 	      if (!stx[x - srcX])
1952 		{
1953 		  continue;
1954 		}
1955 	      if (dst->trueColor)
1956 		{
1957 		  mapTo = gdImageGetTrueColorPixel (src, x, y);
1958 		  /* Added 7/24/95: support transparent copies */
1959 		  if (gdImageGetTransparent (src) == mapTo)
1960 		    {
1961 		      tox++;
1962 		      continue;
1963 		    }
1964 		}
1965 	      else
1966 		{
1967 		  c = gdImageGetPixel (src, x, y);
1968 		  /* Added 7/24/95: support transparent copies */
1969 		  if (gdImageGetTransparent (src) == c)
1970 		    {
1971 		      tox += stx[x - srcX];
1972 		      continue;
1973 		    }
1974 		  if (src->trueColor)
1975 		    {
1976 		      /* Remap to the palette available in the
1977 		         destination image. This is slow and
1978 		         works badly. */
1979 		      mapTo = gdImageColorResolveAlpha (dst,
1980 						      gdTrueColorGetRed (c),
1981 						    gdTrueColorGetGreen (c),
1982 						     gdTrueColorGetBlue (c),
1983 						   gdTrueColorGetAlpha (c));
1984 		    }
1985 		  else
1986 		    {
1987 		      /* Have we established a mapping for this color? */
1988 		      if (colorMap[c] == (-1))
1989 			{
1990 			  /* If it's the same image, mapping is trivial */
1991 			  if (dst == src)
1992 			    {
1993 			      nc = c;
1994 			    }
1995 			  else
1996 			    {
1997 			      /* Find or create the best match */
1998 			      nc = gdImageColorResolveAlpha (dst,
1999 						      gdTrueColorGetRed (c),
2000 						    gdTrueColorGetGreen (c),
2001 						     gdTrueColorGetBlue (c),
2002 						   gdTrueColorGetAlpha (c));
2003 			    }
2004 			  colorMap[c] = nc;
2005 			}
2006 		      mapTo = colorMap[c];
2007 		    }
2008 		}
2009 	      for (i = 0; (i < stx[x - srcX]); i++)
2010 		{
2011 		  gdImageSetPixel (dst, tox, toy, mapTo);
2012 		  tox++;
2013 		}
2014 	    }
2015 	  toy++;
2016 	}
2017     }
2018   gdFree (stx);
2019   gdFree (sty);
2020 }
2021 
2022 /* When gd 1.x was first created, floating point was to be avoided.
2023    These days it is often faster than table lookups or integer
2024    arithmetic. The routine below is shamelessly, gloriously
2025    floating point. TBB */
2026 
2027 void
gdImageCopyResampled(gdImagePtr dst,gdImagePtr src,int dstX,int dstY,int srcX,int srcY,int dstW,int dstH,int srcW,int srcH)2028 gdImageCopyResampled (gdImagePtr dst,
2029 		      gdImagePtr src,
2030 		      int dstX, int dstY,
2031 		      int srcX, int srcY,
2032 		      int dstW, int dstH,
2033 		      int srcW, int srcH)
2034 {
2035   int x, y;
2036   if (!dst->trueColor)
2037     {
2038       gdImageCopyResized (
2039 			   dst, src, dstX, dstY, srcX, srcY, dstW, dstH,
2040 			   srcW, srcH);
2041       return;
2042     }
2043   for (y = dstY; (y < dstY + dstH); y++)
2044     {
2045       for (x = dstX; (x < dstX + dstW); x++)
2046 	{
2047 	  float sy1, sy2, sx1, sx2;
2048 	  float sx, sy;
2049 	  float spixels = 0;
2050 	  float red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
2051 	  sy1 = ((float) y - (float) dstY) * (float) srcH /
2052 	    (float) dstH;
2053 	  sy2 = ((float) (y + 1) - (float) dstY) * (float) srcH /
2054 	    (float) dstH;
2055 	  sy = sy1;
2056 	  do
2057 	    {
2058 	      float yportion;
2059 	      if (floor (sy) == floor (sy1))
2060 		{
2061 		  yportion = 1.0 - (sy - floor (sy));
2062 		  if (yportion > sy2 - sy1)
2063 		    {
2064 		      yportion = sy2 - sy1;
2065 		    }
2066 		  sy = floor (sy);
2067 		}
2068 	      else if (sy == floor (sy2))
2069 		{
2070 		  yportion = sy2 - floor (sy2);
2071 		}
2072 	      else
2073 		{
2074 		  yportion = 1.0;
2075 		}
2076 	      sx1 = ((float) x - (float) dstX) * (float) srcW /
2077 		dstW;
2078 	      sx2 = ((float) (x + 1) - (float) dstX) * (float) srcW /
2079 		dstW;
2080 	      sx = sx1;
2081 	      do
2082 		{
2083 		  float xportion;
2084 		  float pcontribution;
2085 		  int p;
2086 		  if (floor (sx) == floor (sx1))
2087 		    {
2088 		      xportion = 1.0 - (sx - floor (sx));
2089 		      if (xportion > sx2 - sx1)
2090 			{
2091 			  xportion = sx2 - sx1;
2092 			}
2093 		      sx = floor (sx);
2094 		    }
2095 		  else if (sx == floor (sx2))
2096 		    {
2097 		      xportion = sx2 - floor (sx2);
2098 		    }
2099 		  else
2100 		    {
2101 		      xportion = 1.0;
2102 		    }
2103 		  pcontribution = xportion * yportion;
2104 		  p = gdImageGetTrueColorPixel (
2105 						 src,
2106 						 (int) sx,
2107 						 (int) sy);
2108 		  red += gdTrueColorGetRed (p) * pcontribution;
2109 		  green += gdTrueColorGetGreen (p) * pcontribution;
2110 		  blue += gdTrueColorGetBlue (p) * pcontribution;
2111 		  alpha += gdTrueColorGetAlpha (p) * pcontribution;
2112 		  spixels += xportion * yportion;
2113 		  sx += 1.0;
2114 		}
2115 	      while (sx < sx2);
2116 	      sy += 1.0;
2117 	    }
2118 	  while (sy < sy2);
2119 	  if (spixels != 0.0)
2120 	    {
2121 	      red /= spixels;
2122 	      green /= spixels;
2123 	      blue /= spixels;
2124 	      alpha /= spixels;
2125 	    }
2126 	  /* Clamping to allow for rounding errors above */
2127 	  if (red > 255.0)
2128 	    {
2129 	      red = 255.0;
2130 	    }
2131 	  if (green > 255.0)
2132 	    {
2133 	      green = 255.0;
2134 	    }
2135 	  if (blue > 255.0)
2136 	    {
2137 	      blue = 255.0;
2138 	    }
2139 	  if (alpha > gdAlphaMax)
2140 	    {
2141 	      alpha = gdAlphaMax;
2142 	    }
2143 	  gdImageSetPixel (dst,
2144 			   x, y,
2145 			   gdTrueColorAlpha ((int) red,
2146 					     (int) green,
2147 					     (int) blue,
2148 					     (int) alpha));
2149 	}
2150     }
2151 }
2152 
2153 gdImagePtr
gdImageCreateFromXbm(FILE * fd)2154 gdImageCreateFromXbm (FILE * fd)
2155 {
2156   gdImagePtr im;
2157   int bit;
2158   int w, h;
2159   int bytes;
2160   int ch;
2161   int i, x, y;
2162   char *sp;
2163   char s[161];
2164   if (!fgets (s, 160, fd))
2165     {
2166       return 0;
2167     }
2168   sp = &s[0];
2169   /* Skip #define */
2170   sp = strchr (sp, ' ');
2171   if (!sp)
2172     {
2173       return 0;
2174     }
2175   /* Skip width label */
2176   sp++;
2177   sp = strchr (sp, ' ');
2178   if (!sp)
2179     {
2180       return 0;
2181     }
2182   /* Get width */
2183   w = atoi (sp + 1);
2184   if (!w)
2185     {
2186       return 0;
2187     }
2188   if (!fgets (s, 160, fd))
2189     {
2190       return 0;
2191     }
2192   sp = s;
2193   /* Skip #define */
2194   sp = strchr (sp, ' ');
2195   if (!sp)
2196     {
2197       return 0;
2198     }
2199   /* Skip height label */
2200   sp++;
2201   sp = strchr (sp, ' ');
2202   if (!sp)
2203     {
2204       return 0;
2205     }
2206   /* Get height */
2207   h = atoi (sp + 1);
2208   if (!h)
2209     {
2210       return 0;
2211     }
2212 
2213   /* The X protocol request CreatePixmap puts an upper bound
2214      of 16 bit to the size.
2215      see, e.g. moz#424333, fdo#48961, rhbz#1086714 */
2216   if (w < 0 || w > SHRT_MAX || h < 0 || h > SHRT_MAX)
2217     {
2218         return 0;
2219     }
2220 
2221   /* Skip declaration line */
2222   if (!fgets (s, 160, fd))
2223     {
2224       return 0;
2225     }
2226   bytes = (w * h / 8) + 1;
2227   im = gdImageCreate (w, h);
2228   if (!im) {
2229     return 0;
2230   }
2231 
2232   gdImageColorAllocate (im, 255, 255, 255);
2233   gdImageColorAllocate (im, 0, 0, 0);
2234   x = 0;
2235   y = 0;
2236   for (i = 0; (i < bytes); i++)
2237     {
2238       char h[3];
2239       int b;
2240       /* Skip spaces, commas, CRs, 0x */
2241       while (1)
2242 	{
2243 	  ch = getc (fd);
2244 	  if (ch == EOF)
2245 	    {
2246 	      goto fail;
2247 	    }
2248 	  if (ch == 'x')
2249 	    {
2250 	      break;
2251 	    }
2252 	}
2253       /* Get hex value */
2254       ch = getc (fd);
2255       if (ch == EOF)
2256 	{
2257 	  goto fail;
2258 	}
2259       h[0] = ch;
2260       ch = getc (fd);
2261       if (ch == EOF)
2262 	{
2263 	  goto fail;
2264 	}
2265       h[1] = ch;
2266       h[2] = '\0';
2267       if (sscanf (h, "%x", &b) != 1)
2268         {
2269 	  goto fail;
2270         }
2271       for (bit = 1; (bit <= 128); (bit = bit << 1))
2272 	{
2273 	  gdImageSetPixel (im, x++, y, (b & bit) ? 1 : 0);
2274 	  if (x == im->sx)
2275 	    {
2276 	      x = 0;
2277 	      y++;
2278 	      if (y == im->sy)
2279 		{
2280 		  return im;
2281 		}
2282 	      /* Fix 8/8/95 */
2283 	      break;
2284 	    }
2285 	}
2286     }
2287   /* Shouldn't happen */
2288   fprintf (stderr, "Error: bug in gdImageCreateFromXbm!\n");
2289 fail:
2290   gdImageDestroy (im);
2291   return 0;
2292 }
2293 
2294 void
gdImagePolygon(gdImagePtr im,gdPointPtr p,int n,int c)2295 gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2296 {
2297   int i;
2298   int lx, ly;
2299   if (!n)
2300     {
2301       return;
2302     }
2303   lx = p->x;
2304   ly = p->y;
2305   gdImageLine (im, lx, ly, p[n - 1].x, p[n - 1].y, c);
2306   for (i = 1; (i < n); i++)
2307     {
2308       p++;
2309       gdImageLine (im, lx, ly, p->x, p->y, c);
2310       lx = p->x;
2311       ly = p->y;
2312     }
2313 }
2314 
2315 static int gdCompareInt (const void *a, const void *b);
2316 
2317 /* THANKS to Kirsten Schulz for the polygon fixes! */
2318 
2319 /* The intersection finding technique of this code could be improved  */
2320 /* by remembering the previous intertersection, and by using the slope. */
2321 /* That could help to adjust intersections  to produce a nice */
2322 /* interior_extrema. */
2323 
2324 void
gdImageFilledPolygon(gdImagePtr im,gdPointPtr p,int n,int c)2325 gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
2326 {
2327   int i;
2328   int y;
2329   int miny, maxy;
2330   int x1, y1;
2331   int x2, y2;
2332   int ind1, ind2;
2333   int ints;
2334   if (!n)
2335     {
2336       return;
2337     }
2338   if (!im->polyAllocated)
2339     {
2340       im->polyInts = (int *) gdMalloc (sizeof (int) * n);
2341       im->polyAllocated = n;
2342     }
2343   if (im->polyAllocated < n)
2344     {
2345       while (im->polyAllocated < n)
2346 	{
2347 	  im->polyAllocated *= 2;
2348 	}
2349       im->polyInts = (int *) gdRealloc (im->polyInts,
2350 					sizeof (int) * im->polyAllocated);
2351     }
2352   miny = p[0].y;
2353   maxy = p[0].y;
2354   for (i = 1; (i < n); i++)
2355     {
2356       if (p[i].y < miny)
2357 	{
2358 	  miny = p[i].y;
2359 	}
2360       if (p[i].y > maxy)
2361 	{
2362 	  maxy = p[i].y;
2363 	}
2364     }
2365   /* Fix in 1.3: count a vertex only once */
2366   for (y = miny; (y <= maxy); y++)
2367     {
2368 /*1.4           int interLast = 0; */
2369 /*              int dirLast = 0; */
2370 /*              int interFirst = 1; */
2371       ints = 0;
2372       for (i = 0; (i < n); i++)
2373 	{
2374 	  if (!i)
2375 	    {
2376 	      ind1 = n - 1;
2377 	      ind2 = 0;
2378 	    }
2379 	  else
2380 	    {
2381 	      ind1 = i - 1;
2382 	      ind2 = i;
2383 	    }
2384 	  y1 = p[ind1].y;
2385 	  y2 = p[ind2].y;
2386 	  if (y1 < y2)
2387 	    {
2388 	      x1 = p[ind1].x;
2389 	      x2 = p[ind2].x;
2390 	    }
2391 	  else if (y1 > y2)
2392 	    {
2393 	      y2 = p[ind1].y;
2394 	      y1 = p[ind2].y;
2395 	      x2 = p[ind1].x;
2396 	      x1 = p[ind2].x;
2397 	    }
2398 	  else
2399 	    {
2400 	      continue;
2401 	    }
2402 	  if ((y >= y1) && (y < y2))
2403 	    {
2404 	      im->polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
2405 	    }
2406 	  else if ((y == maxy) && (y > y1) && (y <= y2))
2407 	    {
2408 	      im->polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
2409 	    }
2410 	}
2411       qsort (im->polyInts, ints, sizeof (int), gdCompareInt);
2412 
2413       for (i = 0; (i < (ints)); i += 2)
2414 	{
2415 	  gdImageLine (im, im->polyInts[i], y,
2416 		       im->polyInts[i + 1], y, c);
2417 	}
2418     }
2419 }
2420 
2421 int
gdCompareInt(const void * a,const void * b)2422 gdCompareInt (const void *a, const void *b)
2423 {
2424   return (*(const int *) a) - (*(const int *) b);
2425 }
2426 
2427 void
gdImageSetStyle(gdImagePtr im,int * style,int noOfPixels)2428 gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
2429 {
2430   if (im->style)
2431     {
2432       gdFree (im->style);
2433     }
2434   im->style = (int *)
2435     gdMalloc (sizeof (int) * noOfPixels);
2436   memcpy (im->style, style, sizeof (int) * noOfPixels);
2437   im->styleLength = noOfPixels;
2438   im->stylePos = 0;
2439 }
2440 
2441 void
gdImageSetThickness(gdImagePtr im,int thickness)2442 gdImageSetThickness (gdImagePtr im, int thickness)
2443 {
2444   im->thick = thickness;
2445 }
2446 
2447 void
gdImageSetBrush(gdImagePtr im,gdImagePtr brush)2448 gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
2449 {
2450   int i;
2451   im->brush = brush;
2452   if ((!im->trueColor) && (!im->brush->trueColor))
2453     {
2454       for (i = 0; (i < gdImageColorsTotal (brush)); i++)
2455 	{
2456 	  int index;
2457 	  index = gdImageColorResolveAlpha (im,
2458 					    gdImageRed (brush, i),
2459 					    gdImageGreen (brush, i),
2460 					    gdImageBlue (brush, i),
2461 					    gdImageAlpha (brush, i));
2462 	  im->brushColorMap[i] = index;
2463 	}
2464     }
2465 }
2466 
2467 void
gdImageSetTile(gdImagePtr im,gdImagePtr tile)2468 gdImageSetTile (gdImagePtr im, gdImagePtr tile)
2469 {
2470   int i;
2471   im->tile = tile;
2472   if ((!im->trueColor) && (!im->tile->trueColor))
2473     {
2474       for (i = 0; (i < gdImageColorsTotal (tile)); i++)
2475 	{
2476 	  int index;
2477 	  index = gdImageColorResolveAlpha (im,
2478 					    gdImageRed (tile, i),
2479 					    gdImageGreen (tile, i),
2480 					    gdImageBlue (tile, i),
2481 					    gdImageAlpha (tile, i));
2482 	  im->tileColorMap[i] = index;
2483 	}
2484     }
2485 }
2486 
2487 void
gdImageInterlace(gdImagePtr im,int interlaceArg)2488 gdImageInterlace (gdImagePtr im, int interlaceArg)
2489 {
2490   im->interlace = interlaceArg;
2491 }
2492 
2493 int
gdImageCompare(gdImagePtr im1,gdImagePtr im2)2494 gdImageCompare (gdImagePtr im1, gdImagePtr im2)
2495 {
2496   int x, y;
2497   int p1, p2;
2498   int cmpStatus = 0;
2499   int sx, sy;
2500 
2501   if (im1->interlace != im2->interlace)
2502     {
2503       cmpStatus |= GD_CMP_INTERLACE;
2504     }
2505 
2506   if (im1->transparent != im2->transparent)
2507     {
2508       cmpStatus |= GD_CMP_TRANSPARENT;
2509     }
2510 
2511   if (im1->trueColor != im2->trueColor)
2512     {
2513       cmpStatus |= GD_CMP_TRUECOLOR;
2514     }
2515 
2516   sx = im1->sx;
2517   if (im1->sx != im2->sx)
2518     {
2519       cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
2520       if (im2->sx < im1->sx)
2521 	{
2522 	  sx = im2->sx;
2523 	}
2524     }
2525 
2526   sy = im1->sy;
2527   if (im1->sy != im2->sy)
2528     {
2529       cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
2530       if (im2->sy < im1->sy)
2531 	{
2532 	  sy = im2->sy;
2533 	}
2534     }
2535 
2536   if (im1->colorsTotal != im2->colorsTotal)
2537     {
2538       cmpStatus |= GD_CMP_NUM_COLORS;
2539     }
2540 
2541   for (y = 0; (y < sy); y++)
2542     {
2543       for (x = 0; (x < sx); x++)
2544 	{
2545 	  p1 = im1->pixels[y][x];
2546 	  p2 = im2->pixels[y][x];
2547 	  if (gdImageRed (im1, p1) != gdImageRed (im2, p2))
2548 	    {
2549 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2550 	      break;
2551 	    }
2552 	  if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2))
2553 	    {
2554 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2555 	      break;
2556 	    }
2557 	  if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2))
2558 	    {
2559 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2560 	      break;
2561 	    }
2562 #if 0
2563 	  /* Soon we'll add alpha channel to palettes */
2564 	  if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2))
2565 	    {
2566 	      cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
2567 	      break;
2568 	    }
2569 #endif
2570 	}
2571       if (cmpStatus & GD_CMP_COLOR)
2572 	{
2573 	  break;
2574 	};
2575     }
2576 
2577   return cmpStatus;
2578 }
2579 
2580 int
gdAlphaBlend(int dst,int src)2581 gdAlphaBlend (int dst, int src)
2582 {
2583   return (((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
2584 	     gdTrueColorGetRed (src) / gdAlphaMax) +
2585 	    (gdTrueColorGetAlpha (src) *
2586 	     gdTrueColorGetRed (dst)) / gdAlphaMax) << 16) +
2587 	  ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
2588 	     gdTrueColorGetGreen (src) / gdAlphaMax) +
2589 	    (gdTrueColorGetAlpha (src) *
2590 	     gdTrueColorGetGreen (dst)) / gdAlphaMax) << 8) +
2591 	  (((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
2592 	    gdTrueColorGetBlue (src) / gdAlphaMax) +
2593 	   (gdTrueColorGetAlpha (src) *
2594 	    gdTrueColorGetBlue (dst)) / gdAlphaMax));
2595 }
2596 
2597 void
gdImageAlphaBlending(gdImagePtr im,int alphaBlendingArg)2598 gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
2599 {
2600   im->alphaBlendingFlag = alphaBlendingArg;
2601 }
2602 
2603 void
gdImageSaveAlpha(gdImagePtr im,int saveAlphaArg)2604 gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
2605 {
2606   im->saveAlphaFlag = saveAlphaArg;
2607 }
2608