root/ext/gd/libgd/gd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_gd_error_ex
  2. php_gd_error
  3. gdImageCreate
  4. gdImageCreateTrueColor
  5. gdImageDestroy
  6. gdImageColorClosest
  7. gdImageColorClosestAlpha
  8. RGB_to_HWB
  9. HWB_Diff
  10. HWB_to_RGB
  11. gdImageColorClosestHWB
  12. gdImageColorExact
  13. gdImageColorExactAlpha
  14. gdImageColorAllocate
  15. gdImageColorAllocateAlpha
  16. gdImageColorResolve
  17. gdImageColorResolveAlpha
  18. gdImageColorDeallocate
  19. gdImageColorTransparent
  20. gdImagePaletteCopy
  21. clip_1d
  22. gdImageSetPixel
  23. gdImageGetTrueColorPixel
  24. gdImageBrushApply
  25. gdImageTileApply
  26. gdImageTileGet
  27. gdImageAntiAliasedApply
  28. gdImageGetPixel
  29. gdImageAABlend
  30. gdImageHLine
  31. gdImageVLine
  32. gdImageLine
  33. gdImageSetAAPixelColor
  34. gdImageAALine
  35. gdImageDashedLine
  36. dashedSet
  37. gdImageChar
  38. gdImageCharUp
  39. gdImageString
  40. gdImageStringUp
  41. gdImageString16
  42. gdImageStringUp16
  43. strlen16
  44. lsqrt
  45. gdImageArc
  46. gdImageFilledArc
  47. gdImageFillToBorder
  48. gdImageFill
  49. _gdImageFillTiled
  50. gdImageRectangle
  51. gdImageFilledRectangle
  52. gdImageCopy
  53. gdImageCopyMerge
  54. gdImageCopyMergeGray
  55. gdImageCopyResized
  56. gdImageCopyResampled
  57. gdImagePolygon
  58. gdImageFilledPolygon
  59. gdCompareInt
  60. gdImageSetStyle
  61. gdImageSetThickness
  62. gdImageSetBrush
  63. gdImageSetTile
  64. gdImageSetAntiAliased
  65. gdImageSetAntiAliasedDontBlend
  66. gdImageInterlace
  67. gdImageCompare
  68. gdAlphaBlendOld
  69. gdAlphaBlend
  70. gdImageAlphaBlending
  71. gdImageAntialias
  72. gdImageSaveAlpha
  73. gdLayerOverlay
  74. gdAlphaOverlayColor
  75. gdImageSetClip
  76. gdImageGetClip
  77. gdImagePaletteToTrueColor

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

/* [<][>][^][v][top][bottom][index][help] */