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

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