Back to index

php5  5.3.10
gd.c
Go to the documentation of this file.
00001 
00002 #include <math.h>
00003 #include <string.h>
00004 #include <stdlib.h>
00005 #include "gd.h"
00006 #include "gdhelpers.h"
00007 
00008 #include "php.h"
00009 
00010 #ifdef _MSC_VER
00011 # if _MSC_VER >= 1300
00012 /* in MSVC.NET these are available but only for __cplusplus and not _MSC_EXTENSIONS */
00013 #  if !defined(_MSC_EXTENSIONS) && defined(__cplusplus)
00014 #   define HAVE_FABSF 1
00015 extern float fabsf(float x);
00016 #   define HAVE_FLOORF 1
00017 extern float floorf(float x);
00018 #  endif /*MSVC.NET */
00019 # endif /* MSC */
00020 #endif
00021 #ifndef HAVE_FABSF
00022 # define HAVE_FABSF 0
00023 #endif
00024 #ifndef HAVE_FLOORF
00025 # define HAVE_FLOORF 0
00026 #endif
00027 #if HAVE_FABSF == 0
00028 /* float fabsf(float x); */
00029 # ifndef fabsf
00030 #  define fabsf(x) ((float)(fabs(x)))
00031 # endif
00032 #endif
00033 #if HAVE_FLOORF == 0
00034 # ifndef floorf
00035 /* float floorf(float x);*/
00036 #  define floorf(x) ((float)(floor(x)))
00037 # endif
00038 #endif
00039 
00040 #ifdef _OSD_POSIX           /* BS2000 uses the EBCDIC char set instead of ASCII */
00041 #define CHARSET_EBCDIC
00042 #define __attribute__(any)  /*nothing */
00043 #endif
00044 /*_OSD_POSIX*/
00045 
00046 #ifndef CHARSET_EBCDIC
00047 #define ASC(ch)  ch
00048 #else /*CHARSET_EBCDIC */
00049 #define ASC(ch) gd_toascii[(unsigned char)ch]
00050 static const unsigned char gd_toascii[256] =
00051 {
00052 /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
00053   0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,       /*................ */
00054 /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
00055   0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f,       /*................ */
00056 /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
00057   0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,       /*................ */
00058 /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
00059   0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,       /*................ */
00060 /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
00061   0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,       /* .........`.<(+| */
00062 /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
00063   0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f,       /*&.........!$*);. */
00064 /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
00065   0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
00066 /*-/........^,%_>?*/
00067 /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
00068   0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,       /*..........:#@'=" */
00069 /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
00070   0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1,       /*.abcdefghi...... */
00071 /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
00072   0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4,       /*.jklmnopqr...... */
00073 /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
00074   0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae,       /*..stuvwxyz...... */
00075 /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
00076   0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7,       /*...........[\].. */
00077 /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
00078   0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5,       /*.ABCDEFGHI...... */
00079 /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
00080   0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff,       /*.JKLMNOPQR...... */
00081 /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
00082   0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5,       /*..STUVWXYZ...... */
00083 /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
00084   0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */
00085 };
00086 #endif /*CHARSET_EBCDIC */
00087 
00088 /* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */
00089 #define floor_cast(exp) ((long) exp)
00090 
00091 extern int gdCosT[];
00092 extern int gdSinT[];
00093 
00094 static void gdImageBrushApply(gdImagePtr im, int x, int y);
00095 static void gdImageTileApply(gdImagePtr im, int x, int y);
00096 static void gdImageAntiAliasedApply(gdImagePtr im, int x, int y);
00097 static int gdLayerOverlay(int dst, int src);
00098 static int gdAlphaOverlayColor(int src, int dst, int max);
00099 int gdImageGetTrueColorPixel(gdImagePtr im, int x, int y);
00100 
00101 void php_gd_error_ex(int type, const char *format, ...)
00102 {
00103        va_list args;
00104 
00105        TSRMLS_FETCH();
00106 
00107        va_start(args, format);
00108        php_verror(NULL, "", type, format, args TSRMLS_CC);
00109        va_end(args);
00110 }
00111 
00112 void php_gd_error(const char *format, ...)
00113 {
00114        va_list args;
00115 
00116        TSRMLS_FETCH();
00117 
00118        va_start(args, format);
00119        php_verror(NULL, "", E_WARNING, format, args TSRMLS_CC);
00120        va_end(args);
00121 }
00122 
00123 gdImagePtr gdImageCreate (int sx, int sy)
00124 {
00125        int i;
00126        gdImagePtr im;
00127 
00128        if (overflow2(sx, sy)) {
00129               return NULL;
00130        }
00131 
00132        if (overflow2(sizeof(unsigned char *), sy)) {
00133               return NULL;
00134        }
00135 
00136        im = (gdImage *) gdCalloc(1, sizeof(gdImage));
00137 
00138        /* Row-major ever since gd 1.3 */
00139        im->pixels = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
00140        im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
00141        im->polyInts = 0;
00142        im->polyAllocated = 0;
00143        im->brush = 0;
00144        im->tile = 0;
00145        im->style = 0;
00146        for (i = 0; i < sy; i++) {
00147               /* Row-major ever since gd 1.3 */
00148               im->pixels[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
00149               im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
00150        }
00151        im->sx = sx;
00152        im->sy = sy;
00153        im->colorsTotal = 0;
00154        im->transparent = (-1);
00155        im->interlace = 0;
00156        im->thick = 1;
00157        im->AA = 0;
00158        im->AA_polygon = 0;
00159        for (i = 0; i < gdMaxColors; i++) {
00160               im->open[i] = 1;
00161               im->red[i] = 0;
00162               im->green[i] = 0;
00163               im->blue[i] = 0;
00164        }
00165        im->trueColor = 0;
00166        im->tpixels = 0;
00167        im->cx1 = 0;
00168        im->cy1 = 0;
00169        im->cx2 = im->sx - 1;
00170        im->cy2 = im->sy - 1;
00171        return im;
00172 }
00173 
00174 gdImagePtr gdImageCreateTrueColor (int sx, int sy)
00175 {
00176        int i;
00177        gdImagePtr im;
00178 
00179        if (overflow2(sx, sy)) {
00180               return NULL;
00181        }
00182 
00183        if (overflow2(sizeof(unsigned char *), sy)) {
00184               return NULL;
00185        }
00186        
00187        if (overflow2(sizeof(int), sx)) {
00188               return NULL;
00189        }
00190 
00191        im = (gdImage *) gdMalloc(sizeof(gdImage));
00192        memset(im, 0, sizeof(gdImage));
00193        im->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
00194        im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
00195        im->polyInts = 0;
00196        im->polyAllocated = 0;
00197        im->brush = 0;
00198        im->tile = 0;
00199        im->style = 0;
00200        for (i = 0; i < sy; i++) {
00201               im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
00202               im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
00203        }
00204        im->sx = sx;
00205        im->sy = sy;
00206        im->transparent = (-1);
00207        im->interlace = 0;
00208        im->trueColor = 1;
00209        /* 2.0.2: alpha blending is now on by default, and saving of alpha is
00210         * off by default. This allows font antialiasing to work as expected
00211         * on the first try in JPEGs -- quite important -- and also allows
00212         * for smaller PNGs when saving of alpha channel is not really
00213         * desired, which it usually isn't!
00214         */
00215        im->saveAlphaFlag = 0;
00216        im->alphaBlendingFlag = 1;
00217        im->thick = 1;
00218        im->AA = 0;
00219        im->AA_polygon = 0;
00220        im->cx1 = 0;
00221        im->cy1 = 0;
00222        im->cx2 = im->sx - 1;
00223        im->cy2 = im->sy - 1;
00224        return im;
00225 }
00226 
00227 void gdImageDestroy (gdImagePtr im)
00228 {
00229        int i;
00230        if (im->pixels) {
00231               for (i = 0; i < im->sy; i++) {
00232                      gdFree(im->pixels[i]);
00233               }
00234               gdFree(im->pixels);
00235        }
00236        if (im->tpixels) {
00237               for (i = 0; i < im->sy; i++) {
00238                      gdFree(im->tpixels[i]);
00239               }
00240               gdFree(im->tpixels);
00241        }
00242        if (im->AA_opacity) {
00243               for (i = 0; i < im->sy; i++) {
00244                      gdFree(im->AA_opacity[i]);
00245               }
00246               gdFree(im->AA_opacity);
00247        }
00248        if (im->polyInts) {
00249               gdFree(im->polyInts);
00250        }
00251        if (im->style) {
00252               gdFree(im->style);
00253        }
00254        gdFree(im);
00255 }
00256 
00257 int gdImageColorClosest (gdImagePtr im, int r, int g, int b)
00258 {
00259        return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
00260 }
00261 
00262 int gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
00263 {
00264        int i;
00265        long rd, gd, bd, ad;
00266        int ct = (-1);
00267        int first = 1;
00268        long mindist = 0;
00269 
00270        if (im->trueColor) {
00271               return gdTrueColorAlpha(r, g, b, a);
00272        }
00273        for (i = 0; i < im->colorsTotal; i++) {
00274               long dist;
00275               if (im->open[i]) {
00276                      continue;
00277               }
00278               rd = im->red[i] - r;
00279               gd = im->green[i] - g;
00280               bd = im->blue[i] - b;
00281               /* gd 2.02: whoops, was - b (thanks to David Marwood) */
00282               ad = im->alpha[i] - a;
00283               dist = rd * rd + gd * gd + bd * bd + ad * ad;
00284               if (first || (dist < mindist)) {
00285                      mindist = dist;
00286                      ct = i;
00287                      first = 0;
00288               }
00289        }
00290        return ct;
00291 }
00292 
00293 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
00294  * on colour conversion to/from RBG and HWB colour systems.
00295  * It has been modified to return the converted value as a * parameter.
00296  */
00297 
00298 #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
00299 #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
00300 #define HWB_UNDEFINED -1
00301 #define SETUP_RGB(s, r, g, b) {s.R = r/255.0f; s.G = g/255.0f; s.B = b/255.0f;}
00302 
00303 #ifndef MIN
00304 #define MIN(a,b) ((a)<(b)?(a):(b))
00305 #endif
00306 #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
00307 #ifndef MAX
00308 #define MAX(a,b) ((a)<(b)?(b):(a))
00309 #endif
00310 #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
00311 
00312 
00313 /*
00314  * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
00315  * red always maps to 6 in this implementation. Therefore UNDEFINED can be
00316  * defined as 0 in situations where only unsigned numbers are desired.
00317  */
00318 typedef struct
00319 {
00320        float R, G, B;
00321 }
00322 RGBType;
00323 typedef struct
00324 {
00325        float H, W, B;
00326 }
00327 HWBType;
00328 
00329 static HWBType * RGB_to_HWB (RGBType RGB, HWBType * HWB)
00330 {
00331        /*
00332         * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
00333         * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
00334         */
00335 
00336        float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
00337        int i;
00338 
00339        w = MIN3 (R, G, B);
00340        v = MAX3 (R, G, B);
00341        b = 1 - v;
00342        if (v == w) {
00343               RETURN_HWB(HWB_UNDEFINED, w, b);
00344        }
00345        f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
00346        i = (R == w) ? 3 : ((G == w) ? 5 : 1);
00347 
00348        RETURN_HWB(i - f / (v - w), w, b);
00349 }
00350 
00351 static float HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
00352 {
00353        RGBType RGB1, RGB2;
00354        HWBType HWB1, HWB2;
00355        float diff;
00356 
00357        SETUP_RGB(RGB1, r1, g1, b1);
00358        SETUP_RGB(RGB2, r2, g2, b2);
00359 
00360        RGB_to_HWB(RGB1, &HWB1);
00361        RGB_to_HWB(RGB2, &HWB2);
00362 
00363        /*
00364         * I made this bit up; it seems to produce OK results, and it is certainly
00365         * more visually correct than the current RGB metric. (PJW)
00366         */
00367 
00368        if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
00369               diff = 0.0f;  /* Undefined hues always match... */
00370        } else {
00371               diff = fabsf(HWB1.H - HWB2.H);
00372               if (diff > 3.0f) {
00373                      diff = 6.0f - diff;  /* Remember, it's a colour circle */
00374               }
00375        }
00376 
00377        diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
00378 
00379        return diff;
00380 }
00381 
00382 
00383 #if 0
00384 /*
00385  * This is not actually used, but is here for completeness, in case someone wants to
00386  * use the HWB stuff for anything else...
00387  */
00388 static RGBType * HWB_to_RGB (HWBType HWB, RGBType * RGB)
00389 {
00390        /*
00391         * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
00392         * RGB are each returned on [0, 1].
00393         */
00394 
00395        float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
00396        int i;
00397 
00398        v = 1 - b;
00399        if (h == HWB_UNDEFINED) {
00400               RETURN_RGB(v, v, v);
00401        }
00402        i = floor(h);
00403        f = h - i;
00404        if (i & 1) {
00405               f = 1 - f; /* if i is odd */
00406        }
00407        n = w + f * (v - w);        /* linear interpolation between w and v */
00408        switch (i) {
00409               case 6:
00410               case 0:
00411                      RETURN_RGB(v, n, w);
00412               case 1:
00413                      RETURN_RGB(n, v, w);
00414               case 2:
00415                      RETURN_RGB(w, v, n);
00416               case 3:
00417                      RETURN_RGB(w, n, v);
00418               case 4:
00419                      RETURN_RGB(n, w, v);
00420               case 5:
00421                      RETURN_RGB(v, w, n);
00422        }
00423 
00424        return RGB;
00425 }
00426 #endif
00427 
00428 int gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
00429 {
00430        int i;
00431        /* long rd, gd, bd; */
00432        int ct = (-1);
00433        int first = 1;
00434        float mindist = 0;
00435        if (im->trueColor) {
00436               return gdTrueColor(r, g, b);
00437        }
00438        for (i = 0; i < im->colorsTotal; i++) {
00439               float dist;
00440               if (im->open[i]) {
00441                      continue;
00442               }
00443               dist = HWB_Diff(im->red[i], im->green[i], im->blue[i], r, g, b);
00444               if (first || (dist < mindist)) {
00445                      mindist = dist;
00446                      ct = i;
00447                      first = 0;
00448               }
00449        }
00450        return ct;
00451 }
00452 
00453 int gdImageColorExact (gdImagePtr im, int r, int g, int b)
00454 {
00455        return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
00456 }
00457 
00458 int gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
00459 {
00460        int i;
00461        if (im->trueColor) {
00462               return gdTrueColorAlpha(r, g, b, a);
00463        }
00464        for (i = 0; i < im->colorsTotal; i++) {
00465               if (im->open[i]) {
00466                      continue;
00467               }
00468               if ((im->red[i] == r) && (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
00469                      return i;
00470               }
00471        }
00472        return -1;
00473 }
00474 
00475 int gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
00476 {
00477        return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
00478 }
00479 
00480 int gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
00481 {
00482        int i;
00483        int ct = (-1);
00484        if (im->trueColor) {
00485               return gdTrueColorAlpha(r, g, b, a);
00486        }
00487        for (i = 0; i < im->colorsTotal; i++) {
00488               if (im->open[i]) {
00489                      ct = i;
00490                      break;
00491               }
00492        }
00493        if (ct == (-1)) {
00494               ct = im->colorsTotal;
00495               if (ct == gdMaxColors) {
00496                      return -1;
00497               }
00498               im->colorsTotal++;
00499        }
00500        im->red[ct] = r;
00501        im->green[ct] = g;
00502        im->blue[ct] = b;
00503        im->alpha[ct] = a;
00504        im->open[ct] = 0;
00505 
00506        return ct;
00507 }
00508 
00509 /*
00510  * gdImageColorResolve is an alternative for the code fragment:
00511  *
00512  *      if ((color=gdImageColorExact(im,R,G,B)) < 0)
00513  *        if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
00514  *          color=gdImageColorClosest(im,R,G,B);
00515  *
00516  * in a single function.    Its advantage is that it is guaranteed to
00517  * return a color index in one search over the color table.
00518  */
00519 
00520 int gdImageColorResolve (gdImagePtr im, int r, int g, int b)
00521 {
00522        return gdImageColorResolveAlpha(im, r, g, b, gdAlphaOpaque);
00523 }
00524 
00525 int gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
00526 {
00527   int c;
00528   int ct = -1;
00529   int op = -1;
00530   long rd, gd, bd, ad, dist;
00531   long mindist = 4 * 255 * 255;    /* init to max poss dist */
00532   if (im->trueColor)
00533     {
00534       return gdTrueColorAlpha (r, g, b, a);
00535     }
00536 
00537   for (c = 0; c < im->colorsTotal; c++)
00538     {
00539       if (im->open[c])
00540        {
00541          op = c;            /* Save open slot */
00542          continue;          /* Color not in use */
00543        }
00544       if (c == im->transparent)
00545         {
00546           /* don't ever resolve to the color that has
00547            * been designated as the transparent color */
00548           continue;
00549        }
00550       rd = (long) (im->red[c] - r);
00551       gd = (long) (im->green[c] - g);
00552       bd = (long) (im->blue[c] - b);
00553       ad = (long) (im->alpha[c] - a);
00554       dist = rd * rd + gd * gd + bd * bd + ad * ad;
00555       if (dist < mindist)
00556        {
00557          if (dist == 0)
00558            {
00559              return c;             /* Return exact match color */
00560            }
00561          mindist = dist;
00562          ct = c;
00563        }
00564     }
00565   /* no exact match.  We now know closest, but first try to allocate exact */
00566   if (op == -1)
00567     {
00568       op = im->colorsTotal;
00569       if (op == gdMaxColors)
00570        {                    /* No room for more colors */
00571          return ct;         /* Return closest available color */
00572        }
00573       im->colorsTotal++;
00574     }
00575   im->red[op] = r;
00576   im->green[op] = g;
00577   im->blue[op] = b;
00578   im->alpha[op] = a;
00579   im->open[op] = 0;
00580   return op;                /* Return newly allocated color */
00581 }
00582 
00583 void gdImageColorDeallocate (gdImagePtr im, int color)
00584 {
00585        if (im->trueColor) {
00586               return;
00587        }
00588        /* Mark it open. */
00589        im->open[color] = 1;
00590 }
00591 
00592 void gdImageColorTransparent (gdImagePtr im, int color)
00593 {
00594        if (!im->trueColor) {
00595               if (im->transparent != -1) {
00596                      im->alpha[im->transparent] = gdAlphaOpaque;
00597               }
00598               if (color > -1 && color < im->colorsTotal && color < gdMaxColors) {
00599                      im->alpha[color] = gdAlphaTransparent;
00600               } else {
00601                      return;
00602               }
00603        }
00604        im->transparent = color;
00605 }
00606 
00607 void gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
00608 {
00609        int i;
00610        int x, y, p;
00611        int xlate[256];
00612        if (to->trueColor || from->trueColor) {
00613               return;
00614        }
00615 
00616        for (i = 0; i < 256; i++) {
00617               xlate[i] = -1;
00618        }
00619 
00620        for (y = 0; y < to->sy; y++) {
00621               for (x = 0; x < to->sx; x++) {
00622                      p = gdImageGetPixel(to, x, y);
00623                      if (xlate[p] == -1) {
00624                             /* This ought to use HWB, but we don't have an alpha-aware version of that yet. */
00625                             xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
00626                      }
00627                      gdImageSetPixel(to, x, y, xlate[p]);
00628               }
00629        }
00630 
00631        for (i = 0; i < from->colorsTotal; i++) {
00632               to->red[i] = from->red[i];
00633               to->blue[i] = from->blue[i];
00634               to->green[i] = from->green[i];
00635               to->alpha[i] = from->alpha[i];
00636               to->open[i] = 0;
00637        }
00638 
00639        for (i = from->colorsTotal; i < to->colorsTotal; i++) {
00640               to->open[i] = 1;
00641        }
00642 
00643        to->colorsTotal = from->colorsTotal;
00644 }
00645 
00646 /* 2.0.10: before the drawing routines, some code to clip points that are
00647  * outside the drawing window.  Nick Atty (nick@canalplan.org.uk)
00648  *
00649  * This is the Sutherland Hodgman Algorithm, as implemented by
00650  * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short.  See Dr Dobb's
00651  * Journal, January 1996, pp107-110 and 116-117
00652  *
00653  * Given the end points of a line, and a bounding rectangle (which we
00654  * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
00655  * the edges of the rectangle if the line should be drawn at all,
00656  * otherwise return a failure code
00657  */
00658 
00659 /* this does "one-dimensional" clipping: note that the second time it
00660  *  is called, all the x parameters refer to height and the y to width
00661  *  - the comments ignore this (if you can understand it when it's
00662  *  looking at the X parameters, it should become clear what happens on
00663  *  the second call!)  The code is simplified from that in the article,
00664  *  as we know that gd images always start at (0,0)
00665  */
00666 
00667 static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) {
00668        double m;      /* gradient of line */
00669 
00670        if (*x0 < 0) {  /* start of line is left of window */
00671               if(*x1 < 0) { /* as is the end, so the line never cuts the window */
00672                      return 0;
00673               }
00674               m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
00675               /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
00676               *y0 -= (int)(m * *x0);
00677               *x0 = 0;
00678               /* now, perhaps, adjust the far end of the line as well */
00679               if (*x1 > maxdim) {
00680                      *y1 += (int)(m * (maxdim - *x1));
00681                      *x1 = maxdim;
00682               }
00683               return 1;
00684        }
00685        if (*x0 > maxdim) { /* start of line is right of window - complement of above */
00686               if (*x1 > maxdim) { /* as is the end, so the line misses the window */
00687                      return 0;
00688               }
00689               m = (*y1 - *y0)/(double)(*x1 - *x0);  /* calculate the slope of the line */
00690               *y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right boundary */
00691               *x0 = maxdim;
00692               /* now, perhaps, adjust the end of the line */
00693               if (*x1 < 0) {
00694                      *y1 -= (int)(m * *x1);
00695                      *x1 = 0;
00696               }
00697               return 1;
00698        }
00699        /* the final case - the start of the line is inside the window */
00700        if (*x1 > maxdim) { /* other end is outside to the right */
00701               m = (*y1 - *y0)/(double)(*x1 - *x0);  /* calculate the slope of the line */
00702               *y1 += (int)(m * (maxdim - *x1));
00703               *x1 = maxdim;
00704               return 1;
00705        }
00706        if (*x1 < 0) { /* other end is outside to the left */
00707               m = (*y1 - *y0)/(double)(*x1 - *x0);  /* calculate the slope of the line */
00708               *y1 -= (int)(m * *x1);
00709               *x1 = 0;
00710               return 1;
00711        }
00712        /* only get here if both points are inside the window */
00713        return 1;
00714 }
00715 
00716 void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
00717 {
00718        int p;
00719        switch (color) {
00720               case gdStyled:
00721                      if (!im->style) {
00722                             /* Refuse to draw if no style is set. */
00723                             return;
00724                      } else {
00725                             p = im->style[im->stylePos++];
00726                      }
00727                      if (p != gdTransparent) {
00728                             gdImageSetPixel(im, x, y, p);
00729                      }
00730                      im->stylePos = im->stylePos % im->styleLength;
00731                      break;
00732               case gdStyledBrushed:
00733                      if (!im->style) {
00734                             /* Refuse to draw if no style is set. */
00735                             return;
00736                      }
00737                      p = im->style[im->stylePos++];
00738                      if (p != gdTransparent && p != 0) {
00739                             gdImageSetPixel(im, x, y, gdBrushed);
00740                      }
00741                      im->stylePos = im->stylePos % im->styleLength;
00742                      break;
00743               case gdBrushed:
00744                      gdImageBrushApply(im, x, y);
00745                      break;
00746               case gdTiled:
00747                      gdImageTileApply(im, x, y);
00748                      break;
00749               case gdAntiAliased:
00750                      gdImageAntiAliasedApply(im, x, y);
00751                      break;
00752               default:
00753                      if (gdImageBoundsSafe(im, x, y)) {
00754                             if (im->trueColor) {
00755                                    switch (im->alphaBlendingFlag) {
00756                                           default:
00757                                           case gdEffectReplace:
00758                                                  im->tpixels[y][x] = color;
00759                                                  break;
00760                                           case gdEffectAlphaBlend:
00761                                                  im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
00762                                                  break;
00763                                           case gdEffectNormal:
00764                                                  im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
00765                                                  break;
00766                                           case gdEffectOverlay :
00767                                                  im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
00768                                                  break;
00769                                    }
00770                             } else {
00771                                    im->pixels[y][x] = color;
00772                             }
00773                      }
00774                      break;
00775        }
00776 }
00777 
00778 int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
00779 {
00780        int p = gdImageGetPixel(im, x, y);
00781 
00782        if (!im->trueColor)  {
00783               return gdTrueColorAlpha(im->red[p], im->green[p], im->blue[p], (im->transparent == p) ? gdAlphaTransparent : im->alpha[p]);
00784        } else {
00785               return p;
00786        }
00787 }
00788 
00789 static void gdImageBrushApply (gdImagePtr im, int x, int y)
00790 {
00791        int lx, ly;
00792        int hy, hx;
00793        int x1, y1, x2, y2;
00794        int srcx, srcy;
00795 
00796        if (!im->brush) {
00797               return;
00798        }
00799 
00800        hy = gdImageSY(im->brush) / 2;
00801        y1 = y - hy;
00802        y2 = y1 + gdImageSY(im->brush);
00803        hx = gdImageSX(im->brush) / 2;
00804        x1 = x - hx;
00805        x2 = x1 + gdImageSX(im->brush);
00806        srcy = 0;
00807 
00808        if (im->trueColor) {
00809               if (im->brush->trueColor) {
00810                      for (ly = y1; ly < y2; ly++) {
00811                             srcx = 0;
00812                             for (lx = x1; (lx < x2); lx++) {
00813                                    int p;
00814                                    p = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
00815                                    /* 2.0.9, Thomas Winzig: apply simple full transparency */
00816                                    if (p != gdImageGetTransparent(im->brush)) {
00817                                           gdImageSetPixel(im, lx, ly, p);
00818                                    }
00819                                    srcx++;
00820                             }
00821                             srcy++;
00822                      }
00823               } else {
00824                      /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger for pointing out the issue) */
00825                      for (ly = y1; ly < y2; ly++) {
00826                             srcx = 0;
00827                             for (lx = x1; lx < x2; lx++) {
00828                                    int p, tc;
00829                                    p = gdImageGetPixel(im->brush, srcx, srcy);
00830                                    tc = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
00831                                    /* 2.0.9, Thomas Winzig: apply simple full transparency */
00832                                    if (p != gdImageGetTransparent(im->brush)) {
00833                                           gdImageSetPixel(im, lx, ly, tc);
00834                                    }
00835                                    srcx++;
00836                             }
00837                             srcy++;
00838                      }
00839               }
00840        } else {
00841               for (ly = y1; ly < y2; ly++) {
00842                      srcx = 0;
00843                      for (lx = x1; lx < x2; lx++) {
00844                             int p;
00845                             p = gdImageGetPixel(im->brush, srcx, srcy);
00846                             /* Allow for non-square brushes! */
00847                             if (p != gdImageGetTransparent(im->brush)) {
00848                                    /* Truecolor brush. Very slow on a palette destination. */
00849                                    if (im->brush->trueColor) {
00850                                           gdImageSetPixel(im, lx, ly, gdImageColorResolveAlpha(im, gdTrueColorGetRed(p),
00851                                                                                             gdTrueColorGetGreen(p),
00852                                                                                             gdTrueColorGetBlue(p),
00853                                                                                             gdTrueColorGetAlpha(p)));
00854                                    } else {
00855                                           gdImageSetPixel(im, lx, ly, im->brushColorMap[p]);
00856                                    }
00857                             }
00858                             srcx++;
00859                      }
00860                      srcy++;
00861               }
00862        }
00863 }
00864 
00865 static void gdImageTileApply (gdImagePtr im, int x, int y)
00866 {
00867        gdImagePtr tile = im->tile;
00868        int srcx, srcy;
00869        int p;
00870        if (!tile) {
00871               return;
00872        }
00873        srcx = x % gdImageSX(tile);
00874        srcy = y % gdImageSY(tile);
00875        if (im->trueColor) {
00876               p = gdImageGetPixel(tile, srcx, srcy);
00877               if (p != gdImageGetTransparent (tile)) {
00878                      if (!tile->trueColor) {
00879                             p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]);
00880                      }
00881                      gdImageSetPixel(im, x, y, p);
00882               }
00883        } else {
00884               p = gdImageGetPixel(tile, srcx, srcy);
00885               /* Allow for transparency */
00886               if (p != gdImageGetTransparent(tile)) {
00887                      if (tile->trueColor) {
00888                             /* Truecolor tile. Very slow on a palette destination. */
00889                             gdImageSetPixel(im, x, y, gdImageColorResolveAlpha(im,
00890                                                                              gdTrueColorGetRed(p),
00891                                                                              gdTrueColorGetGreen(p),
00892                                                                              gdTrueColorGetBlue(p),
00893                                                                              gdTrueColorGetAlpha(p)));
00894                      } else {
00895                             gdImageSetPixel(im, x, y, im->tileColorMap[p]);
00896                      }
00897               }
00898        }
00899 }
00900 
00901 
00902 static int gdImageTileGet (gdImagePtr im, int x, int y)
00903 {
00904        int srcx, srcy;
00905        int tileColor,p;
00906        if (!im->tile) {
00907               return -1;
00908        }
00909        srcx = x % gdImageSX(im->tile);
00910        srcy = y % gdImageSY(im->tile);
00911        p = gdImageGetPixel(im->tile, srcx, srcy);
00912 
00913        if (im->trueColor) {
00914               if (im->tile->trueColor) {
00915                      tileColor = p;
00916               } else {
00917                      tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
00918               }
00919        } else {
00920               if (im->tile->trueColor) {
00921                      tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
00922               } else {
00923                      tileColor = p;
00924                      tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
00925               }
00926        }
00927        return tileColor;
00928 }
00929 
00930 
00931 static void gdImageAntiAliasedApply (gdImagePtr im, int px, int py)
00932 {
00933        float p_dist, p_alpha;
00934        unsigned char opacity;
00935 
00936        /*
00937         * Find the perpendicular distance from point C (px, py) to the line
00938         * segment AB that is being drawn.  (Adapted from an algorithm from the
00939         * comp.graphics.algorithms FAQ.)
00940         */
00941 
00942        int LAC_2, LBC_2;
00943 
00944        int Ax_Cx = im->AAL_x1 - px;
00945        int Ay_Cy = im->AAL_y1 - py;
00946 
00947        int Bx_Cx = im->AAL_x2 - px;
00948        int By_Cy = im->AAL_y2 - py;
00949 
00950        /* 2.0.13: bounds check! AA_opacity is just as capable of
00951         * overflowing as the main pixel array. Arne Jorgensen.
00952         * 2.0.14: typo fixed. 2.0.15: moved down below declarations
00953         * to satisfy non-C++ compilers.
00954         */
00955        if (!gdImageBoundsSafe(im, px, py)) {
00956               return;
00957        }
00958 
00959        /* Get the squares of the lengths of the segemnts AC and BC. */
00960        LAC_2 = (Ax_Cx * Ax_Cx) + (Ay_Cy * Ay_Cy);
00961        LBC_2 = (Bx_Cx * Bx_Cx) + (By_Cy * By_Cy);
00962 
00963        if (((im->AAL_LAB_2 + LAC_2) >= LBC_2) && ((im->AAL_LAB_2 + LBC_2) >= LAC_2)) {
00964               /* The two angles are acute.  The point lies inside the portion of the
00965                * plane spanned by the line segment.
00966                */
00967               p_dist = fabs ((float) ((Ay_Cy * im->AAL_Bx_Ax) - (Ax_Cx * im->AAL_By_Ay)) / im->AAL_LAB);
00968        } else {
00969               /* The point is past an end of the line segment.  It's length from the
00970                * segment is the shorter of the lengths from the endpoints, but call
00971                * the distance -1, so as not to compute the alpha nor draw the pixel.
00972                */
00973               p_dist = -1;
00974        }
00975 
00976        if ((p_dist >= 0) && (p_dist <= (float) (im->thick))) {
00977               p_alpha = pow (1.0 - (p_dist / 1.5), 2);
00978 
00979               if (p_alpha > 0) {
00980                      if (p_alpha >= 1) {
00981                             opacity = 255;
00982                      } else {
00983                             opacity = (unsigned char) (p_alpha * 255.0);
00984                      }
00985                      if (!im->AA_polygon || (im->AA_opacity[py][px] < opacity)) {
00986                             im->AA_opacity[py][px] = opacity;
00987                      }
00988               }
00989        }
00990 }
00991 
00992 
00993 int gdImageGetPixel (gdImagePtr im, int x, int y)
00994 {
00995        if (gdImageBoundsSafe(im, x, y)) {
00996               if (im->trueColor) {
00997                      return im->tpixels[y][x];
00998               } else {
00999                      return im->pixels[y][x];
01000               }
01001        } else {
01002               return 0;
01003        }
01004 }
01005 
01006 void gdImageAABlend (gdImagePtr im)
01007 {
01008        float p_alpha, old_alpha;
01009        int color = im->AA_color, color_red, color_green, color_blue;
01010        int old_color, old_red, old_green, old_blue;
01011        int p_color, p_red, p_green, p_blue;
01012        int px, py;
01013 
01014        color_red = gdImageRed(im, color);
01015        color_green = gdImageGreen(im, color);
01016        color_blue = gdImageBlue(im, color);
01017 
01018        /* Impose the anti-aliased drawing on the image. */
01019        for (py = 0; py < im->sy; py++) {
01020               for (px = 0; px < im->sx; px++) {
01021                      if (im->AA_opacity[py][px] != 0) {
01022                             old_color = gdImageGetPixel(im, px, py);
01023 
01024                             if ((old_color != color) && ((old_color != im->AA_dont_blend) || (im->AA_opacity[py][px] == 255))) {
01025                                    /* Only blend with different colors that aren't the dont_blend color. */
01026                                    p_alpha = (float) (im->AA_opacity[py][px]) / 255.0;
01027                                    old_alpha = 1.0 - p_alpha;
01028 
01029                                    if (p_alpha >= 1.0) {
01030                                           p_color = color;
01031                                    } else {
01032                                           old_red = gdImageRed(im, old_color);
01033                                           old_green = gdImageGreen(im, old_color);
01034                                           old_blue = gdImageBlue(im, old_color);
01035 
01036                                           p_red = (int) (((float) color_red * p_alpha) + ((float) old_red * old_alpha));
01037                                           p_green = (int) (((float) color_green * p_alpha) + ((float) old_green * old_alpha));
01038                                           p_blue = (int) (((float) color_blue * p_alpha) + ((float) old_blue * old_alpha));
01039                                           p_color = gdImageColorResolve(im, p_red, p_green, p_blue);
01040                                    }
01041                                    gdImageSetPixel(im, px, py, p_color);
01042                             }
01043                      }
01044               }
01045               /* Clear the AA_opacity array behind us. */
01046               memset(im->AA_opacity[py], 0, im->sx);
01047        }
01048 }
01049 
01050 static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
01051 {
01052        if (im->thick > 1) {
01053               int thickhalf = im->thick >> 1;
01054               gdImageFilledRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
01055        } else {
01056               if (x2 < x1) {
01057                      int t = x2;
01058                      x2 = x1;
01059                      x1 = t;
01060               }
01061 
01062               for (;x1 <= x2; x1++) {
01063                      gdImageSetPixel(im, x1, y, col);
01064               }
01065        }
01066        return;
01067 }
01068 
01069 static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
01070 {
01071        if (im->thick > 1) {
01072               int thickhalf = im->thick >> 1;
01073               gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
01074        } else {
01075               if (y2 < y1) {
01076                      int t = y1;
01077                      y1 = y2;
01078                      y2 = t;
01079               }
01080 
01081               for (;y1 <= y2; y1++) {
01082                      gdImageSetPixel(im, x, y1, col);
01083               }
01084        }
01085        return;
01086 }
01087 
01088 /* Bresenham as presented in Foley & Van Dam */
01089 void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
01090 {
01091        int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
01092        int wid;
01093        int w, wstart;
01094        int thick = im->thick;
01095 
01096        if (color == gdAntiAliased) {
01097               /* 
01098                  gdAntiAliased passed as color: use the much faster, much cheaper
01099                  and equally attractive gdImageAALine implementation. That
01100                  clips too, so don't clip twice.
01101                  */
01102               gdImageAALine(im, x1, y1, x2, y2, im->AA_color); 
01103               return;
01104        }
01105 
01106        /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
01107        if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im))) {
01108               return;
01109        }
01110 
01111        dx = abs (x2 - x1);
01112        dy = abs (y2 - y1);
01113 
01114        if (dx == 0) {
01115               gdImageVLine(im, x1, y1, y2, color);
01116               return;
01117        } else if (dy == 0) {
01118               gdImageHLine(im, y1, x1, x2, color);
01119               return;
01120        }
01121 
01122        if (dy <= dx) {
01123               /* More-or-less horizontal. use wid for vertical stroke */
01124               /* Doug Claar: watch out for NaN in atan2 (2.0.5) */
01125               if ((dx == 0) && (dy == 0)) {
01126                      wid = 1;
01127               } else {
01128                      /* 2.0.12: Michael Schwartz: divide rather than multiply;
01129 TBB: but watch out for /0! */
01130                      double ac = cos (atan2 (dy, dx));
01131                      if (ac != 0) {
01132                             wid = thick / ac;
01133                      } else {
01134                             wid = 1;
01135                      }
01136                      if (wid == 0) {
01137                             wid = 1;
01138                      }
01139               }
01140               d = 2 * dy - dx;
01141               incr1 = 2 * dy;
01142               incr2 = 2 * (dy - dx);
01143               if (x1 > x2) {
01144                      x = x2;
01145                      y = y2;
01146                      ydirflag = (-1);
01147                      xend = x1;
01148               } else {
01149                      x = x1;
01150                      y = y1;
01151                      ydirflag = 1;
01152                      xend = x2;
01153               }
01154 
01155               /* Set up line thickness */
01156               wstart = y - wid / 2;
01157               for (w = wstart; w < wstart + wid; w++) {
01158                      gdImageSetPixel(im, x, w, color);
01159               }
01160 
01161               if (((y2 - y1) * ydirflag) > 0) {
01162                      while (x < xend) {
01163                             x++;
01164                             if (d < 0) {
01165                                    d += incr1;
01166                             } else {
01167                                    y++;
01168                                    d += incr2;
01169                             }
01170                             wstart = y - wid / 2;
01171                             for (w = wstart; w < wstart + wid; w++) {
01172                                    gdImageSetPixel (im, x, w, color);
01173                             }
01174                      }
01175               } else {
01176                      while (x < xend) {
01177                             x++;
01178                             if (d < 0) {
01179                                    d += incr1;
01180                             } else {
01181                                    y--;
01182                                    d += incr2;
01183                             }
01184                             wstart = y - wid / 2;
01185                             for (w = wstart; w < wstart + wid; w++) {
01186                                    gdImageSetPixel (im, x, w, color);
01187                             }
01188                      }
01189               }
01190        } else {
01191               /* More-or-less vertical. use wid for horizontal stroke */
01192               /* 2.0.12: Michael Schwartz: divide rather than multiply;
01193                  TBB: but watch out for /0! */
01194               double as = sin (atan2 (dy, dx));
01195               if (as != 0) {
01196                      wid = thick / as;
01197               } else {
01198                      wid = 1;
01199               }
01200               if (wid == 0) {
01201                      wid = 1;
01202               }
01203 
01204               d = 2 * dx - dy;
01205               incr1 = 2 * dx;
01206               incr2 = 2 * (dx - dy);
01207               if (y1 > y2) {
01208                      y = y2;
01209                      x = x2;
01210                      yend = y1;
01211                      xdirflag = (-1);
01212               } else {
01213                      y = y1;
01214                      x = x1;
01215                      yend = y2;
01216                      xdirflag = 1;
01217               }
01218 
01219               /* Set up line thickness */
01220               wstart = x - wid / 2;
01221               for (w = wstart; w < wstart + wid; w++) {
01222                      gdImageSetPixel (im, w, y, color);
01223               }
01224 
01225               if (((x2 - x1) * xdirflag) > 0) {
01226                      while (y < yend) {
01227                             y++;
01228                             if (d < 0) {
01229                                    d += incr1;
01230                             } else {
01231                                    x++;
01232                                    d += incr2;
01233                             }
01234                             wstart = x - wid / 2;
01235                             for (w = wstart; w < wstart + wid; w++) {
01236                                    gdImageSetPixel (im, w, y, color);
01237                             }
01238                      }
01239               } else {
01240                      while (y < yend) {
01241                             y++;
01242                             if (d < 0) {
01243                                    d += incr1;
01244                             } else {
01245                                    x--;
01246                                    d += incr2;
01247                             }
01248                             wstart = x - wid / 2;
01249                             for (w = wstart; w < wstart + wid; w++) {
01250                                    gdImageSetPixel (im, w, y, color);
01251                             }
01252                      }
01253               }
01254        }
01255 }
01256 
01257 
01258 /*
01259  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
01260  * */
01261 #define BLEND_COLOR(a, nc, c, cc) \
01262 nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
01263 
01264 inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
01265 {
01266        int dr,dg,db,p,r,g,b;
01267        dr = gdTrueColorGetRed(color);
01268        dg = gdTrueColorGetGreen(color);
01269        db = gdTrueColorGetBlue(color);
01270 
01271        p = gdImageGetPixel(im,x,y);
01272        r = gdTrueColorGetRed(p);
01273        g = gdTrueColorGetGreen(p);
01274        b = gdTrueColorGetBlue(p);
01275 
01276        BLEND_COLOR(t, dr, r, dr);
01277        BLEND_COLOR(t, dg, g, dg);
01278        BLEND_COLOR(t, db, b, db);
01279        im->tpixels[y][x]=gdTrueColorAlpha(dr, dg, db,  gdAlphaOpaque);
01280 }
01281 
01282 /*
01283  * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
01284  **/
01285 void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
01286 {
01287        /* keep them as 32bits */
01288        long x, y, inc;
01289        long dx, dy,tmp;
01290 
01291        if (y1 < 0 && y2 < 0) {
01292               return;
01293        }
01294        if (y1 < 0) {
01295               x1 += (y1 * (x1 - x2)) / (y2 - y1);
01296               y1 = 0;
01297        }
01298        if (y2 < 0) {
01299               x2 += (y2 * (x1 - x2)) / (y2 - y1);
01300               y2 = 0;
01301        }
01302 
01303        /* bottom edge */
01304        if (y1 >= im->sy && y2 >= im->sy) {
01305               return;
01306        }
01307        if (y1 >= im->sy) {
01308               x1 -= ((im->sy - y1) * (x1 - x2)) / (y2 - y1);
01309               y1 = im->sy - 1;
01310        }
01311        if (y2 >= im->sy) {
01312               x2 -= ((im->sy - y2) * (x1 - x2)) / (y2 - y1);
01313               y2 = im->sy - 1;
01314        }
01315 
01316        /* left edge */
01317        if (x1 < 0 && x2 < 0) {
01318               return;
01319        }
01320        if (x1 < 0) {
01321               y1 += (x1 * (y1 - y2)) / (x2 - x1);
01322               x1 = 0;
01323        }
01324        if (x2 < 0) {
01325               y2 += (x2 * (y1 - y2)) / (x2 - x1);
01326               x2 = 0;
01327        }
01328        /* right edge */
01329        if (x1 >= im->sx && x2 >= im->sx) {
01330               return;
01331        }
01332        if (x1 >= im->sx) {
01333               y1 -= ((im->sx - x1) * (y1 - y2)) / (x2 - x1);
01334               x1 = im->sx - 1;
01335        }
01336        if (x2 >= im->sx) {
01337               y2 -= ((im->sx - x2) * (y1 - y2)) / (x2 - x1);
01338               x2 = im->sx - 1;
01339        }
01340 
01341        dx = x2 - x1;
01342        dy = y2 - y1;
01343 
01344        if (dx == 0 && dy == 0) {
01345               return;
01346        }
01347        if (abs(dx) > abs(dy)) {
01348               if (dx < 0) {
01349                      tmp = x1;
01350                      x1 = x2;
01351                      x2 = tmp;
01352                      tmp = y1;
01353                      y1 = y2;
01354                      y2 = tmp;
01355                      dx = x2 - x1;
01356                      dy = y2 - y1;
01357               }
01358               x = x1 << 16;
01359               y = y1 << 16;
01360               inc = (dy * 65536) / dx;
01361               while ((x >> 16) <= x2) {
01362                      gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (y >> 8) & 0xFF);
01363                      if ((y >> 16) + 1 < im->sy) {
01364                             gdImageSetAAPixelColor(im, x >> 16, (y >> 16) + 1,col, (~y >> 8) & 0xFF);
01365                      }
01366                      x += (1 << 16);
01367                      y += inc;
01368               }
01369        } else {
01370               if (dy < 0) {
01371                      tmp = x1;
01372                      x1 = x2;
01373                      x2 = tmp;
01374                      tmp = y1;
01375                      y1 = y2;
01376                      y2 = tmp;
01377                      dx = x2 - x1;
01378                      dy = y2 - y1;
01379               }
01380               x = x1 << 16;
01381               y = y1 << 16;
01382               inc = (dx * 65536) / dy;
01383               while ((y>>16) <= y2) {
01384                      gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (x >> 8) & 0xFF);
01385                      if ((x >> 16) + 1 < im->sx) {
01386                             gdImageSetAAPixelColor(im, (x >> 16) + 1, (y >> 16),col, (~x >> 8) & 0xFF);
01387                      }
01388                      x += inc;
01389                      y += (1<<16);
01390               }
01391        }
01392 }
01393 
01394 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert);
01395 
01396 void gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
01397 {
01398        int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
01399        int dashStep = 0;
01400        int on = 1;
01401        int wid;
01402        int vert;
01403        int thick = im->thick;
01404 
01405        dx = abs(x2 - x1);
01406        dy = abs(y2 - y1);
01407        if (dy <= dx) {
01408               /* More-or-less horizontal. use wid for vertical stroke */
01409               /* 2.0.12: Michael Schwartz: divide rather than multiply;
01410               TBB: but watch out for /0! */
01411               double as = sin(atan2(dy, dx));
01412               if (as != 0) {
01413                      wid = thick / as;
01414               } else {
01415                      wid = 1;
01416               }
01417               wid = (int)(thick * sin(atan2(dy, dx)));
01418               vert = 1;
01419 
01420               d = 2 * dy - dx;
01421               incr1 = 2 * dy;
01422               incr2 = 2 * (dy - dx);
01423               if (x1 > x2) {
01424                      x = x2;
01425                      y = y2;
01426                      ydirflag = (-1);
01427                      xend = x1;
01428               } else {
01429                      x = x1;
01430                      y = y1;
01431                      ydirflag = 1;
01432                      xend = x2;
01433               }
01434               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
01435               if (((y2 - y1) * ydirflag) > 0) {
01436                      while (x < xend) {
01437                             x++;
01438                             if (d < 0) {
01439                                    d += incr1;
01440                             } else {
01441                                    y++;
01442                                    d += incr2;
01443                             }
01444                             dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
01445                      }
01446               } else {
01447                      while (x < xend) {
01448                             x++;
01449                             if (d < 0) {
01450                                    d += incr1;
01451                             } else {
01452                                    y--;
01453                                    d += incr2;
01454                             }
01455                             dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
01456                      }
01457               }
01458        } else {
01459               /* 2.0.12: Michael Schwartz: divide rather than multiply;
01460               TBB: but watch out for /0! */
01461               double as = sin (atan2 (dy, dx));
01462               if (as != 0) {
01463                      wid = thick / as;
01464               } else {
01465                      wid = 1;
01466               }
01467               vert = 0;
01468 
01469               d = 2 * dx - dy;
01470               incr1 = 2 * dx;
01471               incr2 = 2 * (dx - dy);
01472               if (y1 > y2) {
01473                      y = y2;
01474                      x = x2;
01475                      yend = y1;
01476                      xdirflag = (-1);
01477               } else {
01478                      y = y1;
01479                      x = x1;
01480                      yend = y2;
01481                      xdirflag = 1;
01482               }
01483               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
01484               if (((x2 - x1) * xdirflag) > 0) {
01485                      while (y < yend) {
01486                             y++;
01487                             if (d < 0) {
01488                                    d += incr1;
01489                             } else {
01490                                    x++;
01491                                    d += incr2;
01492                             }
01493                             dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
01494                      }
01495               } else {
01496                      while (y < yend) {
01497                             y++;
01498                             if (d < 0) {
01499                                    d += incr1;
01500                             } else {
01501                                    x--;
01502                                    d += incr2;
01503                             }
01504                             dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
01505                      }
01506               }
01507        }
01508 }
01509 
01510 static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert)
01511 {
01512        int dashStep = *dashStepP;
01513        int on = *onP;
01514        int w, wstart;
01515 
01516        dashStep++;
01517        if (dashStep == gdDashSize) {
01518               dashStep = 0;
01519               on = !on;
01520        }
01521        if (on) {
01522               if (vert) {
01523                      wstart = y - wid / 2;
01524                      for (w = wstart; w < wstart + wid; w++) {
01525                             gdImageSetPixel(im, x, w, color);
01526                      }
01527               } else {
01528                      wstart = x - wid / 2;
01529                      for (w = wstart; w < wstart + wid; w++) {
01530                             gdImageSetPixel(im, w, y, color);
01531                      }
01532               }
01533        }
01534        *dashStepP = dashStep;
01535        *onP = on;
01536 }
01537 
01538 void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
01539 {
01540        int cx, cy;
01541        int px, py;
01542        int fline;
01543        cx = 0;
01544        cy = 0;
01545 #ifdef CHARSET_EBCDIC
01546        c = ASC (c);
01547 #endif /*CHARSET_EBCDIC */
01548        if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
01549               return;
01550        }
01551        fline = (c - f->offset) * f->h * f->w;
01552        for (py = y; (py < (y + f->h)); py++) {
01553               for (px = x; (px < (x + f->w)); px++) {
01554                      if (f->data[fline + cy * f->w + cx]) {
01555                             gdImageSetPixel(im, px, py, color);
01556                      }
01557                      cx++;
01558               }
01559               cx = 0;
01560               cy++;
01561        }
01562 }
01563 
01564 void gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
01565 {
01566        int cx, cy;
01567        int px, py;
01568        int fline;
01569        cx = 0;
01570        cy = 0;
01571 #ifdef CHARSET_EBCDIC
01572        c = ASC (c);
01573 #endif /*CHARSET_EBCDIC */
01574        if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
01575               return;
01576        }
01577        fline = (c - f->offset) * f->h * f->w;
01578        for (py = y; py > (y - f->w); py--) {
01579               for (px = x; px < (x + f->h); px++) {
01580                      if (f->data[fline + cy * f->w + cx]) {
01581                             gdImageSetPixel(im, px, py, color);
01582                      }
01583                      cy++;
01584               }
01585               cy = 0;
01586               cx++;
01587        }
01588 }
01589 
01590 void gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
01591 {
01592        int i;
01593        int l;
01594        l = strlen ((char *) s);
01595        for (i = 0; (i < l); i++) {
01596               gdImageChar(im, f, x, y, s[i], color);
01597               x += f->w;
01598        }
01599 }
01600 
01601 void gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
01602 {
01603        int i;
01604        int l;
01605        l = strlen ((char *) s);
01606        for (i = 0; (i < l); i++) {
01607               gdImageCharUp(im, f, x, y, s[i], color);
01608               y -= f->w;
01609        }
01610 }
01611 
01612 static int strlen16 (unsigned short *s);
01613 
01614 void gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
01615 {
01616        int i;
01617        int l;
01618        l = strlen16(s);
01619        for (i = 0; (i < l); i++) {
01620               gdImageChar(im, f, x, y, s[i], color);
01621               x += f->w;
01622        }
01623 }
01624 
01625 void gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
01626 {
01627        int i;
01628        int l;
01629        l = strlen16(s);
01630        for (i = 0; i < l; i++) {
01631               gdImageCharUp(im, f, x, y, s[i], color);
01632               y -= f->w;
01633        }
01634 }
01635 
01636 static int strlen16 (unsigned short *s)
01637 {
01638        int len = 0;
01639        while (*s) {
01640               s++;
01641               len++;
01642        }
01643        return len;
01644 }
01645 
01646 #ifndef HAVE_LSQRT
01647 /* If you don't have a nice square root function for longs, you can use
01648    ** this hack
01649  */
01650 long lsqrt (long n)
01651 {
01652        long result = (long) sqrt ((double) n);
01653        return result;
01654 }
01655 #endif
01656 
01657 /* s and e are integers modulo 360 (degrees), with 0 degrees
01658    being the rightmost extreme and degrees changing clockwise.
01659    cx and cy are the center in pixels; w and h are the horizontal
01660    and vertical diameter in pixels. Nice interface, but slow.
01661    See gd_arc_f_buggy.c for a better version that doesn't
01662    seem to be bug-free yet. */
01663 
01664 void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
01665 {
01666        if ((s % 360) == (e % 360)) {
01667               gdImageEllipse(im, cx, cy, w, h, color);
01668        } else {
01669               gdImageFilledArc(im, cx, cy, w, h, s, e, color, gdNoFill);
01670        }
01671 }
01672 
01673 void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
01674 {
01675        gdPoint pts[3];
01676        int i;
01677        int lx = 0, ly = 0;
01678        int fx = 0, fy = 0;
01679 
01680 
01681     if ((s % 360)  == (e % 360)) {
01682               s = 0; e = 360;
01683        } else {
01684               if (s > 360) {
01685                      s = s % 360;
01686               }
01687 
01688               if (e > 360) {
01689                      e = e % 360;
01690               }
01691 
01692               while (s < 0) {
01693                      s += 360;
01694               }
01695 
01696               while (e < s) {
01697                      e += 360;
01698               }
01699               if (s == e) {
01700                      s = 0; e = 360;
01701               }
01702        }
01703 
01704        for (i = s; i <= e; i++) {
01705               int x, y;
01706               x = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
01707               y = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
01708               if (i != s) {
01709                      if (!(style & gdChord)) {
01710                             if (style & gdNoFill) {
01711                                    gdImageLine(im, lx, ly, x, y, color);
01712                             } else {
01713                                    /* This is expensive! */
01714                                    pts[0].x = lx;
01715                                    pts[0].y = ly;
01716                                    pts[1].x = x;
01717                                    pts[1].y = y;
01718                                    pts[2].x = cx;
01719                                    pts[2].y = cy;
01720                                    gdImageFilledPolygon(im, pts, 3, color);
01721                             }
01722                      }
01723               } else {
01724                      fx = x;
01725                      fy = y;
01726               }
01727               lx = x;
01728               ly = y;
01729        }
01730        if (style & gdChord) {
01731               if (style & gdNoFill) {
01732                      if (style & gdEdged) {
01733                             gdImageLine(im, cx, cy, lx, ly, color);
01734                             gdImageLine(im, cx, cy, fx, fy, color);
01735                      }
01736                      gdImageLine(im, fx, fy, lx, ly, color);
01737               } else {
01738                      pts[0].x = fx;
01739                      pts[0].y = fy;
01740                      pts[1].x = lx;
01741                      pts[1].y = ly;
01742                      pts[2].x = cx;
01743                      pts[2].y = cy;
01744                      gdImageFilledPolygon(im, pts, 3, color);
01745               }
01746        } else {
01747               if (style & gdNoFill) {
01748                      if (style & gdEdged) {
01749                             gdImageLine(im, cx, cy, lx, ly, color);
01750                             gdImageLine(im, cx, cy, fx, fy, color);
01751                      }
01752               }
01753        }
01754 }
01755 
01756 void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
01757 {
01758        int lastBorder;
01759        /* Seek left */
01760        int leftLimit = -1, rightLimit;
01761        int i, restoreAlphaBlending = 0;
01762 
01763        if (border < 0) {
01764               /* Refuse to fill to a non-solid border */
01765               return;
01766        }
01767 
01768        restoreAlphaBlending = im->alphaBlendingFlag;
01769        im->alphaBlendingFlag = 0;
01770 
01771        if (x >= im->sx) {
01772               x = im->sx - 1;
01773        }
01774        if (y >= im->sy) {
01775               y = im->sy - 1;
01776        }
01777 
01778        for (i = x; i >= 0; i--) {
01779               if (gdImageGetPixel(im, i, y) == border) {
01780                      break;
01781               }
01782               gdImageSetPixel(im, i, y, color);
01783               leftLimit = i;
01784        }
01785        if (leftLimit == -1) {
01786               im->alphaBlendingFlag = restoreAlphaBlending;
01787               return;
01788        }
01789        /* Seek right */
01790        rightLimit = x;
01791        for (i = (x + 1); i < im->sx; i++) {
01792               if (gdImageGetPixel(im, i, y) == border) {
01793                      break;
01794               }
01795               gdImageSetPixel(im, i, y, color);
01796               rightLimit = i;
01797        }
01798        /* Look at lines above and below and start paints */
01799        /* Above */
01800        if (y > 0) {
01801               lastBorder = 1;
01802               for (i = leftLimit; i <= rightLimit; i++) {
01803                      int c = gdImageGetPixel(im, i, y - 1);
01804                      if (lastBorder) {
01805                             if ((c != border) && (c != color)) {
01806                                    gdImageFillToBorder(im, i, y - 1, border, color);
01807                                    lastBorder = 0;
01808                             }
01809                      } else if ((c == border) || (c == color)) {
01810                             lastBorder = 1;
01811                      }
01812               }
01813        }
01814 
01815        /* Below */
01816        if (y < ((im->sy) - 1)) {
01817               lastBorder = 1;
01818               for (i = leftLimit; i <= rightLimit; i++) {
01819                      int c = gdImageGetPixel(im, i, y + 1);
01820 
01821                      if (lastBorder) {
01822                             if ((c != border) && (c != color)) {
01823                                    gdImageFillToBorder(im, i, y + 1, border, color);
01824                                    lastBorder = 0;
01825                             }
01826                      } else if ((c == border) || (c == color)) {
01827                             lastBorder = 1;
01828                      }
01829               }
01830        }
01831        im->alphaBlendingFlag = restoreAlphaBlending;
01832 }
01833 
01834 /*
01835  * set the pixel at (x,y) and its 4-connected neighbors
01836  * with the same pixel value to the new pixel value nc (new color).
01837  * A 4-connected neighbor:  pixel above, below, left, or right of a pixel.
01838  * ideas from comp.graphics discussions.
01839  * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
01840  * contain the same color as the color to fill. To do not bloat normal filling
01841  * code I added a 2nd private function.
01842  */
01843 
01844 /* horizontal segment of scan line y */
01845 struct seg {int y, xl, xr, dy;};
01846 
01847 /* max depth of stack */
01848 #define FILL_MAX ((int)(im->sy*im->sx)/4)
01849 #define FILL_PUSH(Y, XL, XR, DY) \
01850     if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
01851     {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
01852 
01853 #define FILL_POP(Y, XL, XR, DY) \
01854     {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
01855 
01856 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
01857 
01858 void gdImageFill(gdImagePtr im, int x, int y, int nc)
01859 {
01860        int l, x1, x2, dy;
01861        int oc;   /* old pixel value */
01862        int wx2,wy2;
01863 
01864        int alphablending_bak;
01865 
01866        /* stack of filled segments */
01867        /* struct seg stack[FILL_MAX],*sp = stack;; */
01868        struct seg *stack = NULL;
01869        struct seg *sp;
01870 
01871        if (!im->trueColor && nc > (im->colorsTotal -1)) {
01872               return;
01873        }
01874 
01875        alphablending_bak = im->alphaBlendingFlag;       
01876        im->alphaBlendingFlag = 0;
01877 
01878        if (nc==gdTiled){
01879               _gdImageFillTiled(im,x,y,nc);
01880               im->alphaBlendingFlag = alphablending_bak;
01881               return;
01882        }
01883 
01884        wx2=im->sx;wy2=im->sy;
01885        oc = gdImageGetPixel(im, x, y);
01886        if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
01887               im->alphaBlendingFlag = alphablending_bak;       
01888               return;
01889        }
01890 
01891        /* Do not use the 4 neighbors implementation with
01892         * small images
01893         */
01894        if (im->sx < 4) {
01895               int ix = x, iy = y, c;
01896               do {
01897                      do {
01898                             c = gdImageGetPixel(im, ix, iy);
01899                             if (c != oc) {
01900                                    goto done;
01901                             }
01902                             gdImageSetPixel(im, ix, iy, nc);
01903                      } while(ix++ < (im->sx -1));
01904                      ix = x;
01905               } while(iy++ < (im->sy -1));
01906               goto done;
01907        }
01908 
01909        stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
01910        sp = stack;
01911 
01912        /* required! */
01913        FILL_PUSH(y,x,x,1);
01914        /* seed segment (popped 1st) */
01915        FILL_PUSH(y+1, x, x, -1);
01916        while (sp>stack) {
01917               FILL_POP(y, x1, x2, dy);
01918 
01919               for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
01920                      gdImageSetPixel(im,x, y, nc);
01921               }
01922               if (x>=x1) {
01923                      goto skip;
01924               }
01925               l = x+1;
01926 
01927                 /* leak on left? */
01928               if (l<x1) {
01929                      FILL_PUSH(y, l, x1-1, -dy);
01930               }
01931               x = x1+1;
01932               do {
01933                      for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
01934                             gdImageSetPixel(im, x, y, nc);
01935                      }
01936                      FILL_PUSH(y, l, x-1, dy);
01937                      /* leak on right? */
01938                      if (x>x2+1) {
01939                             FILL_PUSH(y, x2+1, x-1, -dy);
01940                      }
01941 skip:                for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
01942 
01943                      l = x;
01944               } while (x<=x2);
01945        }
01946 
01947        efree(stack);
01948 
01949 done:
01950        im->alphaBlendingFlag = alphablending_bak;       
01951 }
01952 
01953 static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
01954 {
01955        int i, l, x1, x2, dy;
01956        int oc;   /* old pixel value */
01957        int tiled;
01958        int wx2,wy2;
01959        /* stack of filled segments */
01960        struct seg *stack;
01961        struct seg *sp;
01962        char **pts;
01963 
01964        if (!im->tile) {
01965               return;
01966        }
01967 
01968        wx2=im->sx;wy2=im->sy;
01969        tiled = nc==gdTiled;
01970 
01971        nc =  gdImageTileGet(im,x,y);
01972 
01973        pts = (char **) ecalloc(im->sy + 1, sizeof(char *));
01974        for (i = 0; i < im->sy + 1; i++) {
01975               pts[i] = (char *) ecalloc(im->sx + 1, sizeof(char));
01976        }
01977 
01978        stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
01979        sp = stack;
01980 
01981        oc = gdImageGetPixel(im, x, y);
01982 
01983        /* required! */
01984        FILL_PUSH(y,x,x,1);
01985        /* seed segment (popped 1st) */
01986        FILL_PUSH(y+1, x, x, -1);
01987        while (sp>stack) {
01988               FILL_POP(y, x1, x2, dy);
01989               for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) {
01990                      nc = gdImageTileGet(im,x,y);
01991                      pts[y][x] = 1;
01992                      gdImageSetPixel(im,x, y, nc);
01993               }
01994               if (x>=x1) {
01995                      goto skip;
01996               }
01997               l = x+1;
01998 
01999               /* leak on left? */
02000               if (l<x1) {
02001                      FILL_PUSH(y, l, x1-1, -dy);
02002               }
02003               x = x1+1;
02004               do {
02005                      for(; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc); x++) {
02006                             nc = gdImageTileGet(im,x,y);
02007                             pts[y][x] = 1;
02008                             gdImageSetPixel(im, x, y, nc);
02009                      }
02010                      FILL_PUSH(y, l, x-1, dy);
02011                      /* leak on right? */
02012                      if (x>x2+1) {
02013                             FILL_PUSH(y, x2+1, x-1, -dy);
02014                      }
02015 skip:         for(x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++);
02016                      l = x;
02017               } while (x<=x2);
02018        }
02019 
02020        for(i = 0; i < im->sy + 1; i++) {
02021               efree(pts[i]);
02022        }
02023 
02024        efree(pts);
02025        efree(stack);
02026 }
02027 
02028 
02029 
02030 void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
02031 {
02032        int x1h = x1, x1v = x1, y1h = y1, y1v = y1, x2h = x2, x2v = x2, y2h = y2, y2v = y2;
02033        int thick = im->thick;
02034        int half1 = 1;
02035        int t;
02036 
02037        if (x1 == x2 && y1 == y2 && thick == 1) {
02038               gdImageSetPixel(im, x1, y1, color);
02039               return;
02040        }
02041 
02042        if (y2 < y1) {
02043               t=y1;
02044               y1 = y2;
02045               y2 = t;
02046 
02047               t = x1;
02048               x1 = x2;
02049               x2 = t;
02050        }
02051 
02052        x1h = x1; x1v = x1; y1h = y1; y1v = y1; x2h = x2; x2v = x2; y2h = y2; y2v = y2;
02053        if (thick > 1) {
02054               int cx, cy, x1ul, y1ul, x2lr, y2lr;
02055               int half = thick >> 1;
02056               half1 = thick - half;
02057               x1ul = x1 - half;
02058               y1ul = y1 - half;
02059               
02060               x2lr = x2 + half;
02061               y2lr = y2 + half;
02062 
02063               cy = y1ul + thick;
02064               while (cy-- > y1ul) {
02065                      cx = x1ul - 1;
02066                      while (cx++ < x2lr) {
02067                             gdImageSetPixel(im, cx, cy, color);
02068                      }
02069               }
02070 
02071               cy = y2lr - thick;
02072               while (cy++ < y2lr) {
02073                      cx = x1ul - 1;
02074                      while (cx++ < x2lr) {
02075                             gdImageSetPixel(im, cx, cy, color);
02076                      }
02077               }
02078 
02079               cy = y1ul + thick - 1;
02080               while (cy++ < y2lr -thick) {
02081                      cx = x1ul - 1;
02082                      while (cx++ < x1ul + thick) {
02083                             gdImageSetPixel(im, cx, cy, color);
02084                      }
02085               }
02086 
02087               cy = y1ul + thick - 1;
02088               while (cy++ < y2lr -thick) {
02089                      cx = x2lr - thick - 1;
02090                      while (cx++ < x2lr) {
02091                             gdImageSetPixel(im, cx, cy, color);
02092                      }
02093               }
02094 
02095               return;
02096        } else {
02097               y1v = y1h + 1;
02098               y2v = y2h - 1;
02099               gdImageLine(im, x1h, y1h, x2h, y1h, color);
02100               gdImageLine(im, x1h, y2h, x2h, y2h, color);
02101               gdImageLine(im, x1v, y1v, x1v, y2v, color);
02102               gdImageLine(im, x2v, y1v, x2v, y2v, color);
02103        }
02104 }
02105 
02106 void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
02107 {
02108        int x, y;
02109 
02110 
02111        if (x1 == x2 && y1 == y2) {
02112               gdImageSetPixel(im, x1, y1, color);
02113               return;
02114        }
02115 
02116        if (x1 > x2) {
02117               x = x1;
02118               x1 = x2;
02119               x2 = x;
02120        }
02121 
02122        if (y1 > y2) {
02123               y = y1;
02124               y1 = y2;
02125               y2 = y;
02126        }
02127 
02128        if (x1 < 0) {
02129               x1 = 0;
02130        }
02131 
02132        if (x2 >= gdImageSX(im)) {
02133               x2 = gdImageSX(im) - 1;
02134        }
02135 
02136        if (y1 < 0) {
02137               y1 = 0;
02138        }
02139 
02140        if (y2 >= gdImageSY(im)) {
02141               y2 = gdImageSY(im) - 1;
02142        }
02143 
02144        for (y = y1; (y <= y2); y++) {
02145               for (x = x1; (x <= x2); x++) {
02146                      gdImageSetPixel (im, x, y, color);
02147               }
02148        }
02149 }
02150 
02151 void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
02152 {
02153        int c;
02154        int x, y;
02155        int tox, toy;
02156        int i;
02157        int colorMap[gdMaxColors];
02158 
02159        if (dst->trueColor) {
02160               /* 2.0: much easier when the destination is truecolor. */
02161               /* 2.0.10: needs a transparent-index check that is still valid if
02162                * the source is not truecolor. Thanks to Frank Warmerdam.
02163                */
02164 
02165               if (src->trueColor) {
02166                      for (y = 0; (y < h); y++) {
02167                             for (x = 0; (x < w); x++) {
02168                                    int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
02169                                    gdImageSetPixel (dst, dstX + x, dstY + y, c);
02170                             }
02171                      }
02172               } else {
02173                      /* source is palette based */
02174                      for (y = 0; (y < h); y++) {
02175                             for (x = 0; (x < w); x++) {
02176                                    int c = gdImageGetPixel (src, srcX + x, srcY + y);
02177                                    if (c != src->transparent) {
02178                                           gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
02179                                    }
02180                             }
02181                      }
02182               }
02183               return;
02184        }
02185 
02186        /* Destination is palette based */
02187        if (src->trueColor) { /* But source is truecolor (Ouch!) */
02188               toy = dstY;
02189               for (y = srcY; (y < (srcY + h)); y++) {
02190                      tox = dstX;
02191                      for (x = srcX; x < (srcX + w); x++) {
02192                             int nc;
02193                             c = gdImageGetPixel (src, x, y);
02194 
02195                             /* Get best match possible. */
02196                             nc = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c), gdTrueColorGetAlpha(c));
02197 
02198                             gdImageSetPixel(dst, tox, toy, nc);
02199                             tox++;
02200                      }
02201                      toy++;
02202               }
02203               return;
02204        }
02205 
02206        /* Palette based to palette based */
02207        for (i = 0; i < gdMaxColors; i++) {
02208               colorMap[i] = (-1);
02209        }
02210        toy = dstY;
02211        for (y = srcY; y < (srcY + h); y++) {
02212               tox = dstX;
02213               for (x = srcX; x < (srcX + w); x++) {
02214                      int nc;
02215                      int mapTo;
02216                      c = gdImageGetPixel (src, x, y);
02217                      /* Added 7/24/95: support transparent copies */
02218                      if (gdImageGetTransparent (src) == c) {
02219                             tox++;
02220                             continue;
02221                      }
02222                      /* Have we established a mapping for this color? */
02223                      if (src->trueColor) {
02224                             /* 2.05: remap to the palette available in the destination image. This is slow and
02225                              * works badly, but it beats crashing! Thanks to Padhrig McCarthy.
02226                              */
02227                             mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c));
02228                      } else if (colorMap[c] == (-1)) {
02229                             /* If it's the same image, mapping is trivial */
02230                             if (dst == src) {
02231                                    nc = c;
02232                             } else {
02233                                    /* Get best match possible. This function never returns error. */
02234                                    nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]);
02235                             }
02236                             colorMap[c] = nc;
02237                             mapTo = colorMap[c];
02238                      } else {
02239                             mapTo = colorMap[c];
02240                      }
02241                      gdImageSetPixel (dst, tox, toy, mapTo);
02242                      tox++;
02243               }
02244               toy++;
02245        }
02246 }
02247 
02248 /* This function is a substitute for real alpha channel operations,
02249    so it doesn't pay attention to the alpha channel. */
02250 void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
02251 {
02252        int c, dc;
02253        int x, y;
02254        int tox, toy;
02255        int ncR, ncG, ncB;
02256        toy = dstY;
02257        
02258        for (y = srcY; y < (srcY + h); y++) {
02259               tox = dstX;
02260               for (x = srcX; x < (srcX + w); x++) {
02261                      int nc;
02262                      c = gdImageGetPixel(src, x, y);
02263                      /* Added 7/24/95: support transparent copies */
02264                      if (gdImageGetTransparent(src) == c) {
02265                             tox++;
02266                             continue;
02267                      }
02268                      /* If it's the same image, mapping is trivial */
02269                      if (dst == src) {
02270                             nc = c;
02271                      } else {
02272                             dc = gdImageGetPixel(dst, tox, toy);
02273 
02274                             ncR = (int)(gdImageRed (src, c) * (pct / 100.0) + gdImageRed (dst, dc) * ((100 - pct) / 100.0));
02275                             ncG = (int)(gdImageGreen (src, c) * (pct / 100.0) + gdImageGreen (dst, dc) * ((100 - pct) / 100.0));
02276                             ncB = (int)(gdImageBlue (src, c) * (pct / 100.0) + gdImageBlue (dst, dc) * ((100 - pct) / 100.0));
02277 
02278                             /* Find a reasonable color */
02279                             nc = gdImageColorResolve (dst, ncR, ncG, ncB);
02280                      }
02281                      gdImageSetPixel (dst, tox, toy, nc);
02282                      tox++;
02283               }
02284               toy++;
02285        }
02286 }
02287 
02288 /* This function is a substitute for real alpha channel operations,
02289    so it doesn't pay attention to the alpha channel. */
02290 void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
02291 {
02292        int c, dc;
02293        int x, y;
02294        int tox, toy;
02295        int ncR, ncG, ncB;
02296        float g;
02297        toy = dstY;
02298 
02299        for (y = srcY; (y < (srcY + h)); y++) {
02300               tox = dstX;
02301               for (x = srcX; (x < (srcX + w)); x++) {
02302                      int nc;
02303                      c = gdImageGetPixel (src, x, y);
02304                      /* Added 7/24/95: support transparent copies */
02305                      if (gdImageGetTransparent(src) == c) {
02306                             tox++;
02307                             continue;
02308                      }
02309 
02310                      /*
02311                       * If it's the same image, mapping is NOT trivial since we
02312                       * merge with greyscale target, but if pct is 100, the grey
02313                       * value is not used, so it becomes trivial. pjw 2.0.12.
02314                       */
02315                      if (dst == src && pct == 100) {
02316                             nc = c;
02317                      } else {
02318                             dc = gdImageGetPixel(dst, tox, toy);
02319                             g = (0.29900f * gdImageRed(dst, dc)) + (0.58700f * gdImageGreen(dst, dc)) + (0.11400f * gdImageBlue(dst, dc));
02320 
02321                             ncR = (int)(gdImageRed (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
02322                             ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
02323                             ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
02324 
02325 
02326                             /* First look for an exact match */
02327                             nc = gdImageColorExact(dst, ncR, ncG, ncB);
02328                             if (nc == (-1)) {
02329                                    /* No, so try to allocate it */
02330                                    nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
02331                                    /* If we're out of colors, go for the closest color */
02332                                    if (nc == (-1)) {
02333                                           nc = gdImageColorClosest(dst, ncR, ncG, ncB);
02334                                    }
02335                             }
02336                      }
02337                      gdImageSetPixel(dst, tox, toy, nc);
02338                      tox++;
02339               }
02340               toy++;
02341        }
02342 }
02343 
02344 void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
02345 {
02346        int c;
02347        int x, y;
02348        int tox, toy;
02349        int ydest;
02350        int i;
02351        int colorMap[gdMaxColors];
02352        /* Stretch vectors */
02353        int *stx, *sty;
02354        /* We only need to use floating point to determine the correct stretch vector for one line's worth. */
02355        double accum;
02356        
02357        if (overflow2(sizeof(int), srcW)) {
02358               return;
02359        }
02360        if (overflow2(sizeof(int), srcH)) {
02361               return;
02362        }
02363 
02364        stx = (int *) gdMalloc (sizeof (int) * srcW);
02365        sty = (int *) gdMalloc (sizeof (int) * srcH);
02366        accum = 0;
02367 
02368        /* Fixed by Mao Morimoto 2.0.16 */
02369        for (i = 0; (i < srcW); i++) {
02370               stx[i] = dstW * (i+1) / srcW - dstW * i / srcW ;
02371        }
02372        for (i = 0; (i < srcH); i++) {
02373               sty[i] = dstH * (i+1) / srcH - dstH * i / srcH ;
02374        }
02375        for (i = 0; (i < gdMaxColors); i++) {
02376               colorMap[i] = (-1);
02377        }
02378        toy = dstY;
02379        for (y = srcY; (y < (srcY + srcH)); y++) {
02380               for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
02381                      tox = dstX;
02382                      for (x = srcX; (x < (srcX + srcW)); x++) {
02383                             int nc = 0;
02384                             int mapTo;
02385                             if (!stx[x - srcX]) {
02386                                    continue;
02387                             }
02388                             if (dst->trueColor) {
02389                                    /* 2.0.9: Thorben Kundinger: Maybe the source image is not a truecolor image */
02390                                    if (!src->trueColor) {
02391                                           int tmp = gdImageGetPixel (src, x, y);
02392                                           mapTo = gdImageGetTrueColorPixel (src, x, y);
02393                                           if (gdImageGetTransparent (src) == tmp) {
02394                                                  /* 2.0.21, TK: not tox++ */
02395                                                  tox += stx[x - srcX];
02396                                                  continue;
02397                                           }
02398                                    } else {
02399                                           /* TK: old code follows */
02400                                           mapTo = gdImageGetTrueColorPixel (src, x, y);
02401                                           /* Added 7/24/95: support transparent copies */
02402                                           if (gdImageGetTransparent (src) == mapTo) {
02403                                                  /* 2.0.21, TK: not tox++ */
02404                                                  tox += stx[x - srcX];
02405                                                  continue;
02406                                           }
02407                                    }
02408                             } else {
02409                                    c = gdImageGetPixel (src, x, y);
02410                                    /* Added 7/24/95: support transparent copies */
02411                                    if (gdImageGetTransparent (src) == c) {
02412                                          tox += stx[x - srcX];
02413                                          continue;
02414                                    }
02415                                    if (src->trueColor) {
02416                                          /* Remap to the palette available in the destination image. This is slow and works badly. */
02417                                          mapTo = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c),
02418                                                                           gdTrueColorGetGreen(c),
02419                                                                           gdTrueColorGetBlue(c),
02420                                                                           gdTrueColorGetAlpha (c));
02421                                    } else {
02422                                           /* Have we established a mapping for this color? */
02423                                           if (colorMap[c] == (-1)) {
02424                                                  /* If it's the same image, mapping is trivial */
02425                                                  if (dst == src) {
02426                                                         nc = c;
02427                                                  } else {
02428                                                         /* Find or create the best match */
02429                                                         /* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
02430                                                         nc = gdImageColorResolveAlpha(dst, gdImageRed(src, c),
02431                                                                                        gdImageGreen(src, c),
02432                                                                                        gdImageBlue(src, c),
02433                                                                                        gdImageAlpha(src, c));
02434                                                  }
02435                                                  colorMap[c] = nc;
02436                                           }
02437                                           mapTo = colorMap[c];
02438                                    }
02439                             }
02440                             for (i = 0; (i < stx[x - srcX]); i++) {
02441                                    gdImageSetPixel (dst, tox, toy, mapTo);
02442                                    tox++;
02443                             }
02444                      }
02445                      toy++;
02446               }
02447        }
02448        gdFree (stx);
02449        gdFree (sty);
02450 }
02451 
02452 /* When gd 1.x was first created, floating point was to be avoided.
02453    These days it is often faster than table lookups or integer
02454    arithmetic. The routine below is shamelessly, gloriously
02455    floating point. TBB */
02456 
02457 void gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
02458 {
02459        int x, y;
02460        double sy1, sy2, sx1, sx2;
02461 
02462        if (!dst->trueColor) {
02463               gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
02464               return;
02465        }
02466        for (y = dstY; (y < dstY + dstH); y++) {
02467               sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
02468               sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
02469               for (x = dstX; (x < dstX + dstW); x++) {
02470                      double sx, sy;
02471                      double spixels = 0;
02472                      double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
02473                      double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
02474                      sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
02475                      sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
02476                      sy = sy1;
02477                      do {
02478                             double yportion;
02479                             if (floor_cast(sy) == floor_cast(sy1)) {
02480                                    yportion = 1.0f - (sy - floor_cast(sy));
02481                                    if (yportion > sy2 - sy1) {
02482                                           yportion = sy2 - sy1;
02483                                    }
02484                                    sy = floor_cast(sy);
02485                             } else if (sy == floorf(sy2)) {
02486                                    yportion = sy2 - floor_cast(sy2);
02487                             } else {
02488                                    yportion = 1.0f;
02489                             }
02490                             sx = sx1;
02491                             do {
02492                                    double xportion;
02493                                    double pcontribution;
02494                                    int p;
02495                                    if (floorf(sx) == floor_cast(sx1)) {
02496                                           xportion = 1.0f - (sx - floor_cast(sx));
02497                                           if (xportion > sx2 - sx1) {
02498                                                  xportion = sx2 - sx1;
02499                                           }
02500                                           sx = floor_cast(sx);
02501                                    } else if (sx == floorf(sx2)) {
02502                                           xportion = sx2 - floor_cast(sx2);
02503                                    } else {
02504                                           xportion = 1.0f;
02505                                    }
02506                                    pcontribution = xportion * yportion;
02507                                    p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
02508 
02509                                    alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
02510                                    red += gdTrueColorGetRed (p) * alpha_factor;
02511                                    green += gdTrueColorGetGreen (p) * alpha_factor;
02512                                    blue += gdTrueColorGetBlue (p) * alpha_factor;
02513                                    alpha += gdTrueColorGetAlpha (p) * pcontribution;
02514                                    alpha_sum += alpha_factor;
02515                                    contrib_sum += pcontribution;
02516                                    spixels += xportion * yportion;
02517                                    sx += 1.0f;
02518                             }
02519                             while (sx < sx2);
02520 
02521                             sy += 1.0f;
02522                      }
02523 
02524                      while (sy < sy2);
02525 
02526                      if (spixels != 0.0f) {
02527                             red /= spixels;
02528                             green /= spixels;
02529                             blue /= spixels;
02530                             alpha /= spixels;
02531                             alpha += 0.5;
02532                      }
02533                      if ( alpha_sum != 0.0f) {
02534                             if( contrib_sum != 0.0f) {
02535                                    alpha_sum /= contrib_sum;
02536                             }
02537                             red /= alpha_sum;
02538                             green /= alpha_sum;
02539                             blue /= alpha_sum;
02540                      }
02541                      /* Clamping to allow for rounding errors above */
02542                      if (red > 255.0f) {
02543                             red = 255.0f;
02544                      }
02545                      if (green > 255.0f) {
02546                             green = 255.0f;
02547                      }
02548                      if (blue > 255.0f) {
02549                             blue = 255.0f;
02550                      }
02551                      if (alpha > gdAlphaMax) {
02552                             alpha = gdAlphaMax;
02553                      }
02554                      gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha));
02555               }
02556        }
02557 }
02558 
02559 void gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
02560 {
02561        int i;
02562        int lx, ly;
02563        typedef void (*image_line)(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
02564        image_line draw_line;
02565 
02566        if (n <= 0) {
02567               return;
02568        }
02569 
02570        /* Let it be known that we are drawing a polygon so that the opacity
02571         * mask doesn't get cleared after each line.
02572         */
02573        if (c == gdAntiAliased) {
02574               im->AA_polygon = 1;
02575        }
02576 
02577        if ( im->antialias) {
02578               draw_line = gdImageAALine;
02579        } else {
02580               draw_line = gdImageLine;
02581        }
02582        lx = p->x;
02583        ly = p->y;
02584        draw_line(im, lx, ly, p[n - 1].x, p[n - 1].y, c);
02585        for (i = 1; i < n; i++) {
02586               p++;
02587               draw_line(im, lx, ly, p->x, p->y, c);
02588               lx = p->x;
02589               ly = p->y;
02590        }
02591 
02592        if (c == gdAntiAliased) {
02593               im->AA_polygon = 0;
02594               gdImageAABlend(im);
02595        }
02596 }
02597 
02598 int gdCompareInt (const void *a, const void *b);
02599 
02600 /* THANKS to Kirsten Schulz for the polygon fixes! */
02601 
02602 /* The intersection finding technique of this code could be improved
02603  * by remembering the previous intertersection, and by using the slope.
02604  * That could help to adjust intersections  to produce a nice
02605  * interior_extrema.
02606  */
02607 
02608 void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
02609 {
02610        int i;
02611        int y;
02612        int miny, maxy, pmaxy;
02613        int x1, y1;
02614        int x2, y2;
02615        int ind1, ind2;
02616        int ints;
02617        int fill_color;
02618 
02619        if (n <= 0) {
02620               return;
02621        }
02622 
02623        if (overflow2(sizeof(int), n)) {
02624               return;
02625        }
02626 
02627        if (c == gdAntiAliased) {
02628               fill_color = im->AA_color;
02629        } else {
02630               fill_color = c;
02631        }
02632 
02633        if (!im->polyAllocated) {
02634               im->polyInts = (int *) gdMalloc(sizeof(int) * n);
02635               im->polyAllocated = n;
02636        }
02637        if (im->polyAllocated < n) {
02638               while (im->polyAllocated < n) {
02639                      im->polyAllocated *= 2;
02640               }
02641               if (overflow2(sizeof(int), im->polyAllocated)) {
02642                      return;
02643               }
02644               im->polyInts = (int *) gdRealloc(im->polyInts, sizeof(int) * im->polyAllocated);
02645        }
02646        miny = p[0].y;
02647        maxy = p[0].y;
02648        for (i = 1; i < n; i++) {
02649               if (p[i].y < miny) {
02650                      miny = p[i].y;
02651               }
02652               if (p[i].y > maxy) {
02653                      maxy = p[i].y;
02654               }
02655        }
02656        pmaxy = maxy;
02657        /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
02658        if (miny < 0) {
02659               miny = 0;
02660        }
02661        if (maxy >= gdImageSY(im)) {
02662               maxy = gdImageSY(im) - 1;
02663        }
02664 
02665        /* Fix in 1.3: count a vertex only once */
02666        for (y = miny; y <= maxy; y++) {
02667               /*1.4           int interLast = 0; */
02668               /*              int dirLast = 0; */
02669               /*              int interFirst = 1; */
02670               ints = 0;
02671               for (i = 0; i < n; i++) {
02672                      if (!i) {
02673                             ind1 = n - 1;
02674                             ind2 = 0;
02675                      } else {
02676                             ind1 = i - 1;
02677                             ind2 = i;
02678                      }
02679                      y1 = p[ind1].y;
02680                      y2 = p[ind2].y;
02681                      if (y1 < y2) {
02682                             x1 = p[ind1].x;
02683                             x2 = p[ind2].x;
02684                      } else if (y1 > y2) {
02685                             y2 = p[ind1].y;
02686                             y1 = p[ind2].y;
02687                             x2 = p[ind1].x;
02688                             x1 = p[ind2].x;
02689                      } else {
02690                             continue;
02691                      }
02692                      /* Do the following math as float intermediately, and round to ensure
02693                       * that Polygon and FilledPolygon for the same set of points have the
02694                       * same footprint.
02695                       */
02696                      if (y >= y1 && y < y2) {
02697                             im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
02698                      } else if (y == pmaxy && y == y2) {
02699                             im->polyInts[ints++] = x2;
02700                      }
02701               }
02702               qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
02703 
02704               for (i = 0; i < ints - 1; i += 2) {
02705                      gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, fill_color);
02706               }
02707        }
02708 
02709        /* If we are drawing this AA, then redraw the border with AA lines. */
02710        if (c == gdAntiAliased) {
02711               gdImagePolygon(im, p, n, c);
02712        }
02713 }
02714 
02715 int gdCompareInt (const void *a, const void *b)
02716 {
02717        return (*(const int *) a) - (*(const int *) b);
02718 }
02719 
02720 void gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
02721 {
02722        if (im->style) {
02723               gdFree(im->style);
02724        }
02725        im->style = (int *) gdMalloc(sizeof(int) * noOfPixels);
02726        memcpy(im->style, style, sizeof(int) * noOfPixels);
02727        im->styleLength = noOfPixels;
02728        im->stylePos = 0;
02729 }
02730 
02731 void gdImageSetThickness (gdImagePtr im, int thickness)
02732 {
02733        im->thick = thickness;
02734 }
02735 
02736 void gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
02737 {
02738        int i;
02739        im->brush = brush;
02740        if (!im->trueColor && !im->brush->trueColor) {
02741               for (i = 0; i < gdImageColorsTotal(brush); i++) {
02742                      int index;
02743                      index = gdImageColorResolveAlpha(im, gdImageRed(brush, i), gdImageGreen(brush, i), gdImageBlue(brush, i), gdImageAlpha(brush, i));
02744                      im->brushColorMap[i] = index;
02745               }
02746        }
02747 }
02748 
02749 void gdImageSetTile (gdImagePtr im, gdImagePtr tile)
02750 {
02751        int i;
02752        im->tile = tile;
02753        if (!im->trueColor && !im->tile->trueColor) {
02754               for (i = 0; i < gdImageColorsTotal(tile); i++) {
02755                      int index;
02756                      index = gdImageColorResolveAlpha(im, gdImageRed(tile, i), gdImageGreen(tile, i), gdImageBlue(tile, i), gdImageAlpha(tile, i));
02757                      im->tileColorMap[i] = index;
02758               }
02759        }
02760 }
02761 
02762 void gdImageSetAntiAliased (gdImagePtr im, int c)
02763 {
02764        im->AA = 1;
02765        im->AA_color = c;
02766        im->AA_dont_blend = -1;
02767 }
02768 
02769 void gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
02770 {
02771        im->AA = 1;
02772        im->AA_color = c;
02773        im->AA_dont_blend = dont_blend;
02774 }
02775 
02776 
02777 void gdImageInterlace (gdImagePtr im, int interlaceArg)
02778 {
02779        im->interlace = interlaceArg;
02780 }
02781 
02782 int gdImageCompare (gdImagePtr im1, gdImagePtr im2)
02783 {
02784        int x, y;
02785        int p1, p2;
02786        int cmpStatus = 0;
02787        int sx, sy;
02788 
02789        if (im1->interlace != im2->interlace) {
02790               cmpStatus |= GD_CMP_INTERLACE;
02791        }
02792 
02793        if (im1->transparent != im2->transparent) {
02794               cmpStatus |= GD_CMP_TRANSPARENT;
02795        }
02796 
02797        if (im1->trueColor != im2->trueColor) {
02798               cmpStatus |= GD_CMP_TRUECOLOR;
02799        }
02800 
02801        sx = im1->sx;
02802        if (im1->sx != im2->sx) {
02803               cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
02804               if (im2->sx < im1->sx) {
02805                      sx = im2->sx;
02806               }
02807        }
02808 
02809        sy = im1->sy;
02810        if (im1->sy != im2->sy) {
02811               cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
02812               if (im2->sy < im1->sy) {
02813                      sy = im2->sy;
02814               }
02815        }
02816 
02817        if (im1->colorsTotal != im2->colorsTotal) {
02818               cmpStatus |= GD_CMP_NUM_COLORS;
02819        }
02820 
02821        for (y = 0; y < sy; y++) {
02822               for (x = 0; x < sx; x++) {
02823                      p1 = im1->trueColor ? gdImageTrueColorPixel(im1, x, y) : gdImagePalettePixel(im1, x, y);
02824                      p2 = im2->trueColor ? gdImageTrueColorPixel(im2, x, y) : gdImagePalettePixel(im2, x, y);
02825 
02826                      if (gdImageRed(im1, p1) != gdImageRed(im2, p2)) {
02827                             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
02828                             break;
02829                      }
02830                      if (gdImageGreen(im1, p1) != gdImageGreen(im2, p2)) {
02831                             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
02832                             break;
02833                      }
02834                      if (gdImageBlue(im1, p1) != gdImageBlue(im2, p2)) {
02835                             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
02836                             break;
02837                      }
02838 #if 0
02839                      /* Soon we'll add alpha channel to palettes */
02840                      if (gdImageAlpha(im1, p1) != gdImageAlpha(im2, p2)) {
02841                             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
02842                             break;
02843                      }
02844 #endif
02845               }
02846               if (cmpStatus & GD_CMP_COLOR) {
02847                      break;
02848               }
02849        }
02850 
02851        return cmpStatus;
02852 }
02853 
02854 int
02855 gdAlphaBlendOld (int dst, int src)
02856 {
02857        /* 2.0.12: TBB: alpha in the destination should be a
02858         * component of the result. Thanks to Frank Warmerdam for
02859         * pointing out the issue.
02860         */
02861        return ((((gdTrueColorGetAlpha (src) *
02862             gdTrueColorGetAlpha (dst)) / gdAlphaMax) << 24) +
02863          ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
02864             gdTrueColorGetRed (src) / gdAlphaMax) +
02865            (gdTrueColorGetAlpha (src) *
02866             gdTrueColorGetRed (dst)) / gdAlphaMax) << 16) +
02867          ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
02868             gdTrueColorGetGreen (src) / gdAlphaMax) +
02869            (gdTrueColorGetAlpha (src) *
02870             gdTrueColorGetGreen (dst)) / gdAlphaMax) << 8) +
02871          (((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
02872            gdTrueColorGetBlue (src) / gdAlphaMax) +
02873           (gdTrueColorGetAlpha (src) *
02874            gdTrueColorGetBlue (dst)) / gdAlphaMax));
02875 }
02876 
02877 int gdAlphaBlend (int dst, int src) {
02878     int src_alpha = gdTrueColorGetAlpha(src);
02879     int dst_alpha, alpha, red, green, blue;
02880     int src_weight, dst_weight, tot_weight;
02881 
02882 /* -------------------------------------------------------------------- */
02883 /*      Simple cases we want to handle fast.                            */
02884 /* -------------------------------------------------------------------- */
02885     if( src_alpha == gdAlphaOpaque )
02886         return src;
02887 
02888     dst_alpha = gdTrueColorGetAlpha(dst);
02889     if( src_alpha == gdAlphaTransparent )
02890         return dst;
02891     if( dst_alpha == gdAlphaTransparent )
02892         return src;
02893 
02894 /* -------------------------------------------------------------------- */
02895 /*      What will the source and destination alphas be?  Note that      */
02896 /*      the destination weighting is substantially reduced as the       */
02897 /*      overlay becomes quite opaque.                                   */
02898 /* -------------------------------------------------------------------- */
02899     src_weight = gdAlphaTransparent - src_alpha;
02900     dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
02901     tot_weight = src_weight + dst_weight;
02902     
02903 /* -------------------------------------------------------------------- */
02904 /*      What red, green and blue result values will we use?             */
02905 /* -------------------------------------------------------------------- */
02906     alpha = src_alpha * dst_alpha / gdAlphaMax;
02907 
02908     red = (gdTrueColorGetRed(src) * src_weight
02909            + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
02910     green = (gdTrueColorGetGreen(src) * src_weight
02911            + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
02912     blue = (gdTrueColorGetBlue(src) * src_weight
02913            + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
02914 
02915 /* -------------------------------------------------------------------- */
02916 /*      Return merged result.                                           */
02917 /* -------------------------------------------------------------------- */
02918     return ((alpha << 24) + (red << 16) + (green << 8) + blue);
02919 
02920 }
02921 
02922 void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
02923 {
02924        im->alphaBlendingFlag = alphaBlendingArg;
02925 }
02926 
02927 void gdImageAntialias (gdImagePtr im, int antialias)
02928 {
02929        if (im->trueColor){
02930               im->antialias = antialias;
02931        }
02932 }
02933 
02934 void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
02935 {
02936        im->saveAlphaFlag = saveAlphaArg;
02937 }
02938 
02939 static int gdLayerOverlay (int dst, int src)
02940 {
02941        int a1, a2;
02942        a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
02943        a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
02944        return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
02945               (gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
02946               (gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
02947               (gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
02948               );
02949 }
02950 
02951 static int gdAlphaOverlayColor (int src, int dst, int max )
02952 {
02953        /* this function implements the algorithm
02954         *
02955         * for dst[rgb] < 0.5,
02956         *   c[rgb] = 2.src[rgb].dst[rgb]
02957         * and for dst[rgb] > 0.5,
02958         *   c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
02959         *
02960         */
02961 
02962        dst = dst << 1;
02963        if( dst > max ) {
02964               /* in the "light" zone */
02965               return dst + (src << 1) - (dst * src / max) - max;
02966        } else {
02967               /* in the "dark" zone */
02968               return dst * src / max;
02969        }
02970 }
02971 
02972 void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
02973 {
02974        if (x1 < 0) {
02975               x1 = 0;
02976        }
02977        if (x1 >= im->sx) {
02978               x1 = im->sx - 1;
02979        }
02980        if (x2 < 0) {
02981               x2 = 0;
02982        }
02983        if (x2 >= im->sx) {
02984               x2 = im->sx - 1;
02985        }
02986        if (y1 < 0) {
02987               y1 = 0;
02988        }
02989        if (y1 >= im->sy) {
02990               y1 = im->sy - 1;
02991        }
02992        if (y2 < 0) {
02993               y2 = 0;
02994        }
02995        if (y2 >= im->sy) {
02996               y2 = im->sy - 1;
02997        }
02998        im->cx1 = x1;
02999        im->cy1 = y1;
03000        im->cx2 = x2;
03001        im->cy2 = y2;
03002 }
03003 
03004 void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
03005 {
03006        *x1P = im->cx1;
03007        *y1P = im->cy1;
03008        *x2P = im->cx2;
03009        *y2P = im->cy2;
03010 }
03011