Back to index

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