Back to index

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