]> granicus.if.org Git - php/commitdiff
MFH (gd upgrade).
authorIlia Alshanetsky <iliaa@php.net>
Sat, 5 Apr 2003 17:24:16 +0000 (17:24 +0000)
committerIlia Alshanetsky <iliaa@php.net>
Sat, 5 Apr 2003 17:24:16 +0000 (17:24 +0000)
12 files changed:
ext/gd/libgd/gd.c
ext/gd/libgd/gd.h
ext/gd/libgd/gd_gd.c
ext/gd/libgd/gd_gd2.c
ext/gd/libgd/gd_io.h
ext/gd/libgd/gd_jpeg.c
ext/gd/libgd/gd_png.c
ext/gd/libgd/gd_topal.c
ext/gd/libgd/gdcache.c
ext/gd/libgd/gdcache.h
ext/gd/libgd/gdft.c
ext/gd/libgd/gdkanji.c

index 4b1f7ec021ebaf12b432125629473e2c9abe8bcb..f2411d6d98dc5574d98de7611cd050352f766470 100644 (file)
@@ -87,8 +87,9 @@ static const unsigned char gd_toascii[256] =
 extern int gdCosT[];
 extern int gdSinT[];
 
-static void gdImageBrushApply (gdImagePtr im, int x, int y);
-static void gdImageTileApply (gdImagePtr im, int x, int y);
+static void gdImageBrushApply(gdImagePtr im, int x, int y);
+static void gdImageTileApply(gdImagePtr im, int x, int y);
+static void gdImageAntiAliasedApply(gdImagePtr im, int x, int y);
 static int gdFullAlphaBlend(int dst, int src);
 static int gdLayerOverlay(int dst, int src);
 static int gdAlphaBlendColor(int b1, int b2, int a1, int a2);
@@ -117,148 +118,152 @@ void php_gd_error(const char *format, ...)
        va_end(args);
 }
 
-gdImagePtr
-gdImageCreate (int sx, int sy)
-{
-  int i;
-  gdImagePtr im;
-  im = (gdImage *) gdMalloc (sizeof (gdImage));
-  memset (im, 0, sizeof (gdImage));
-  /* Row-major ever since gd 1.3 */
-  im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy);
-  im->polyInts = 0;
-  im->polyAllocated = 0;
-  im->brush = 0;
-  im->tile = 0;
-  im->style = 0;
-  for (i = 0; (i < sy); i++)
-    {
-      /* Row-major ever since gd 1.3 */
-      im->pixels[i] = (unsigned char *) gdCalloc (
-                                               sx, sizeof (unsigned char));
-    }
-  im->sx = sx;
-  im->sy = sy;
-  im->colorsTotal = 0;
-  im->transparent = (-1);
-  im->interlace = 0;
-  im->thick = 1;
-  for (i = 0; (i < gdMaxColors); i++)
-    {
-      im->open[i] = 1;
-      im->red[i] = 0;
-      im->green[i] = 0;
-      im->blue[i] = 0;
-    };
-  im->trueColor = 0;
-  im->tpixels = 0;
-  return im;
-}
-
-gdImagePtr
-gdImageCreateTrueColor (int sx, int sy)
-{
-  int i;
-  gdImagePtr im;
-  im = (gdImage *) gdMalloc (sizeof (gdImage));
-  memset (im, 0, sizeof (gdImage));
-  im->tpixels = (int **) gdMalloc (sizeof (int *) * sy);
-  im->polyInts = 0;
-  im->polyAllocated = 0;
-  im->brush = 0;
-  im->tile = 0;
-  im->style = 0;
-  for (i = 0; (i < sy); i++)
-    {
-      im->tpixels[i] = (int *) gdCalloc (
-                                         sx, sizeof (int));
-    }
-  im->sx = sx;
-  im->sy = sy;
-  im->transparent = (-1);
-  im->interlace = 0;
-  im->trueColor = 1;
-  /* 2.0.2: alpha blending is now on by default, and saving of alpha is
-    off by default. This allows font antialiasing to work as expected
-    on the first try in JPEGs -- quite important -- and also allows
-    for smaller PNGs when saving of alpha channel is not really
-    desired, which it usually isn't! */
-  im->saveAlphaFlag = 0;
-  im->alphaBlendingFlag = 1;
-  im->thick = 1;
-  return im;
-}
-
-void
-gdImageDestroy (gdImagePtr im)
-{
-  int i;
-  if (im->pixels)
-    {
-      for (i = 0; (i < im->sy); i++)
-       {
-         gdFree (im->pixels[i]);
+gdImagePtr gdImageCreate (int sx, int sy)
+{
+       int i;
+       gdImagePtr im;
+       im = (gdImage *) gdMalloc(sizeof(gdImage));
+       memset(im, 0, sizeof(gdImage));
+       /* Row-major ever since gd 1.3 */
+       im->pixels = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
+       im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
+       im->polyInts = 0;
+       im->polyAllocated = 0;
+       im->brush = 0;
+       im->tile = 0;
+       im->style = 0;
+       for (i = 0; i < sy; i++) {
+               /* Row-major ever since gd 1.3 */
+               im->pixels[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
+               im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
+       }
+       im->sx = sx;
+       im->sy = sy;
+       im->colorsTotal = 0;
+       im->transparent = (-1);
+       im->interlace = 0;
+       im->thick = 1;
+       im->AA = 0;
+       im->AA_polygon = 0;
+       for (i = 0; i < gdMaxColors; i++) {
+               im->open[i] = 1;
+               im->red[i] = 0;
+               im->green[i] = 0;
+               im->blue[i] = 0;
+       }
+       im->trueColor = 0;
+       im->tpixels = 0;
+       im->cx1 = 0;
+       im->cy1 = 0;
+       im->cx2 = im->sx - 1;
+       im->cy2 = im->sy - 1;
+       return im;
+}
+
+gdImagePtr gdImageCreateTrueColor (int sx, int sy)
+{
+       int i;
+       gdImagePtr im;
+       im = (gdImage *) gdMalloc(sizeof(gdImage));
+       memset(im, 0, sizeof(gdImage));
+       im->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
+       im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
+       im->polyInts = 0;
+       im->polyAllocated = 0;
+       im->brush = 0;
+       im->tile = 0;
+       im->style = 0;
+       for (i = 0; i < sy; i++) {
+               im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
+               im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
+       }
+       im->sx = sx;
+       im->sy = sy;
+       im->transparent = (-1);
+       im->interlace = 0;
+       im->trueColor = 1;
+       /* 2.0.2: alpha blending is now on by default, and saving of alpha is
+        * off by default. This allows font antialiasing to work as expected
+        * on the first try in JPEGs -- quite important -- and also allows
+        * for smaller PNGs when saving of alpha channel is not really
+        * desired, which it usually isn't!
+        */
+       im->saveAlphaFlag = 0;
+       im->alphaBlendingFlag = 1;
+       im->thick = 1;
+       im->AA = 0;
+       im->AA_polygon = 0;
+       im->cx1 = 0;
+       im->cy1 = 0;
+       im->cx2 = im->sx - 1;
+       im->cy2 = im->sy - 1;
+       return im;
+}
+
+void gdImageDestroy (gdImagePtr im)
+{
+       int i;
+       if (im->pixels) {
+               for (i = 0; i < im->sy; i++) {
+                       gdFree(im->pixels[i]);
+               }
+               gdFree(im->pixels);
        }
-      gdFree (im->pixels);
-    }
-  if (im->tpixels)
-    {
-      for (i = 0; (i < im->sy); i++)
-       {
-         gdFree (im->tpixels[i]);
+       if (im->tpixels) {
+               for (i = 0; i < im->sy; i++) {
+                       gdFree(im->tpixels[i]);
+               }
+               gdFree(im->tpixels);
        }
-      gdFree (im->tpixels);
-    }
-  if (im->polyInts)
-    {
-      gdFree (im->polyInts);
-    }
-  if (im->style)
-    {
-      gdFree (im->style);
-    }
-  gdFree (im);
+       if (im->AA_opacity) {
+               for (i = 0; i < im->sy; i++) {
+                       gdFree(im->AA_opacity[i]);
+               }
+               gdFree(im->AA_opacity);
+       }
+       if (im->polyInts) {
+               gdFree(im->polyInts);
+       }
+       if (im->style) {
+               gdFree(im->style);
+       }
+       gdFree(im);
 }
 
-int
-gdImageColorClosest (gdImagePtr im, int r, int g, int b)
+int gdImageColorClosest (gdImagePtr im, int r, int g, int b)
 {
-  return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
+       return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
 }
 
-int
-gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
+int gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
 {
-  int i;
-  long rd, gd, bd, ad;
-  int ct = (-1);
-  int first = 1;
-  long mindist = 0;
-  if (im->trueColor)
-    {
-      return gdTrueColorAlpha (r, g, b, a);
-    }
-  for (i = 0; (i < (im->colorsTotal)); i++)
-    {
-      long dist;
-      if (im->open[i])
-       {
-         continue;
+       int i;
+       long rd, gd, bd, ad;
+       int ct = (-1);
+       int first = 1;
+       long mindist = 0;
+
+       if (im->trueColor) {
+               return gdTrueColorAlpha(r, g, b, a);
        }
-      rd = (im->red[i] - r);
-      gd = (im->green[i] - g);
-      bd = (im->blue[i] - b);
-      /* gd 2.02: whoops, was - b (thanks to David Marwood) */
-      ad = (im->blue[i] - a);
-      dist = rd * rd + gd * gd + bd * bd + ad * ad;
-      if (first || (dist < mindist))
-       {
-         mindist = dist;
-         ct = i;
-         first = 0;
+       for (i = 0; i < im->colorsTotal; i++) {
+               long dist;
+               if (im->open[i]) {
+                       continue;
+               }
+               rd = im->red[i] - r;
+               gd = im->green[i] - g;
+               bd = im->blue[i] - b;
+               /* gd 2.02: whoops, was - b (thanks to David Marwood) */
+               ad = im->blue[i] - a;
+               dist = rd * rd + gd * gd + bd * bd + ad * ad;
+               if (first || (dist < mindist)) {
+                       mindist = dist;
+                       ct = i;
+                       first = 0;
+               }
        }
-    }
-  return ct;
+       return ct;
 }
 
 /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
@@ -288,72 +293,66 @@ gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
  */
 typedef struct
 {
-  float R, G, B;
+       float R, G, B;
 }
 RGBType;
 typedef struct
-  {
-    float H, W, B;
-  }
+{
+       float H, W, B;
+}
 HWBType;
 
-static HWBType *
-RGB_to_HWB (RGBType RGB, HWBType * HWB)
+static HWBType * RGB_to_HWB (RGBType RGB, HWBType * HWB)
 {
+       /*
+        * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is  
+        * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.  
+        */
 
-  /*
-   * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is  
-   * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.  
-   */
-
-  float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
-  int i;
-
-  w = MIN3 (R, G, B);
-  v = MAX3 (R, G, B);
-  b = 1 - v;
-  if (v == w)
-    RETURN_HWB (HWB_UNDEFINED, w, b);
-  f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
-  i = (R == w) ? 3 : ((G == w) ? 5 : 1);
-  RETURN_HWB (i - f / (v - w), w, b);
+       float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
+       int i;
 
+       w = MIN3 (R, G, B);
+       v = MAX3 (R, G, B);
+       b = 1 - v;
+       if (v == w) {
+               RETURN_HWB(HWB_UNDEFINED, w, b);
+       }
+       f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
+       i = (R == w) ? 3 : ((G == w) ? 5 : 1);
+       
+       RETURN_HWB(i - f / (v - w), w, b);
 }
 
-static float
-HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
+static float HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
 {
-  RGBType RGB1, RGB2;
-  HWBType HWB1, HWB2;
-  float diff;
+       RGBType RGB1, RGB2;
+       HWBType HWB1, HWB2;
+       float diff;
 
-  SETUP_RGB (RGB1, r1, g1, b1);
-  SETUP_RGB (RGB2, r2, g2, b2);
+       SETUP_RGB(RGB1, r1, g1, b1);
+       SETUP_RGB(RGB2, r2, g2, b2);
 
-  RGB_to_HWB (RGB1, &HWB1);
-  RGB_to_HWB (RGB2, &HWB2);
+       RGB_to_HWB(RGB1, &HWB1);
+       RGB_to_HWB(RGB2, &HWB2);
 
-  /*
-   * I made this bit up; it seems to produce OK results, and it is certainly
-   * more visually correct than the current RGB metric. (PJW)
-   */
+       /*
+        * I made this bit up; it seems to produce OK results, and it is certainly
+        * more visually correct than the current RGB metric. (PJW)
+        */
 
-  if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED))
-    {
-      diff = 0.0f;                     /* Undefined hues always match... */
-    }
-  else
-    {
-      diff = fabsf(HWB1.H - HWB2.H);
-      if (diff > 3.0f)
-       {
-         diff = 6.0f - diff;   /* Remember, it's a colour circle */
+       if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
+               diff = 0.0f;    /* Undefined hues always match... */
+       } else {
+               diff = fabsf(HWB1.H - HWB2.H);
+               if (diff > 3.0f) {
+                       diff = 6.0f - diff;     /* Remember, it's a colour circle */
+               }
        }
-    }
 
-  diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
+       diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
 
-  return diff;
+       return diff;
 }
 
 
@@ -362,147 +361,125 @@ HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
  * This is not actually used, but is here for completeness, in case someone wants to
  * use the HWB stuff for anything else...
  */
-static RGBType *
-HWB_to_RGB (HWBType HWB, RGBType * RGB)
-{
-
-  /* 
-   * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].  
-   * RGB are each returned on [0, 1]. 
-   */
-
-  float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
-  int i;
-
-  v = 1 - b;
-  if (h == HWB_UNDEFINED)
-    RETURN_RGB (v, v, v);
-  i = floor (h);
-  f = h - i;
-  if (i & 1)
-    f = 1 - f;                 /* if i is odd */
-  n = w + f * (v - w);         /* linear interpolation between w and v */
-  switch (i)
-    {
-    case 6:
-    case 0:
-      RETURN_RGB (v, n, w);
-    case 1:
-      RETURN_RGB (n, v, w);
-    case 2:
-      RETURN_RGB (w, v, n);
-    case 3:
-      RETURN_RGB (w, n, v);
-    case 4:
-      RETURN_RGB (n, w, v);
-    case 5:
-      RETURN_RGB (v, w, n);
-    }
+static RGBType * HWB_to_RGB (HWBType HWB, RGBType * RGB)
+{
+       /* 
+        * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].  
+        * RGB are each returned on [0, 1]. 
+        */
 
-  return RGB;
+       float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
+       int i;
 
+       v = 1 - b;
+       if (h == HWB_UNDEFINED) {
+               RETURN_RGB(v, v, v);
+       }
+       i = floor(h);
+       f = h - i;
+       if (i & 1) {
+               f = 1 - f; /* if i is odd */
+       }
+       n = w + f * (v - w);            /* linear interpolation between w and v */
+       switch (i) {
+               case 6:
+               case 0:
+                       RETURN_RGB(v, n, w);
+               case 1:
+                       RETURN_RGB(n, v, w);
+               case 2:
+                       RETURN_RGB(w, v, n);
+               case 3:
+                       RETURN_RGB(w, n, v);
+               case 4:
+                       RETURN_RGB(n, w, v);
+               case 5:
+                       RETURN_RGB(v, w, n);
+       }
+
+       return RGB;
 }
 #endif
 
-int
-gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
+int gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
 {
-  int i;
-  /* long rd, gd, bd; */
-  int ct = (-1);
-  int first = 1;
-  float mindist = 0;
-  if (im->trueColor)
-    {
-      return gdTrueColor (r, g, b);
-    }
-  for (i = 0; (i < (im->colorsTotal)); i++)
-    {
-      float dist;
-      if (im->open[i])
-       {
-         continue;
+       int i;
+       /* long rd, gd, bd; */
+       int ct = (-1);
+       int first = 1;
+       float mindist = 0;
+       if (im->trueColor) {
+               return gdTrueColor(r, g, b);
        }
-      dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b);
-      if (first || (dist < mindist))
-       {
-         mindist = dist;
-         ct = i;
-         first = 0;
+       for (i = 0; i < im->colorsTotal; i++) {
+               float dist;
+               if (im->open[i]) {
+                       continue;
+               }
+               dist = HWB_Diff(im->red[i], im->green[i], im->blue[i], r, g, b);
+               if (first || (dist < mindist)) {
+                       mindist = dist;
+                       ct = i;
+                       first = 0;
+               }
        }
-    }
-  return ct;
+       return ct;
 }
 
-int
-gdImageColorExact (gdImagePtr im, int r, int g, int b)
+int gdImageColorExact (gdImagePtr im, int r, int g, int b)
 {
-  return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
+       return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
 }
 
-int
-gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
+int gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
 {
-  int i;
-  if (im->trueColor)
-    {
-      return gdTrueColorAlpha (r, g, b, a);
-    }
-  for (i = 0; (i < (im->colorsTotal)); i++)
-    {
-      if (im->open[i])
-       {
-         continue;
+       int i;
+       if (im->trueColor) {
+               return gdTrueColorAlpha(r, g, b, a);
        }
-      if ((im->red[i] == r) &&
-         (im->green[i] == g) &&
-         (im->blue[i] == b) &&
-         (im->alpha[i] == a))
-       {
-         return i;
+       for (i = 0; i < im->colorsTotal; i++) {
+               if (im->open[i]) {
+                       continue;
+               }
+               if ((im->red[i] == r) && (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
+                       return i;
+               }
        }
-    }
-  return -1;
+       return -1;
 }
 
-int
-gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
+int gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
 {
-  return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
+       return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
 }
 
-int
-gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
+int gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
 {
-  int i;
-  int ct = (-1);
-  if (im->trueColor)
-    {
-      return gdTrueColorAlpha (r, g, b, a);
-    }
-  for (i = 0; (i < (im->colorsTotal)); i++)
-    {
-      if (im->open[i])
-       {
-         ct = i;
-         break;
+       int i;
+       int ct = (-1);
+       if (im->trueColor) {
+               return gdTrueColorAlpha(r, g, b, a);
        }
-    }
-  if (ct == (-1))
-    {
-      ct = im->colorsTotal;
-      if (ct == gdMaxColors)
-       {
-         return -1;
+       for (i = 0; i < im->colorsTotal; i++) {
+               if (im->open[i]) {
+                       ct = i;
+                       break;
+               }
        }
-      im->colorsTotal++;
-    }
-  im->red[ct] = r;
-  im->green[ct] = g;
-  im->blue[ct] = b;
-  im->alpha[ct] = a;
-  im->open[ct] = 0;
-  return ct;
+       if (ct == (-1)) {
+               ct = im->colorsTotal;
+               if (ct == gdMaxColors) {
+                       return -1;
+               }
+               im->colorsTotal++;
+       }
+       im->red[ct] = r;
+       im->green[ct] = g;
+       im->blue[ct] = b;
+       im->alpha[ct] = a;
+       im->open[ct] = 0;
+       
+       return ct;
 }
 
 /*
@@ -516,14 +493,12 @@ gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
  * return a color index in one search over the color table.
  */
 
-int
-gdImageColorResolve (gdImagePtr im, int r, int g, int b)
+int gdImageColorResolve (gdImagePtr im, int r, int g, int b)
 {
-  return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);
+       return gdImageColorResolveAlpha(im, r, g, b, gdAlphaOpaque);
 }
 
-int
-gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
+int gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
 {
   int c;
   int ct = -1;
@@ -581,15 +556,13 @@ gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
   return op;                   /* Return newly allocated color */
 }
 
-void
-gdImageColorDeallocate (gdImagePtr im, int color)
+void gdImageColorDeallocate (gdImagePtr im, int color)
 {
-  if (im->trueColor)
-    {
-      return;
-    }
-  /* Mark it open. */
-  im->open[color] = 1;
+       if (im->trueColor) {
+               return;
+       }
+       /* Mark it open. */
+       im->open[color] = 1;
 }
 
 void gdImageColorTransparent (gdImagePtr im, int color)
@@ -607,61 +580,43 @@ void gdImageColorTransparent (gdImagePtr im, int color)
        im->transparent = color;
 }
 
-void
-gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
+void gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
 {
-  int i;
-  int x, y, p;
-  int xlate[256];
-  if (to->trueColor)
-    {
-      return;
-    }
-  if (from->trueColor)
-    {
-      return;
-    }
+       int i;
+       int x, y, p;
+       int xlate[256];
+       if (to->trueColor || from->trueColor) {
+               return;
+       }
 
-  for (i = 0; i < 256; i++)
-    {
-      xlate[i] = -1;
-    };
+       for (i = 0; i < 256; i++) {
+               xlate[i] = -1;
+       }
 
-  for (x = 0; x < (to->sx); x++)
-    {
-      for (y = 0; y < (to->sy); y++)
-       {
-         p = gdImageGetPixel (to, x, y);
-         if (xlate[p] == -1)
-           {
-             /* This ought to use HWB, but we don't have an alpha-aware
-                version of that yet. */
-             xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
-             /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */
-             /*      p,  to->red[p], to->green[p], to->blue[p], to->alpha[p], */
-             /*      xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
-           };
-         gdImageSetPixel (to, x, y, xlate[p]);
-       };
-    };
-
-  for (i = 0; (i < (from->colorsTotal)); i++)
-    {
-      /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */
-      to->red[i] = from->red[i];
-      to->blue[i] = from->blue[i];
-      to->green[i] = from->green[i];
-      to->alpha[i] = from->alpha[i];
-      to->open[i] = 0;
-    };
-
-  for (i = from->colorsTotal; (i < to->colorsTotal); i++)
-    {
-      to->open[i] = 1;
-    };
+       for (x = 0; x < to->sx; x++) {
+               for (y = 0; y < to->sy; y++) {
+                       p = gdImageGetPixel(to, x, y);
+                       if (xlate[p] == -1) {
+                               /* This ought to use HWB, but we don't have an alpha-aware version of that yet. */
+                               xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
+                       }
+                       gdImageSetPixel(to, x, y, xlate[p]);
+               }
+       }
 
-  to->colorsTotal = from->colorsTotal;
+       for (i = 0; i < from->colorsTotal; i++) {
+               to->red[i] = from->red[i];
+               to->blue[i] = from->blue[i];
+               to->green[i] = from->green[i];
+               to->alpha[i] = from->alpha[i];
+               to->open[i] = 0;
+       }
 
+       for (i = from->colorsTotal; i < to->colorsTotal; i++) {
+               to->open[i] = 1;
+       }
+
+       to->colorsTotal = from->colorsTotal;
 }
 
 /* 2.0.10: before the drawing routines, some code to clip points that are
@@ -734,92 +689,80 @@ static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) {
        return 1;
 }
 
-void
-gdImageSetPixel (gdImagePtr im, int x, int y, int color)
+void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
 {
-  int p;
-  switch (color)
-    {
-    case gdStyled:
-      if (!im->style)
-       {
-         /* Refuse to draw if no style is set. */
-         return;
-       }
-      else
-       {
-         p = im->style[im->stylePos++];
-       }
-      if (p != (gdTransparent))
-       {
-         gdImageSetPixel (im, x, y, p);
-       }
-      im->stylePos = im->stylePos % im->styleLength;
-      break;
-    case gdStyledBrushed:
-      if (!im->style)
-       {
-         /* Refuse to draw if no style is set. */
-         return;
-       }
-      p = im->style[im->stylePos++];
-      if ((p != gdTransparent) && (p != 0))
-       {
-         gdImageSetPixel (im, x, y, gdBrushed);
-       }
-      im->stylePos = im->stylePos % im->styleLength;
-      break;
-    case gdBrushed:
-      gdImageBrushApply (im, x, y);
-      break;
-    case gdTiled:
-      gdImageTileApply (im, x, y);
-      break;
-    default:
-      if (gdImageBoundsSafe (im, x, y)) {
-               if (im->trueColor) {
-                       switch( im->alphaBlendingFlag )
-                       {
-                       default:
-                       case gdEffectReplace :
-                               im->tpixels[y][x] = color;
-                               break;
-                       case gdEffectAlphaBlend :
-                               im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
-                               break;
-                       case gdEffectNormal :
-                               im->tpixels[y][x] = gdFullAlphaBlend(im->tpixels[y][x], color);
-                               break;
-                       case gdEffectOverlay :
-                               im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
-                               break;
+       int p;
+       switch (color) {
+               case gdStyled:
+                       if (!im->style) {
+                               /* Refuse to draw if no style is set. */
+                               return;
+                       } else {
+                               p = im->style[im->stylePos++];
                        }
-               } else {
-                       im->pixels[y][x] = color;
-               }
-         }
-      break;
-    }
+                       if (p != gdTransparent) {
+                               gdImageSetPixel(im, x, y, p);
+                       }
+                       im->stylePos = im->stylePos % im->styleLength;
+                       break;
+               case gdStyledBrushed:
+                       if (!im->style) {
+                               /* Refuse to draw if no style is set. */
+                               return;
+                       }
+                       p = im->style[im->stylePos++];
+                       if (p != gdTransparent && p != 0) {
+                               gdImageSetPixel(im, x, y, gdBrushed);
+                       }
+                       im->stylePos = im->stylePos % im->styleLength;
+                       break;
+               case gdBrushed:
+                       gdImageBrushApply(im, x, y);
+                       break;
+               case gdTiled:
+                       gdImageTileApply(im, x, y);
+                       break;
+               case gdAntiAliased:
+                       gdImageAntiAliasedApply(im, x, y);
+                       break;
+               default:
+                       if (gdImageBoundsSafe(im, x, y)) {
+                               if (im->trueColor) {
+                                       switch (im->alphaBlendingFlag) {
+                                               default:
+                                               case gdEffectReplace:
+                                                       im->tpixels[y][x] = color;
+                                                       break;
+                                               case gdEffectAlphaBlend:
+                                                       im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
+                                                       break;
+                                               case gdEffectNormal:
+                                                       im->tpixels[y][x] = gdFullAlphaBlend(im->tpixels[y][x], color);
+                                                       break;
+                                               case gdEffectOverlay :
+                                                       im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
+                                                       break;
+                                       }
+                               } else {
+                                       im->pixels[y][x] = color;
+                               }
+                       }
+                       break;
+       }
 }
 
-static int
-gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
+static int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
 {
-  int p = gdImageGetPixel (im, x, y);
-  if (!im->trueColor)
-    {
-      return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p],
-                              (im->transparent == p) ? gdAlphaTransparent :
-                              gdAlphaOpaque);
-    }
-  else
-    {
-      return p;
-    }
+       int p = gdImageGetPixel(im, x, y);
+
+       if (!im->trueColor)  {
+               return gdTrueColorAlpha(im->red[p], im->green[p], im->blue[p], (im->transparent == p) ? gdAlphaTransparent : gdAlphaOpaque);
+       } else {
+               return p;
+       }
 }
 
-static void
-gdImageBrushApply (gdImagePtr im, int x, int y)
+static void gdImageBrushApply (gdImagePtr im, int x, int y)
 {
        int lx, ly;
        int hy, hx;
@@ -830,36 +773,54 @@ gdImageBrushApply (gdImagePtr im, int x, int y)
                return;
        }
 
-       hy = gdImageSY (im->brush) / 2;
+       hy = gdImageSY(im->brush) / 2;
        y1 = y - hy;
-       y2 = y1 + gdImageSY (im->brush);
-       hx = gdImageSX (im->brush) / 2;
+       y2 = y1 + gdImageSY(im->brush);
+       hx = gdImageSX(im->brush) / 2;
        x1 = x - hx;
-       x2 = x1 + gdImageSX (im->brush);
+       x2 = x1 + gdImageSX(im->brush);
        srcy = 0;
        
        if (im->trueColor) {
-               for (ly = y1; (ly < y2); ly++) {
-                       srcx = 0;
-                       for (lx = x1; (lx < x2); lx++) {
-                               int p;
-                               p = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
-                               /* 2.0.9, Thomas Winzig: apply simple full transparency */
-                               if (p != gdImageGetTransparent (im->brush)) {
-                                       gdImageSetPixel (im, lx, ly, p);
-                               }      
-                               srcx++;
+               if (im->brush->trueColor) {
+                       for (ly = y1; ly < y2; ly++) {
+                               srcx = 0;
+                               for (lx = x1; (lx < x2); lx++) {
+                                       int p;
+                                       p = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
+                                       /* 2.0.9, Thomas Winzig: apply simple full transparency */
+                                       if (p != gdImageGetTransparent(im->brush)) {
+                                               gdImageSetPixel(im, lx, ly, p);
+                                       }
+                                       srcx++;
+                               }
+                               srcy++;
+                       }
+               } else {
+                       /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger for pointing out the issue) */
+                       for (ly = y1; ly < y2; ly++) {
+                               srcx = 0;
+                               for (lx = x1; lx < x2; lx++) {
+                                       int p, tc;
+                                       p = gdImageGetPixel(im->brush, srcx, srcy);
+                                       tc = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
+                                       /* 2.0.9, Thomas Winzig: apply simple full transparency */
+                                       if (p != gdImageGetTransparent(im->brush)) {
+                                               gdImageSetPixel(im, lx, ly, tc);
+                                       }
+                                       srcx++;
+                               }
+                               srcy++;
                        }
-                       srcy++;
                }
        } else {
-               for (ly = y1; (ly < y2); ly++) {
+               for (ly = y1; ly < y2; ly++) {
                        srcx = 0;
-                       for (lx = x1; (lx < x2); lx++) {
+                       for (lx = x1; lx < x2; lx++) {
                                int p;
-                               p = gdImageGetPixel (im->brush, srcx, srcy);
+                               p = gdImageGetPixel(im->brush, srcx, srcy);
                                /* Allow for non-square brushes! */
-                               if (p != gdImageGetTransparent (im->brush)) {
+                               if (p != gdImageGetTransparent(im->brush)) {
                                        /* Truecolor brush. Very slow on a palette destination. */
                                        if (im->brush->trueColor) {
                                                gdImageSetPixel(im, lx, ly, gdImageColorResolveAlpha(im, gdTrueColorGetRed(p), 
@@ -877,72 +838,149 @@ gdImageBrushApply (gdImagePtr im, int x, int y)
        }
 }
 
-static void
-gdImageTileApply (gdImagePtr im, int x, int y)
+static void gdImageTileApply (gdImagePtr im, int x, int y)
 {
-  int srcx, srcy;
-  int p;
-  if (!im->tile)
-    {
-      return;
-    }
-  srcx = x % gdImageSX (im->tile);
-  srcy = y % gdImageSY (im->tile);
-  if (im->trueColor)
-    {
-      p = gdImageGetTrueColorPixel (im->tile, srcx, srcy);
-      gdImageSetPixel (im, x, y, p);
-    }
-  else
-    {
-      p = gdImageGetPixel(im->tile, srcx, srcy);
-      /* Allow for transparency */
-      if (p != gdImageGetTransparent (im->tile))
-       {
-         if (im->tile->trueColor)
-           {
-             /* Truecolor tile. Very slow
-                on a palette destination. */
-             gdImageSetPixel (im, x, y,
-                              gdImageColorResolveAlpha (
-                                                         im,
-                                                     gdTrueColorGetRed (p),
-                                                   gdTrueColorGetGreen (p),
-                                                    gdTrueColorGetBlue (p),
-                                                 gdTrueColorGetAlpha (p)));
-           }
-         else
-           {
-             gdImageSetPixel (im, x, y,
-                              im->tileColorMap[p]);
-           }
+       int srcx, srcy;
+       int p;
+       if (!im->tile) {
+               return;
+       }
+       srcx = x % gdImageSX(im->tile);
+       srcy = y % gdImageSY(im->tile);
+       if (im->trueColor) {
+               p = gdImageGetTrueColorPixel(im->tile, srcx, srcy);
+               gdImageSetPixel(im, x, y, p);
+       } else {
+               p = gdImageGetPixel(im->tile, srcx, srcy);
+               /* Allow for transparency */
+               if (p != gdImageGetTransparent(im->tile)) {
+                       if (im->tile->trueColor) {
+                               /* Truecolor tile. Very slow on a palette destination. */
+                               gdImageSetPixel(im, x, y, gdImageColorResolveAlpha(im,
+                                                                                       gdTrueColorGetRed(p),
+                                                                                       gdTrueColorGetGreen(p),
+                                                                                       gdTrueColorGetBlue(p),
+                                                                                       gdTrueColorGetAlpha(p)));
+                       } else {
+                               gdImageSetPixel(im, x, y, im->tileColorMap[p]);
+                       }
+               }
        }
-    }
 }
 
-int
-gdImageGetPixel (gdImagePtr im, int x, int y)
+static void gdImageAntiAliasedApply (gdImagePtr im, int px, int py)
 {
-  if (gdImageBoundsSafe (im, x, y))
-    {
-      if (im->trueColor)
-       {
-         return im->tpixels[y][x];
+       float p_dist, p_alpha;
+       unsigned char opacity;
+
+       /* 
+        * Find the perpendicular distance from point C (px, py) to the line 
+        * segment AB that is being drawn.  (Adapted from an algorithm from the
+        * comp.graphics.algorithms FAQ.)
+        */
+
+       int LAC_2, LBC_2;
+
+       int Ax_Cx = im->AAL_x1 - px;
+       int Ay_Cy = im->AAL_y1 - py;
+
+       int Bx_Cx = im->AAL_x2 - px;
+       int By_Cy = im->AAL_y2 - py;
+
+       /* Get the squares of the lengths of the segemnts AC and BC. */
+       LAC_2 = (Ax_Cx * Ax_Cx) + (Ay_Cy * Ay_Cy);
+       LBC_2 = (Bx_Cx * Bx_Cx) + (By_Cy * By_Cy);
+
+       if (((im->AAL_LAB_2 + LAC_2) >= LBC_2) && ((im->AAL_LAB_2 + LBC_2) >= LAC_2)) {
+               /* The two angles are acute.  The point lies inside the portion of the 
+                * plane spanned by the line segment.
+                */
+               p_dist = fabs ((float) ((Ay_Cy * im->AAL_Bx_Ax) - (Ax_Cx * im->AAL_By_Ay)) / im->AAL_LAB);
+       } else {
+               /* The point is past an end of the line segment.  It's length from the 
+                * segment is the shorter of the lengths from the endpoints, but call
+                * the distance -1, so as not to compute the alpha nor draw the pixel.
+                */
+               p_dist = -1;
        }
-      else
-       {
-         return im->pixels[y][x];
+
+       if ((p_dist >= 0) && (p_dist <= (float) (im->thick))) {
+               p_alpha = pow (1.0 - (p_dist / 1.5), 2);
+
+               if (p_alpha > 0) {
+                       if (p_alpha >= 1) {
+                               opacity = 255;
+                       } else {
+                               opacity = (unsigned char) (p_alpha * 255.0);
+                       }
+                       if (!im->AA_polygon || (im->AA_opacity[py][px] < opacity)) {
+                               im->AA_opacity[py][px] = opacity;
+                       }
+               }
        }
-    }
-  else
-    {
-      return 0;
-    }
 }
 
+
+int gdImageGetPixel (gdImagePtr im, int x, int y)
+{
+       if (gdImageBoundsSafe(im, x, y)) {
+               if (im->trueColor) {
+                       return im->tpixels[y][x];
+               } else {
+                       return im->pixels[y][x];
+               }
+       } else {
+               return 0;
+       }
+}
+
+void gdImageAABlend (gdImagePtr im)
+{
+       float p_alpha, old_alpha;
+       int color = im->AA_color, color_red, color_green, color_blue;
+       int old_color, old_red, old_green, old_blue;
+       int p_color, p_red, p_green, p_blue;
+       int px, py;
+
+       color_red = gdImageRed(im, color);
+       color_green = gdImageGreen(im, color);
+       color_blue = gdImageBlue(im, color);
+
+       /* Impose the anti-aliased drawing on the image. */
+       for (py = 0; py < im->sy; py++) {
+               for (px = 0; px < im->sx; px++) {
+                       if (im->AA_opacity[py][px] != 0) {
+                               old_color = gdImageGetPixel(im, px, py);
+
+                               if ((old_color != color) && ((old_color != im->AA_dont_blend) || (im->AA_opacity[py][px] == 255))) {
+                                       /* Only blend with different colors that aren't the dont_blend color. */
+                                       p_alpha = (float) (im->AA_opacity[py][px]) / 255.0;
+                                       old_alpha = 1.0 - p_alpha;
+
+                                       if (p_alpha >= 1.0) {
+                                               p_color = color;
+                                       } else {
+                                               old_red = gdImageRed(im, old_color);
+                                               old_green = gdImageGreen(im, old_color);
+                                               old_blue = gdImageBlue(im, old_color);
+
+                                               p_red = (int) (((float) color_red * p_alpha) + ((float) old_red * old_alpha));
+                                               p_green = (int) (((float) color_green * p_alpha) + ((float) old_green * old_alpha));
+                                               p_blue = (int) (((float) color_blue * p_alpha) + ((float) old_blue * old_alpha));
+                                               p_color = gdImageColorResolve(im, p_red, p_green, p_blue);
+                                       }
+                                       gdImageSetPixel(im, px, py, p_color);
+                               }
+                       }
+               }
+               /* Clear the AA_opacity array behind us. */
+               memset(im->AA_opacity[py], 0, im->sx);
+       }
+}
+
+
 /* Bresenham as presented in Foley & Van Dam */
-void
-gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
 {
        int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
        int wid;
@@ -953,6 +991,25 @@ gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
        if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im))) {
                return;
        }
+
+       /* gdAntiAliased passed as color: set anti-aliased line (AAL) global vars. */
+       if (color == gdAntiAliased) {
+               im->AAL_x1 = x1;
+               im->AAL_y1 = y1;
+               im->AAL_x2 = x2;
+               im->AAL_y2 = y2;
+
+               /* Compute what we can for point-to-line distance calculation later. */
+               im->AAL_Bx_Ax = x2 - x1;
+               im->AAL_By_Ay = y2 - y1;
+               im->AAL_LAB_2 = (im->AAL_Bx_Ax * im->AAL_Bx_Ax) + (im->AAL_By_Ay * im->AAL_By_Ay);
+               im->AAL_LAB = sqrt (im->AAL_LAB_2);
+
+               /* For AA, we must draw pixels outside the width of the line.  Keep in
+                * mind that this will be curtailed by cos/sin of theta later. 
+                */
+               thick += 4;
+       }
        
        dx = abs(x2 - x1);
        dy = abs(y2 - y1);
@@ -1019,8 +1076,14 @@ gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
                }
        } else {
                /* More-or-less vertical. use wid for horizontal stroke */
-               wid = (int)(thick * sin (atan2 (dy, dx)));
-               if (wid == 0) {
+               /* 2.0.12: Michael Schwartz: divide rather than multiply; 
+                  TBB: but watch out for /0! */
+               double as = sin(atan2(dy, dx));
+               if (as != 0) {
+                       if (!(wid = thick / as)) {
+                               wid = 1;
+                       }
+               } else {
                        wid = 1;
                }
 
@@ -1075,6 +1138,11 @@ gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
                        }
                }
        }
+
+       /* If this is the only line we are drawing, go ahead and blend. */
+       if (color == gdAntiAliased && !im->AA_polygon) {
+               gdImageAABlend(im);
+       }
 }
 
 
@@ -1210,317 +1278,266 @@ void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
        }
 }
 
-static void dashedSet (gdImagePtr im, int x, int y, int color,
-                      int *onP, int *dashStepP, int wid, int vert);
+static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert);
 
-void
-gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+void gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
 {
-  int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
-  int dashStep = 0;
-  int on = 1;
-  int wid;
-  int vert;
-  int thick = im->thick;
+       int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
+       int dashStep = 0;
+       int on = 1;
+       int wid;
+       int vert;
+       int thick = im->thick;
 
-  dx = abs (x2 - x1);
-  dy = abs (y2 - y1);
-  if (dy <= dx)
-    {
-      /* More-or-less horizontal. use wid for vertical stroke */
-      wid = (int)(thick * sin (atan2 (dy, dx)));
-      vert = 1;
-
-      d = 2 * dy - dx;
-      incr1 = 2 * dy;
-      incr2 = 2 * (dy - dx);
-      if (x1 > x2)
-       {
-         x = x2;
-         y = y2;
-         ydirflag = (-1);
-         xend = x1;
-       }
-      else
-       {
-         x = x1;
-         y = y1;
-         ydirflag = 1;
-         xend = x2;
-       }
-      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
-      if (((y2 - y1) * ydirflag) > 0)
-       {
-         while (x < xend)
-           {
-             x++;
-             if (d < 0)
-               {
-                 d += incr1;
-               }
-             else
-               {
-                 y++;
-                 d += incr2;
-               }
-             dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
-           }
-       }
-      else
-       {
-         while (x < xend)
-           {
-             x++;
-             if (d < 0)
-               {
-                 d += incr1;
+       dx = abs(x2 - x1);
+       dy = abs(y2 - y1);
+       if (dy <= dx) {
+               /* More-or-less horizontal. use wid for vertical stroke */
+               /* 2.0.12: Michael Schwartz: divide rather than multiply;
+               TBB: but watch out for /0! */
+               double as = sin(atan2(dy, dx));
+               if (as != 0) {
+                       wid = thick / as;
+               } else {
+                       wid = 1;
                }
-             else
-               {
-                 y--;
-                 d += incr2;
+               wid = (int)(thick * sin(atan2(dy, dx)));
+               vert = 1;
+
+               d = 2 * dy - dx;
+               incr1 = 2 * dy;
+               incr2 = 2 * (dy - dx);
+               if (x1 > x2) {
+                       x = x2;
+                       y = y2;
+                       ydirflag = (-1);
+                       xend = x1;
+               } else {
+                       x = x1;
+                       y = y1;
+                       ydirflag = 1;
+                       xend = x2;
                }
-             dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
-           }
-       }
-    }
-  else
-    {
-      /* More-or-less vertical. use wid for horizontal stroke */
-      wid = (int)(thick * sin (atan2 (dy, dx)));
-      vert = 0;
-
-      d = 2 * dx - dy;
-      incr1 = 2 * dx;
-      incr2 = 2 * (dx - dy);
-      if (y1 > y2)
-       {
-         y = y2;
-         x = x2;
-         yend = y1;
-         xdirflag = (-1);
-       }
-      else
-       {
-         y = y1;
-         x = x1;
-         yend = y2;
-         xdirflag = 1;
-       }
-      dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
-      if (((x2 - x1) * xdirflag) > 0)
-       {
-         while (y < yend)
-           {
-             y++;
-             if (d < 0)
-               {
-                 d += incr1;
+               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
+               if (((y2 - y1) * ydirflag) > 0) {
+                       while (x < xend) {
+                               x++;
+                               if (d < 0) {
+                                       d += incr1;
+                               } else {
+                                       y++;
+                                       d += incr2;
+                               }
+                               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
+                       }
+               } else {
+                       while (x < xend) {
+                               x++;
+                               if (d < 0) {
+                                       d += incr1;
+                               } else {
+                                       y--;
+                                       d += incr2;
+                               }
+                               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
+                       }
                }
-             else
-               {
-                 x++;
-                 d += incr2;
+       } else {
+               /* 2.0.12: Michael Schwartz: divide rather than multiply;
+               TBB: but watch out for /0! */
+               double as = sin (atan2 (dy, dx));
+               if (as != 0) {
+                       wid = thick / as;
+               } else {
+                       wid = 1;
                }
-             dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
-           }
-       }
-      else
-       {
-         while (y < yend)
-           {
-             y++;
-             if (d < 0)
-               {
-                 d += incr1;
+               vert = 0;
+
+               d = 2 * dx - dy;
+               incr1 = 2 * dx;
+               incr2 = 2 * (dx - dy);
+               if (y1 > y2) {
+                       y = y2;
+                       x = x2;
+                       yend = y1;
+                       xdirflag = (-1);
+               } else {
+                       y = y1;
+                       x = x1;
+                       yend = y2;
+                       xdirflag = 1;
                }
-             else
-               {
-                 x--;
-                 d += incr2;
+               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
+               if (((x2 - x1) * xdirflag) > 0) {
+                       while (y < yend) {
+                               y++;
+                               if (d < 0) {
+                                       d += incr1;
+                               } else {
+                                       x++;
+                                       d += incr2;
+                               }
+                               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
+                       }
+               } else {
+                       while (y < yend) {
+                               y++;
+                               if (d < 0) {
+                                       d += incr1;
+                               } else {
+                                       x--;
+                                       d += incr2;
+                               }
+                               dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
+                       }
                }
-             dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
-           }
        }
-    }
 }
 
-static void
-dashedSet (gdImagePtr im, int x, int y, int color,
-          int *onP, int *dashStepP, int wid, int vert)
+static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert)
 {
-  int dashStep = *dashStepP;
-  int on = *onP;
-  int w, wstart;
+       int dashStep = *dashStepP;
+       int on = *onP;
+       int w, wstart;
 
-  dashStep++;
-  if (dashStep == gdDashSize)
-    {
-      dashStep = 0;
-      on = !on;
-    }
-  if (on)
-    {
-      if (vert)
-       {
-         wstart = y - wid / 2;
-         for (w = wstart; w < wstart + wid; w++)
-           gdImageSetPixel (im, x, w, color);
+       dashStep++;
+       if (dashStep == gdDashSize) {
+               dashStep = 0;
+               on = !on;
        }
-      else
-       {
-         wstart = x - wid / 2;
-         for (w = wstart; w < wstart + wid; w++)
-           gdImageSetPixel (im, w, y, color);
+       if (on) {
+               if (vert) {
+                       wstart = y - wid / 2;
+                       for (w = wstart; w < wstart + wid; w++) {
+                               gdImageSetPixel(im, x, w, color);
+                       }
+               } else {
+                       wstart = x - wid / 2;
+                       for (w = wstart; w < wstart + wid; w++) {
+                               gdImageSetPixel(im, w, y, color);
+                       }
+               }
        }
-    }
-  *dashStepP = dashStep;
-  *onP = on;
+       *dashStepP = dashStep;
+       *onP = on;
 }
 
-void
-gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y,
-            int c, int color)
+void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
 {
-  int cx, cy;
-  int px, py;
-  int fline;
-  cx = 0;
-  cy = 0;
+       int cx, cy;
+       int px, py;
+       int fline;
+       cx = 0;
+       cy = 0;
 #ifdef CHARSET_EBCDIC
-  c = ASC (c);
+       c = ASC (c);
 #endif /*CHARSET_EBCDIC */
-  if ((c < f->offset) || (c >= (f->offset + f->nchars)))
-    {
-      return;
-    }
-  fline = (c - f->offset) * f->h * f->w;
-  for (py = y; (py < (y + f->h)); py++)
-    {
-      for (px = x; (px < (x + f->w)); px++)
-       {
-         if (f->data[fline + cy * f->w + cx])
-           {
-             gdImageSetPixel (im, px, py, color);
-           }
-         cx++;
+       if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
+               return;
+       }
+       fline = (c - f->offset) * f->h * f->w;
+       for (py = y; (py < (y + f->h)); py++) {
+               for (px = x; (px < (x + f->w)); px++) {
+                       if (f->data[fline + cy * f->w + cx]) {
+                               gdImageSetPixel(im, px, py, color);
+                       }
+                       cx++;
+               }
+               cx = 0;
+               cy++;
        }
-      cx = 0;
-      cy++;
-    }
 }
 
-void
-gdImageCharUp (gdImagePtr im, gdFontPtr f,
-              int x, int y, int c, int color)
+void gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
 {
-  int cx, cy;
-  int px, py;
-  int fline;
-  cx = 0;
-  cy = 0;
+       int cx, cy;
+       int px, py;
+       int fline;
+       cx = 0;
+       cy = 0;
 #ifdef CHARSET_EBCDIC
-  c = ASC (c);
+       c = ASC (c);
 #endif /*CHARSET_EBCDIC */
-  if ((c < f->offset) || (c >= (f->offset + f->nchars)))
-    {
-      return;
-    }
-  fline = (c - f->offset) * f->h * f->w;
-  for (py = y; (py > (y - f->w)); py--)
-    {
-      for (px = x; (px < (x + f->h)); px++)
-       {
-         if (f->data[fline + cy * f->w + cx])
-           {
-             gdImageSetPixel (im, px, py, color);
-           }
-         cy++;
+       if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
+               return;
+       }
+       fline = (c - f->offset) * f->h * f->w;
+       for (py = y; py > (y - f->w); py--) {
+               for (px = x; px < (x + f->h); px++) {
+                       if (f->data[fline + cy * f->w + cx]) {
+                               gdImageSetPixel(im, px, py, color);
+                       }
+                       cy++;
+               }
+               cy = 0;
+               cx++;
        }
-      cy = 0;
-      cx++;
-    }
 }
 
-void
-gdImageString (gdImagePtr im, gdFontPtr f,
-              int x, int y, unsigned char *s, int color)
+void gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
 {
-  int i;
-  int l;
-  l = strlen ((char *) s);
-  for (i = 0; (i < l); i++)
-    {
-      gdImageChar (im, f, x, y, s[i], color);
-      x += f->w;
-    }
+       int i;
+       int l;
+       l = strlen ((char *) s);
+       for (i = 0; (i < l); i++) {
+               gdImageChar(im, f, x, y, s[i], color);
+               x += f->w;
+       }
 }
 
-void
-gdImageStringUp (gdImagePtr im, gdFontPtr f,
-                int x, int y, unsigned char *s, int color)
+void gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
 {
-  int i;
-  int l;
-  l = strlen ((char *) s);
-  for (i = 0; (i < l); i++)
-    {
-      gdImageCharUp (im, f, x, y, s[i], color);
-      y -= f->w;
-    }
+       int i;
+       int l;
+       l = strlen ((char *) s);
+       for (i = 0; (i < l); i++) {
+               gdImageCharUp(im, f, x, y, s[i], color);
+               y -= f->w;
+       }
 }
 
 static int strlen16 (unsigned short *s);
 
-void
-gdImageString16 (gdImagePtr im, gdFontPtr f,
-                int x, int y, unsigned short *s, int color)
+void gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
 {
-  int i;
-  int l;
-  l = strlen16 (s);
-  for (i = 0; (i < l); i++)
-    {
-      gdImageChar (im, f, x, y, s[i], color);
-      x += f->w;
-    }
+       int i;
+       int l;
+       l = strlen16(s);
+       for (i = 0; (i < l); i++) {
+               gdImageChar(im, f, x, y, s[i], color);
+               x += f->w;
+       }
 }
 
-void
-gdImageStringUp16 (gdImagePtr im, gdFontPtr f,
-                  int x, int y, unsigned short *s, int color)
+void gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
 {
-  int i;
-  int l;
-  l = strlen16 (s);
-  for (i = 0; (i < l); i++)
-    {
-      gdImageCharUp (im, f, x, y, s[i], color);
-      y -= f->w;
-    }
+       int i;
+       int l;
+       l = strlen16(s);
+       for (i = 0; i < l; i++) {
+               gdImageCharUp(im, f, x, y, s[i], color);
+               y -= f->w;
+       }
 }
 
-static int
-strlen16 (unsigned short *s)
+static int strlen16 (unsigned short *s)
 {
-  int len = 0;
-  while (*s)
-    {
-      s++;
-      len++;
-    }
-  return len;
+       int len = 0;
+       while (*s) {
+               s++;
+               len++;
+       }
+       return len;
 }
 
 #ifndef HAVE_LSQRT
 /* If you don't have a nice square root function for longs, you can use
    ** this hack
  */
-long
-lsqrt (long n)
+long lsqrt (long n)
 {
-  long result = (long) sqrt ((double) n);
-  return result;
+       long result = (long) sqrt ((double) n);
+       return result;
 }
 #endif
 
@@ -1531,97 +1548,75 @@ lsqrt (long n)
    See gd_arc_f_buggy.c for a better version that doesn't 
    seem to be bug-free yet. */
 
-void 
-gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
+void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
 {
-       if( (s%360)==(e%360) ){
+       if ((s % 360) == (e % 360)) {
                gdImageEllipse(im, cx, cy, w, h, color);
        } else {
-               gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill);
+               gdImageFilledArc(im, cx, cy, w, h, s, e, color, gdNoFill);
        }
 }
 
-void 
-gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
+void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
 {
-  gdPoint pts[3];
-  int i;
-  int lx = 0, ly = 0;
-  int fx = 0, fy = 0;
-  int w2, h2;
-  w2 = w / 2;
-  h2 = h / 2;
-  while (e < s)
-    {
-      e += 360;
-    }
-  for (i = s; (i <= e); i++)
-    {
-      int x, y;
-      x = ((long) gdCosT[i % 360] * (long) w2 / 1024) + cx;
-      y = ((long) gdSinT[i % 360] * (long) h2 / 1024) + cy;
-      if (i != s)
-       {
-         if (!(style & gdChord))
-           {
-             if (style & gdNoFill)
-               {
-                 gdImageLine (im, lx, ly, x, y, color);
-               }
-             else
-               {
-                 /* This is expensive! */
-                 pts[0].x = lx;
-                 pts[0].y = ly;
-                 pts[1].x = x;
-                 pts[1].y = y;
-                 pts[2].x = cx;
-                 pts[2].y = cy;
-                 gdImageFilledPolygon (im, pts, 3, color);
+       gdPoint pts[3];
+       int i;
+       int lx = 0, ly = 0;
+       int fx = 0, fy = 0;
+
+       while (e < s) {
+               e += 360;
+       }
+       for (i = s; i <= e; i++) {
+               int x, y;
+               x = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
+               y = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
+               if (i != s) {
+                       if (!(style & gdChord)) {
+                               if (style & gdNoFill) {
+                                       gdImageLine(im, lx, ly, x, y, color);
+                               } else {
+                                       /* This is expensive! */
+                                       pts[0].x = lx;
+                                       pts[0].y = ly;
+                                       pts[1].x = x;
+                                       pts[1].y = y;
+                                       pts[2].x = cx;
+                                       pts[2].y = cy;
+                                       gdImageFilledPolygon(im, pts, 3, color);
+                               }
+                       }
+               } else {
+                       fx = x;
+                       fy = y;
+               }
+               lx = x;
+               ly = y;
+       }
+       if (style & gdChord) {
+               if (style & gdNoFill) {
+                       if (style & gdEdged) {
+                               gdImageLine(im, cx, cy, lx, ly, color);
+                               gdImageLine(im, cx, cy, fx, fy, color);
+                       }
+                       gdImageLine(im, fx, fy, lx, ly, color);
+               } else {
+                       pts[0].x = fx;
+                       pts[0].y = fy;
+                       pts[1].x = lx;
+                       pts[1].y = ly;
+                       pts[2].x = cx;
+                       pts[2].y = cy;
+                       gdImageFilledPolygon(im, pts, 3, color);
+               }
+       } else {
+               if (style & gdNoFill) {
+                       if (style & gdEdged) {
+                               gdImageLine(im, cx, cy, lx, ly, color);
+                               gdImageLine(im, cx, cy, fx, fy, color);
+                       }
                }
-           }
-       }
-      else
-       {
-         fx = x;
-         fy = y;
-       }
-      lx = x;
-      ly = y;
-    }
-  if (style & gdChord)
-    {
-      if (style & gdNoFill)
-       {
-         if (style & gdEdged)
-           {
-             gdImageLine (im, cx, cy, lx, ly, color);
-             gdImageLine (im, cx, cy, fx, fy, color);
-           }
-         gdImageLine (im, fx, fy, lx, ly, color);
-       }
-      else
-       {
-         pts[0].x = fx;
-         pts[0].y = fy;
-         pts[1].x = lx;
-         pts[1].y = ly;
-         pts[2].x = cx;
-         pts[2].y = cy;
-         gdImageFilledPolygon (im, pts, 3, color);
-       }
-    }
-  else
-    {
-      if (style & gdNoFill)
-       {
-         if (style & gdEdged)
-           {
-             gdImageLine (im, cx, cy, lx, ly, color);
-             gdImageLine (im, cx, cy, fx, fy, color);
-           }
        }
-    }
 }
 
 
@@ -1795,178 +1790,132 @@ void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
        }
 }
 
-void
-gdImageFill (gdImagePtr im, int x, int y, int color)
+void gdImageFill (gdImagePtr im, int x, int y, int color)
 {
-  int lastBorder;
-  int old;
-  int leftLimit, rightLimit;
-  int i;
-  
-  if (x >= im->sx) {
-       x = im->sx - 1;
-  }
-  
-  if (y >= im->sy) {
-       y = im->sy - 1;
-  }
+       int lastBorder;
+       int old;
+       int leftLimit, rightLimit;
+       int i;
   
-  old = gdImageGetPixel (im, x, y);
-  if (color == gdTiled)
-    {
-      /* Tile fill -- got to watch out! */
-      int p, tileColor;
-      int srcx, srcy;
-      if (!im->tile)
-       {
-         return;
-       }
-      /* Refuse to flood-fill with a transparent pattern --
-         I can't do it without allocating another image */
-      if (gdImageGetTransparent (im->tile) != (-1))
-       {
-         return;
-       }
-      srcx = x % gdImageSX (im->tile);
-      srcy = y % gdImageSY (im->tile);
-      p = gdImageGetPixel (im->tile, srcx, srcy);
-      if (im->trueColor)
-       {
-         tileColor = p;
+       if (x >= im->sx) {
+               x = im->sx - 1;
        }
-      else
-       {
-         if (im->tile->trueColor)
-           {
-             tileColor = gdImageColorResolveAlpha (im,
-                                                   gdTrueColorGetRed (p),
-                                                   gdTrueColorGetGreen (p),
-                                                   gdTrueColorGetBlue (p),
-                                                   gdTrueColorGetAlpha (p));
-           }
-         else
-           {
-             tileColor = im->tileColorMap[p];
-           }
+  
+       if (y >= im->sy) {
+               y = im->sy - 1;
        }
-      if (old == tileColor)
-       {
-         /* Nothing to be done */
-         return;
+  
+       old = gdImageGetPixel(im, x, y);
+       if (color == gdTiled) {
+               /* Tile fill -- got to watch out! */
+               int p, tileColor;
+               int srcx, srcy;
+               if (!im->tile) {
+                       return;
+               }
+               /* Refuse to flood-fill with a transparent pattern I can't do it without allocating another image */
+               if (gdImageGetTransparent(im->tile) != (-1)) {
+                       return;
+               }
+               srcx = x % gdImageSX(im->tile);
+               srcy = y % gdImageSY(im->tile);
+               p = gdImageGetPixel(im->tile, srcx, srcy);
+               if (im->trueColor) {
+                       tileColor = p;
+               } else {
+                       if (im->tile->trueColor) {
+                               tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
+                       } else {
+                               tileColor = im->tileColorMap[p];
+                       }
+               }
+               if (old == tileColor) {
+                       /* Nothing to be done */
+                       return;
+               }
+       } else {
+               if (old == color) {
+                       /* Nothing to be done */
+                       return;
+               }
        }
-    }
-  else
-    {
-      if (old == color)
-       {
-         /* Nothing to be done */
-         return;
+       /* Seek left */
+       leftLimit = (-1);
+       for (i = x; i >= 0; i--) {
+               if (gdImageGetPixel(im, i, y) != old) {
+                       break;
+               }
+               gdImageSetPixel(im, i, y, color);
+               leftLimit = i;
        }
-    }
-  /* Seek left */
-  leftLimit = (-1);
-  for (i = x; (i >= 0); i--)
-    {
-      if (gdImageGetPixel (im, i, y) != old)
-       {
-         break;
+       if (leftLimit == (-1)) {
+               return;
        }
-      gdImageSetPixel (im, i, y, color);
-      leftLimit = i;
-    }
-  if (leftLimit == (-1))
-    {
-      return;
-    }
-  /* Seek right */
-  rightLimit = x;
-  for (i = (x + 1); (i < im->sx); i++)
-    {
-      if (gdImageGetPixel (im, i, y) != old)
-       {
-         break;
+       /* Seek right */
+       rightLimit = x;
+       for (i = (x + 1); i < im->sx; i++) {
+               if (gdImageGetPixel(im, i, y) != old) {
+                       break;
+               }
+               gdImageSetPixel(im, i, y, color);
+               rightLimit = i;
        }
-      gdImageSetPixel (im, i, y, color);
-      rightLimit = i;
-    }
-  /* Look at lines above and below and start paints */
-  /* Above */
-  if (y > 0)
-    {
-      lastBorder = 1;
-      for (i = leftLimit; (i <= rightLimit); i++)
-       {
-         int c;
-         c = gdImageGetPixel (im, i, y - 1);
-         if (lastBorder)
-           {
-             if (c == old)
-               {
-                 gdImageFill (im, i, y - 1, color);
-                 lastBorder = 0;
+       /* Look at lines above and below and start paints */
+       /* Above */
+       if (y > 0) {
+               lastBorder = 1;
+               for (i = leftLimit; i <= rightLimit; i++) {
+                       int c;
+                       c = gdImageGetPixel(im, i, y - 1);
+                       if (lastBorder && c == old) {
+                               gdImageFill (im, i, y - 1, color);
+                               lastBorder = 0;
+                       } else if (c != old) {
+                               lastBorder = 1;
+                       }
                }
-           }
-         else if (c != old)
-           {
-             lastBorder = 1;
-           }
        }
-    }
-  /* Below */
-  if (y < ((im->sy) - 1))
-    {
-      lastBorder = 1;
-      for (i = leftLimit; (i <= rightLimit); i++)
-       {
-         int c;
-         c = gdImageGetPixel (im, i, y + 1);
-         if (lastBorder)
-           {
-             if (c == old)
-               {
-                 gdImageFill (im, i, y + 1, color);
-                 lastBorder = 0;
+       /* Below */
+       if (y < (im->sy - 1)) {
+               lastBorder = 1;
+               for (i = leftLimit; i <= rightLimit; i++) {
+                       int c;
+                       c = gdImageGetPixel(im, i, y + 1);
+                       if (lastBorder && c == old) {
+                               gdImageFill(im, i, y + 1, color);
+                               lastBorder = 0;
+                       } else if (c != old) {
+                               lastBorder = 1;
+                       }
                }
-           }
-         else if (c != old)
-           {
-             lastBorder = 1;
-           }
        }
-    }
 }
 
-void
-gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
 {
-  int x1h = x1, x1v = x1, y1h = y1, y1v = y1, x2h = x2, x2v = x2, y2h = y2,
-    y2v = y2;
-  int thick = im->thick;
-  if (thick > 1)
-    {
-      int half = thick / 2;
-      int half1 = thick - half;
+       int x1h = x1, x1v = x1, y1h = y1, y1v = y1, x2h = x2, x2v = x2, y2h = y2, y2v = y2;
+       int thick = im->thick;
 
-      if (y1 < y2)
-       {
-         y1v = y1h - half;
-         y2v = y2h + half1 - 1;
-       }
-      else
-       {
-         y1v = y1h + half1 - 1;
-         y2v = y2h - half;
+       if (thick > 1) {
+               int half = thick / 2;
+               int half1 = thick - half;
+
+               if (y1 < y2) {
+                       y1v = y1h - half;
+                       y2v = y2h + half1 - 1;
+               } else {
+                       y1v = y1h + half1 - 1;
+                       y2v = y2h - half;
+               }
        }
-    }
 
-  gdImageLine (im, x1h, y1h, x2h, y1h, color);
-  gdImageLine (im, x1h, y2h, x2h, y2h, color);
-  gdImageLine (im, x1v, y1v, x1v, y2v, color);
-  gdImageLine (im, x2v, y1v, x2v, y2v, color);
+       gdImageLine(im, x1h, y1h, x2h, y1h, color);
+       gdImageLine(im, x1h, y2h, x2h, y2h, color);
+       gdImageLine(im, x1v, y1v, x1v, y2v, color);
+       gdImageLine(im, x2v, y1v, x2v, y2v, color);
 }
 
-void
-gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
 {
        int x, y;
   
@@ -1994,14 +1943,14 @@ gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color
        }
 }
 
-void
-gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
+void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
 {
        int c;
        int x, y;
        int tox, toy;
        int i;
        int colorMap[gdMaxColors];
+
        if (dst->trueColor) {
                /* 2.0: much easier when the destination is truecolor. */
                /* 2.0.10: needs a transparent-index check that is still valid if
@@ -2034,14 +1983,14 @@ gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int s
                toy = dstY;
                for (y = srcY; (y < (srcY + h)); y++) {
                        tox = dstX;
-                       for (x = srcX; (x < (srcX + w)); x++) {
+                       for (x = srcX; x < (srcX + w); x++) {
                                int nc;
                                c = gdImageGetPixel (src, x, y);
 
                                /* Get best match possible. */
-                               nc = gdImageColorResolveAlpha (dst, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c), gdTrueColorGetAlpha(c));
+                               nc = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c), gdTrueColorGetAlpha(c));
 
-                               gdImageSetPixel (dst, tox, toy, nc);
+                               gdImageSetPixel(dst, tox, toy, nc);
                                tox++;
                        }
                        toy++;
@@ -2050,13 +1999,13 @@ gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int s
        }
 
        /* Palette based to palette based */
-       for (i = 0; (i < gdMaxColors); i++) {
+       for (i = 0; i < gdMaxColors; i++) {
                colorMap[i] = (-1);
        }
        toy = dstY;
-       for (y = srcY; (y < (srcY + h)); y++) {
+       for (y = srcY; y < (srcY + h); y++) {
                tox = dstX;
-               for (x = srcX; (x < (srcX + w)); x++) {
+               for (x = srcX; x < (srcX + w); x++) {
                        int nc;
                        int mapTo;
                        c = gdImageGetPixel (src, x, y);
@@ -2093,58 +2042,51 @@ gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int s
 
 /* This function is a substitute for real alpha channel operations,
    so it doesn't pay attention to the alpha channel. */
-void
-gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
+void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
 {
+       int c, dc;
+       int x, y;
+       int tox, toy;
+       int ncR, ncG, ncB;
+       toy = dstY;
 
-  int c, dc;
-  int x, y;
-  int tox, toy;
-  int ncR, ncG, ncB;
-  toy = dstY;
-  for (y = srcY; (y < (srcY + h)); y++)
-    {
-      tox = dstX;
-      for (x = srcX; (x < (srcX + w)); x++)
-       {
-         int nc;
-         c = gdImageGetPixel (src, x, y);
-         /* Added 7/24/95: support transparent copies */
-         if (gdImageGetTransparent (src) == c)
-           {
-             tox++;
-             continue;
-           }
-         /* If it's the same image, mapping is trivial */
-         if (dst == src)
-           {
-             nc = c;
-           }
-         else
-           {
-             dc = gdImageGetPixel (dst, tox, toy);
+       for (y = srcY; y < (srcY + h); y++) {
+               tox = dstX;
+               for (x = srcX; x < (srcX + w); x++) {
+                       int nc;
+                       c = gdImageGetPixel(src, x, y);
+                       /* Added 7/24/95: support transparent copies */
+                       if (gdImageGetTransparent(src) == c) {
+                               tox++;
+                               continue;
+                       }
+                       /* 
+                        * If it's the same image, mapping is NOT trivial since we 
+                        * merge with greyscale target, but if pct is 100, the grey 
+                        * value is not used, so it becomes trivial. pjw 2.0.12. 
+                        */
+                       if (dst == src && pct == 100) {
+                               nc = c;
+                       } else {
+                               dc = gdImageGetPixel(dst, tox, toy);
 
-             ncR = (int)(gdImageRed (src, c) * (pct / 100.0f)
-               + gdImageRed (dst, dc) * ((100 - pct) / 100.0f));
-             ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f)
-               + gdImageGreen (dst, dc) * ((100 - pct) / 100.0f));
-             ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f)
-               + gdImageBlue (dst, dc) * ((100 - pct) / 100.0f));
+                               ncR = (int)(gdImageRed (src, c) * (pct / 100.0f) + ((100 - pct) / 100.0f));
+                               ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f) + ((100 - pct) / 100.0f));
+                               ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f) + ((100 - pct) / 100.0f));
 
-             /* Find a reasonable color */
-             nc = gdImageColorResolve (dst, ncR, ncG, ncB);
-           }
-         gdImageSetPixel (dst, tox, toy, nc);
-         tox++;
+                               /* Find a reasonable color */
+                               nc = gdImageColorResolve (dst, ncR, ncG, ncB);
+                       }
+                       gdImageSetPixel (dst, tox, toy, nc);
+                       tox++;
+               }
+               toy++;
        }
-      toy++;
-    }
 }
 
 /* This function is a substitute for real alpha channel operations,
    so it doesn't pay attention to the alpha channel. */
-void
-gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
+void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
 {
        int c, dc;
        int x, y;
@@ -2192,8 +2134,7 @@ gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int sr
        }
 }
 
-void
-gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
+void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
 {
        int c;
        int x, y;
@@ -2757,7 +2698,6 @@ gdImagePtr gdImageRotate45 (gdImagePtr src, double dAngle, int clrBack)
                gdImageSkewY(dst2, dst1, u, iShear, (dOffset - iShear), clrBack);
        }
 
-
        /* 3rd shear */
        gdImageDestroy(dst1);
 
@@ -2843,8 +2783,7 @@ gdImagePtr gdImageRotate (gdImagePtr src, double dAngle, int clrBack)
 }
 /* End Rotate function */
 
-void
-gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
+void gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
 {
        int i;
        int lx, ly;
@@ -2854,6 +2793,14 @@ gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
        if (!n) {
                return;
        }
+
+       /* Let it be known that we are drawing a polygon so that the opacity
+        * mask doesn't get cleared after each line.
+        */
+       if (c == gdAntiAliased) {
+               im->AA_polygon = 1;
+       }
+
        if ( im->antialias) {
                draw_line = gdImageAALine;
        } else {
@@ -2862,283 +2809,269 @@ gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
        lx = p->x;
        ly = p->y;
        draw_line(im, lx, ly, p[n - 1].x, p[n - 1].y, c);
-       for (i = 1; (i < n); i++) {
+       for (i = 1; i < n; i++) {
                p++;
                draw_line(im, lx, ly, p->x, p->y, c);
                lx = p->x;
                ly = p->y;
        }
+
+       if (c == gdAntiAliased) {
+               im->AA_polygon = 0;
+               gdImageAABlend(im);
+       }
 }
 
 int gdCompareInt (const void *a, const void *b);
 
 /* THANKS to Kirsten Schulz for the polygon fixes! */
 
-/* The intersection finding technique of this code could be improved  */
-/* by remembering the previous intertersection, and by using the slope. */
-/* That could help to adjust intersections  to produce a nice */
-/* interior_extrema. */
-
-void
-gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
-{
-  int i;
-  int y;
-  int miny, maxy;
-  int x1, y1;
-  int x2, y2;
-  int ind1, ind2;
-  int ints;
-  if (!n)
-    {
-      return;
-    }
-  if (!im->polyAllocated)
-    {
-      im->polyInts = (int *) gdMalloc (sizeof (int) * n);
-      im->polyAllocated = n;
-    }
-  if (im->polyAllocated < n)
-    {
-      while (im->polyAllocated < n)
-       {
-         im->polyAllocated *= 2;
+/* The intersection finding technique of this code could be improved
+ * by remembering the previous intertersection, and by using the slope.
+ * That could help to adjust intersections  to produce a nice
+ * interior_extrema.
+ */
+
+void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
+{
+       int i;
+       int y;
+       int miny, maxy;
+       int x1, y1;
+       int x2, y2;
+       int ind1, ind2;
+       int ints;
+       int fill_color;
+
+       if (!n) {
+               return;
        }
-      im->polyInts = (int *) gdRealloc (im->polyInts,
-                                       sizeof (int) * im->polyAllocated);
-    }
-  miny = p[0].y;
-  maxy = p[0].y;
-  for (i = 1; (i < n); i++)
-    {
-      if (p[i].y < miny)
-       {
-         miny = p[i].y;
+
+       if (c == gdAntiAliased) {
+               fill_color = im->AA_color;
+       } else {
+               fill_color = c;
        }
-      if (p[i].y > maxy)
-       {
-         maxy = p[i].y;
+       
+       if (!im->polyAllocated) {
+               im->polyInts = (int *) gdMalloc(sizeof(int) * n);
+               im->polyAllocated = n;
        }
-    }
-  /* Fix in 1.3: count a vertex only once */
-  for (y = miny; (y <= maxy); y++)
-    {
-/*1.4           int interLast = 0; */
-/*              int dirLast = 0; */
-/*              int interFirst = 1; */
-      ints = 0;
-      for (i = 0; (i < n); i++)
-       {
-         if (!i)
-           {
-             ind1 = n - 1;
-             ind2 = 0;
-           }
-         else
-           {
-             ind1 = i - 1;
-             ind2 = i;
-           }
-         y1 = p[ind1].y;
-         y2 = p[ind2].y;
-         if (y1 < y2)
-           {
-             x1 = p[ind1].x;
-             x2 = p[ind2].x;
-           }
-         else if (y1 > y2)
-           {
-             y2 = p[ind1].y;
-             y1 = p[ind2].y;
-             x2 = p[ind1].x;
-             x1 = p[ind2].x;
-           }
-         else
-           {
-             continue;
-           }
-         if ((y >= y1) && (y < y2))
-           {
-             im->polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
-           }
-         else if ((y == maxy) && (y > y1) && (y <= y2))
-           {
-             im->polyInts[ints++] = (y - y1) * (x2 - x1) / (y2 - y1) + x1;
-           }
+       if (im->polyAllocated < n) {
+               while (im->polyAllocated < n) {
+                       im->polyAllocated *= 2;
+               }
+               im->polyInts = (int *) gdRealloc(im->polyInts, sizeof(int) * im->polyAllocated);
+       }
+       miny = p[0].y;
+       maxy = p[0].y;
+       for (i = 1; i < n; i++) {
+               if (p[i].y < miny) {
+                       miny = p[i].y;
+               }
+               if (p[i].y > maxy) {
+                       maxy = p[i].y;
+               }
+       }
+       /* Fix in 1.3: count a vertex only once */
+       for (y = miny; y <= maxy; y++) {
+               /*1.4           int interLast = 0; */
+               /*              int dirLast = 0; */
+               /*              int interFirst = 1; */
+               ints = 0;
+               for (i = 0; i < n; i++) {
+                       if (!i) {
+                               ind1 = n - 1;
+                               ind2 = 0;
+                       } else {
+                               ind1 = i - 1;
+                               ind2 = i;
+                       }
+                       y1 = p[ind1].y;
+                       y2 = p[ind2].y;
+                       if (y1 < y2) {
+                               x1 = p[ind1].x;
+                               x2 = p[ind2].x;
+                       } else if (y1 > y2) {
+                               y2 = p[ind1].y;
+                               y1 = p[ind2].y;
+                               x2 = p[ind1].x;
+                               x1 = p[ind2].x;
+                       } else {
+                               continue;
+                       }
+                       /* Do the following math as float intermediately, and round to ensure
+                        * that Polygon and FilledPolygon for the same set of points have the
+                        * same footprint.
+                        */
+                       if (y >= y1 && y < y2) {
+                               im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
+                       } else if (y == maxy && y > y1 && y <= y2) {
+                               im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
+                       }
+               }
+               qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
+
+               for (i = 0; i < ints; i += 2) {
+                       gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, fill_color);
+               }
        }
-      qsort (im->polyInts, ints, sizeof (int), gdCompareInt);
 
-      for (i = 0; (i < (ints)); i += 2)
-       {
-         gdImageLine (im, im->polyInts[i], y,
-                      im->polyInts[i + 1], y, c);
+       /* If we are drawing this AA, then redraw the border with AA lines. */
+       if (c == gdAntiAliased) {
+               gdImagePolygon(im, p, n, c);
        }
-    }
 }
 
-int
-gdCompareInt (const void *a, const void *b)
+int gdCompareInt (const void *a, const void *b)
 {
-  return (*(const int *) a) - (*(const int *) b);
+       return (*(const int *) a) - (*(const int *) b);
 }
 
-void
-gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
+void gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
 {
-  if (im->style)
-    {
-      gdFree (im->style);
-    }
-  im->style = (int *)
-    gdMalloc (sizeof (int) * noOfPixels);
-  memcpy (im->style, style, sizeof (int) * noOfPixels);
-  im->styleLength = noOfPixels;
-  im->stylePos = 0;
+       if (im->style) {
+               gdFree(im->style);
+       }
+       im->style = (int *) gdMalloc(sizeof(int) * noOfPixels);
+       memcpy(im->style, style, sizeof(int) * noOfPixels);
+       im->styleLength = noOfPixels;
+       im->stylePos = 0;
 }
 
-void
-gdImageSetThickness (gdImagePtr im, int thickness)
+void gdImageSetThickness (gdImagePtr im, int thickness)
 {
-  im->thick = thickness;
+       im->thick = thickness;
 }
 
-void
-gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
+void gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
 {
-  int i;
-  im->brush = brush;
-  if ((!im->trueColor) && (!im->brush->trueColor))
-    {
-      for (i = 0; (i < gdImageColorsTotal (brush)); i++)
-       {
-         int index;
-         index = gdImageColorResolveAlpha (im,
-                                           gdImageRed (brush, i),
-                                           gdImageGreen (brush, i),
-                                           gdImageBlue (brush, i),
-                                           gdImageAlpha (brush, i));
-         im->brushColorMap[i] = index;
+       int i;
+       im->brush = brush;
+       if (!im->trueColor && !im->brush->trueColor) {
+               for (i = 0; i < gdImageColorsTotal(brush); i++) {
+                       int index;
+                       index = gdImageColorResolveAlpha(im, gdImageRed(brush, i), gdImageGreen(brush, i), gdImageBlue(brush, i), gdImageAlpha(brush, i));
+                       im->brushColorMap[i] = index;
+               }
        }
-    }
 }
 
-void
-gdImageSetTile (gdImagePtr im, gdImagePtr tile)
+void gdImageSetTile (gdImagePtr im, gdImagePtr tile)
 {
-  int i;
-  im->tile = tile;
-  if ((!im->trueColor) && (!im->tile->trueColor))
-    {
-      for (i = 0; (i < gdImageColorsTotal (tile)); i++)
-       {
-         int index;
-         index = gdImageColorResolveAlpha (im,
-                                           gdImageRed (tile, i),
-                                           gdImageGreen (tile, i),
-                                           gdImageBlue (tile, i),
-                                           gdImageAlpha (tile, i));
-         im->tileColorMap[i] = index;
+       int i;
+       im->tile = tile;
+       if (!im->trueColor && !im->tile->trueColor) {
+               for (i = 0; i < gdImageColorsTotal(tile); i++) {
+                       int index;
+                       index = gdImageColorResolveAlpha(im, gdImageRed(tile, i), gdImageGreen(tile, i), gdImageBlue(tile, i), gdImageAlpha(tile, i));
+                       im->tileColorMap[i] = index;
+               }
        }
-    }
 }
 
-void
-gdImageInterlace (gdImagePtr im, int interlaceArg)
+void gdImageSetAntiAliased (gdImagePtr im, int c)
 {
-  im->interlace = interlaceArg;
+       im->AA = 1;
+       im->AA_color = c;
+       im->AA_dont_blend = -1;
 }
 
-int
-gdImageCompare (gdImagePtr im1, gdImagePtr im2)
+void gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
 {
-  int x, y;
-  int p1, p2;
-  int cmpStatus = 0;
-  int sx, sy;
+       im->AA = 1;
+       im->AA_color = c;
+       im->AA_dont_blend = dont_blend;
+}
 
-  if (im1->interlace != im2->interlace)
-    {
-      cmpStatus |= GD_CMP_INTERLACE;
-    }
 
-  if (im1->transparent != im2->transparent)
-    {
-      cmpStatus |= GD_CMP_TRANSPARENT;
-    }
+void gdImageInterlace (gdImagePtr im, int interlaceArg)
+{
+       im->interlace = interlaceArg;
+}
 
-  if (im1->trueColor != im2->trueColor)
-    {
-      cmpStatus |= GD_CMP_TRUECOLOR;
-    }
+int gdImageCompare (gdImagePtr im1, gdImagePtr im2)
+{
+       int x, y;
+       int p1, p2;
+       int cmpStatus = 0;
+       int sx, sy;
 
-  sx = im1->sx;
-  if (im1->sx != im2->sx)
-    {
-      cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
-      if (im2->sx < im1->sx)
-       {
-         sx = im2->sx;
+       if (im1->interlace != im2->interlace) {
+               cmpStatus |= GD_CMP_INTERLACE;
        }
-    }
 
-  sy = im1->sy;
-  if (im1->sy != im2->sy)
-    {
-      cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
-      if (im2->sy < im1->sy)
-       {
-         sy = im2->sy;
+       if (im1->transparent != im2->transparent) {
+               cmpStatus |= GD_CMP_TRANSPARENT;
        }
-    }
 
-  if (im1->colorsTotal != im2->colorsTotal)
-    {
-      cmpStatus |= GD_CMP_NUM_COLORS;
-    }
+       if (im1->trueColor != im2->trueColor) {
+               cmpStatus |= GD_CMP_TRUECOLOR;
+       }
 
-  for (y = 0; (y < sy); y++)
-    {
-      for (x = 0; (x < sx); x++)
-       {
-         p1 = im1->pixels[y][x];
-         p2 = im2->pixels[y][x];
-         if (gdImageRed (im1, p1) != gdImageRed (im2, p2))
-           {
-             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
-             break;
-           }
-         if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2))
-           {
-             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
-             break;
-           }
-         if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2))
-           {
-             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
-             break;
-           }
+       sx = im1->sx;
+       if (im1->sx != im2->sx) {
+               cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
+               if (im2->sx < im1->sx) {
+                       sx = im2->sx;
+               }
+       }
+
+       sy = im1->sy;
+       if (im1->sy != im2->sy) {
+               cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
+               if (im2->sy < im1->sy) {
+                       sy = im2->sy;
+               }
+       }
+
+       if (im1->colorsTotal != im2->colorsTotal) {
+               cmpStatus |= GD_CMP_NUM_COLORS;
+       }
+
+       for (y = 0; y < sy; y++) {
+               for (x = 0; x < sx; x++) {
+                       p1 = im1->trueColor ? gdImageTrueColorPixel(im1, x, y) : gdImagePalettePixel(im1, x, y);
+                       p2 = im2->trueColor ? gdImageTrueColorPixel(im2, x, y) : gdImagePalettePixel(im2, x, y);
+
+                       if (gdImageRed(im1, p1) != gdImageRed(im2, p2)) {
+                               cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+                               break;
+                       }
+                       if (gdImageGreen(im1, p1) != gdImageGreen(im2, p2)) {
+                               cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+                               break;
+                       }
+                       if (gdImageBlue(im1, p1) != gdImageBlue(im2, p2)) {
+                               cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+                               break;
+                       }
 #if 0
-         /* Soon we'll add alpha channel to palettes */
-         if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2))
-           {
-             cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
-             break;
-           }
+                       /* Soon we'll add alpha channel to palettes */
+                       if (gdImageAlpha(im1, p1) != gdImageAlpha(im2, p2)) {
+                               cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+                               break;
+                       }
 #endif
+               }
+               if (cmpStatus & GD_CMP_COLOR) {
+                       break;
+               }
        }
-      if (cmpStatus & GD_CMP_COLOR)
-       {
-         break;
-       };
-    }
 
-  return cmpStatus;
+       return cmpStatus;
 }
 
 int
 gdAlphaBlend (int dst, int src)
 {
-  return (((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
+       /* 2.0.12: TBB: alpha in the destination should be a 
+        * component of the result. Thanks to Frank Warmerdam for
+        * pointing out the issue.
+        */
+       return ((((gdTrueColorGetAlpha (src) *
+            gdTrueColorGetAlpha (dst)) / gdAlphaMax) << 24) +
+         ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
             gdTrueColorGetRed (src) / gdAlphaMax) +
            (gdTrueColorGetAlpha (src) *
             gdTrueColorGetRed (dst)) / gdAlphaMax) << 16) +
@@ -3152,28 +3085,24 @@ gdAlphaBlend (int dst, int src)
            gdTrueColorGetBlue (dst)) / gdAlphaMax));
 }
 
-void
-gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
+void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
 {
-  im->alphaBlendingFlag = alphaBlendingArg;
+       im->alphaBlendingFlag = alphaBlendingArg;
 }
 
-void
-gdImageAntialias (gdImagePtr im, int antialias)
+void gdImageAntialias (gdImagePtr im, int antialias)
 {
        if (im->trueColor){
                im->antialias = antialias;
        }
 }
 
-void
-gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
+void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
 {
-  im->saveAlphaFlag = saveAlphaArg;
+       im->saveAlphaFlag = saveAlphaArg;
 }
 
-static int
-gdFullAlphaBlend (int dst, int src)
+static int gdFullAlphaBlend (int dst, int src)
 {
        int a1, a2;
        a1 = gdAlphaTransparent - gdTrueColorGetAlpha(src);
@@ -3186,8 +3115,7 @@ gdFullAlphaBlend (int dst, int src)
                );
 }
 
-static int
-gdAlphaBlendColor( int b1, int b2, int a1, int a2 )
+static int gdAlphaBlendColor( int b1, int b2, int a1, int a2 )
 {
        int c;
        int w;
@@ -3212,8 +3140,7 @@ gdAlphaBlendColor( int b1, int b2, int a1, int a2 )
        return ( a1 * b1 + ( gdAlphaMax - a1 ) * c ) / gdAlphaMax;
 }
 
-static int
-gdLayerOverlay (int dst, int src)
+static int gdLayerOverlay (int dst, int src)
 {
        int a1, a2;
        a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
@@ -3225,8 +3152,7 @@ gdLayerOverlay (int dst, int src)
                );
 }
 
-static int
-gdAlphaOverlayColor( int src, int dst, int max )
+static int gdAlphaOverlayColor (int src, int dst, int max )
 {
        /* this function implements the algorithm
         * 
@@ -3246,3 +3172,43 @@ gdAlphaOverlayColor( int src, int dst, int max )
                return dst * src / max;
        }
 }
+
+void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
+{
+       if (x1 < 0) {
+               x1 = 0;
+       }
+       if (x1 >= im->sx) {
+               x1 = im->sx - 1;
+       }
+       if (x2 < 0) {
+               x2 = 0;
+       }
+       if (x2 >= im->sx) {
+               x2 = im->sx - 1;
+       }
+       if (y1 < 0) {
+               y1 = 0;
+       }
+       if (y1 >= im->sy) {
+               y1 = im->sy - 1;
+       }
+       if (y2 < 0) {
+               y2 = 0;
+       }
+       if (y2 >= im->sy) {
+               y2 = im->sy - 1;
+       }
+       im->cx1 = x1;
+       im->cy1 = y1;
+       im->cx2 = x2;
+       im->cy2 = y2;
+}
+
+void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
+{
+       *x1P = im->cx1;
+       *y1P = im->cy1;
+       *x2P = im->cx2;
+       *y2P = im->cy2;
+}
index 6fa9914191d77c206b0c56360811574d5c08035c..2188d2ccecdbc88ccebbf1a71363a550d39c4981 100644 (file)
@@ -147,6 +147,31 @@ typedef struct gdImageStruct {
                PNG at the moment; other future formats may also
                have that capability. JPEG doesn't. */
        int saveAlphaFlag;
+       
+
+       /* 2.0.12: anti-aliased globals */
+       int AA;
+       int AA_color;
+       int AA_dont_blend;
+       unsigned char **AA_opacity;
+       int AA_polygon;
+       /* Stored and pre-computed variables for determining the perpendicular
+        * distance from a point to the anti-aliased line being drawn: 
+        */
+       int AAL_x1;
+       int AAL_y1;
+       int AAL_x2;
+       int AAL_y2;
+       int AAL_Bx_Ax;
+       int AAL_By_Ay;
+       int AAL_LAB_2;
+       float AAL_LAB;
+
+       /* 2.0.12: simple clipping rectangle. These values must be checked for safety when set; please use gdImageSetClip */
+       int cx1;
+       int cy1;
+       int cx2;
+       int cy2;
 } gdImage;
 
 typedef gdImage * gdImagePtr;
@@ -184,6 +209,8 @@ typedef gdFont *gdFontPtr;
        This is used in line styles only. */
 #define gdTransparent (-6)
 
+#define gdAntiAliased (-7)
+
 /* Functions to manipulate images. */
 
 /* Creates a palette-based image (up to 256 colors). */
@@ -245,6 +272,8 @@ void gdImageSetPixel(gdImagePtr im, int x, int y, int color);
 
 int gdImageGetPixel(gdImagePtr im, int x, int y);
 
+void gdImageAABlend(gdImagePtr im);
+
 void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
 void gdImageAALine(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
 
@@ -256,6 +285,8 @@ void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
 void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
 /* Solid bar. Upper left corner first, lower right corner second. */
 void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
+void gdImageSetClip(gdImagePtr im, int x1, int y1, int x2, int y2);
+void gdImageGetClip(gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P);
 void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color);
 void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color);
 void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color);
@@ -275,10 +306,22 @@ char *gdImageStringFT(gdImage *im, int *brect, int fg, char *fontlist,
                 double ptsize, double angle, int x, int y, char *string);
 
 typedef struct {
-       int flags; /* for future expansion logical OR of gdFTEX_ values */
-       double linespacing; /* fine tune line spacing for '\n' */
-} gdFTStringExtra, *gdFTStringExtraPtr;
+       double linespacing;     /* fine tune line spacing for '\n' */
+       int flags;              /* Logical OR of gdFTEX_ values */
+       int charmap;            /* TBB: 2.0.12: may be gdFTEX_Unicode,
+                                  gdFTEX_Shift_JIS, or gdFTEX_Big5;
+                                  when not specified, maps are searched
+                                  for in the above order. */
+}
+ gdFTStringExtra, *gdFTStringExtraPtr;
+
 #define gdFTEX_LINESPACE 1
+#define gdFTEX_CHARMAP 2
+
+/* These are NOT flags; set one in 'charmap' if you set the gdFTEX_CHARMAP bit in 'flags'. */
+#define gdFTEX_Unicode 0
+#define gdFTEX_Shift_JIS 1
+#define gdFTEX_Big5 2
 
 /* FreeType 2 text output with fine tuning */
 char *
@@ -373,6 +416,13 @@ void gdImageColorTransparent(gdImagePtr im, int color);
 void gdImagePaletteCopy(gdImagePtr dst, gdImagePtr src);
 void gdImagePng(gdImagePtr im, FILE *out);
 void gdImagePngCtx(gdImagePtr im, gdIOCtx *out);
+/* 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all,
+ * 1 is FASTEST but produces larger files, 9 provides the best
+ * compression (smallest files) but takes a long time to compress, and
+ * -1 selects the default compiled into the zlib library. 
+ */
+void gdImagePngEx(gdImagePtr im, FILE * out, int level);
+void gdImagePngCtxEx(gdImagePtr im, gdIOCtx * out, int level);
 
 void gdImageWBMP(gdImagePtr image, int fg, FILE *out);
 void gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtx *out);
@@ -416,6 +466,7 @@ void* gdImagePngPtr(gdImagePtr im, int *size);
 
 /* Best to free this memory with gdFree(), not free() */
 void* gdImageGdPtr(gdImagePtr im, int *size);
+void *gdImagePngPtrEx(gdImagePtr im, int *size, int level);
 
 /* Best to free this memory with gdFree(), not free() */
 void* gdImageGd2Ptr(gdImagePtr im, int cs, int fmt, int *size);
@@ -474,6 +525,8 @@ gdImagePtr gdImageRotate (gdImagePtr src, double dAngle, int clrBack);
 
 void gdImageSetBrush(gdImagePtr im, gdImagePtr brush);
 void gdImageSetTile(gdImagePtr im, gdImagePtr tile);
+void gdImageSetAntiAliased(gdImagePtr im, int c);
+void gdImageSetAntiAliasedDontBlend(gdImagePtr im, int c, int dont_blend);
 void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels);
 /* Line thickness (defaults to 1). Affects lines, ellipses, 
        rectangles, polygons and so forth. */
index 53b1c71f99a1720abbfa6ac6e6219b2cf8aba728..28755a8412304b58c4fa0cf38586037a636827b6 100644 (file)
@@ -20,252 +20,246 @@ extern void gdImageGd (gdImagePtr im, FILE * out);
 /* */
 /* Shared code to read color tables from gd file. */
 /* */
-int
-_gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag)
+int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag)
 {
-  int i;
-  if (gd2xFlag)
-    {
-      if (!gdGetByte (&im->trueColor, in))
-       {
-         goto fail1;
+       int i;
+       if (gd2xFlag) {
+               int trueColorFlag;
+               if (!gdGetByte(&trueColorFlag, in)) {
+                       goto fail1;
+               }
+               /* 2.0.12: detect bad truecolor .gd files created by pre-2.0.12.
+                * Beginning in 2.0.12 truecolor is indicated by the initial 2-byte
+                * signature.
+                */
+               if (trueColorFlag != im->trueColor) {
+                       goto fail1;
+               }
+               /* This should have been a word all along */
+               if (!im->trueColor) {
+                       if (!gdGetWord(&im->colorsTotal, in)) {
+                               goto fail1;
+                       }
+               }
+               /* Int to accommodate truecolor single-color transparency */
+               if (!gdGetInt(&im->transparent, in)) {
+                       goto fail1;
+               }
+       } else {
+               if (!gdGetByte(&im->colorsTotal, in)) {
+                       goto fail1;
+               }
+               if (!gdGetWord(&im->transparent, in)) {
+                       goto fail1;
+               }
+               if (im->transparent == 257) {
+                       im->transparent = (-1);
+               }
        }
-      /* This should have been a word all along */
-      if (!im->trueColor)
-       {
-         if (!gdGetWord (&im->colorsTotal, in))
-           {
-             goto fail1;
-           }
-       }
-      /* Int to accommodate truecolor single-color transparency */
-      if (!gdGetInt (&im->transparent, in))
-       {
-         goto fail1;
-       }
-    }
-  else
-    {
-      if (!gdGetByte (&im->colorsTotal, in))
-       {
-         goto fail1;
-       }
-      if (!gdGetWord (&im->transparent, in))
-       {
-         goto fail1;
-       }
-      if (im->transparent == 257)
-       {
-         im->transparent = (-1);
-       }
-    }
-  GD2_DBG (printf ("Pallette had %d colours (T=%d)\n", im->colorsTotal, im->transparent));
-
-  for (i = 0; (i < gdMaxColors); i++)
-    {
-      if (!gdGetByte (&im->red[i], in))
-       {
-         goto fail1;
-       }
-      if (!gdGetByte (&im->green[i], in))
-       {
-         goto fail1;
-       }
-      if (!gdGetByte (&im->blue[i], in))
-       {
-         goto fail1;
+
+       GD2_DBG(printf("Pallette had %d colours (T=%d)\n", im->colorsTotal, im->transparent));
+       
+       if (im->trueColor) {
+               return TRUE;
        }
-      if (gd2xFlag)
-       {
-         if (!gdGetByte (&im->alpha[i], in))
-           {
-             goto fail1;
-           }
+
+       for (i = 0; i < gdMaxColors; i++) {
+               if (!gdGetByte(&im->red[i], in)) {
+                       goto fail1;
+               }
+               if (!gdGetByte(&im->green[i], in)) {
+                       goto fail1;
+               }
+               if (!gdGetByte(&im->blue[i], in)) {
+                       goto fail1;
+               }
+               if (gd2xFlag) {
+                       if (!gdGetByte(&im->alpha[i], in)) {
+                               goto fail1;
+                       }
+               }
        }
-    }
 
-  for (i = 0; (i < im->colorsTotal); i++)
-    {
-      im->open[i] = 0;
-    };
+       for (i = 0; i < im->colorsTotal; i++) {
+               im->open[i] = 0;
+       }
 
-  return TRUE;
+       return TRUE;
 fail1:
-  return FALSE;
+       return FALSE;
 }
 
 /* */
 /* Use the common basic header info to make the image object. */
-/* This is also called from _gd2CreateFromFile */
 /* */
-static
-  gdImagePtr
-_gdCreateFromFile (gdIOCtx * in, int *sx, int *sy)
+static gdImagePtr _gdCreateFromFile (gdIOCtx * in, int *sx, int *sy)
 {
-  gdImagePtr im;
-  int gd2xFlag = 0;
-  if (!gdGetWord (sx, in))
-    {
-      goto fail1;
-    }
-  if (*sx == 65535)
-    {
-      /* This is a gd 2.0 .gd file */
-      gd2xFlag = 1;
-      if (!gdGetWord (sx, in))
-       {
-         goto fail1;
-       }
-    }
-  if (!gdGetWord (sy, in))
-    {
-      goto fail1;
-    }
+       gdImagePtr im;
+       int gd2xFlag = 0;
+       int trueColorFlag = 0;
 
-  GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
+       if (!gdGetWord(sx, in)) {
+               goto fail1;
+       }
+       if (*sx == 65535 || *sx == 65534) {
+               /* This is a gd 2.0 .gd file */
+               gd2xFlag = 1;
+               /* 2.0.12: 65534 signals a truecolor .gd file. There is a slight redundancy here but we can live with it. */
+               if (*sx == 65534) {
+                       trueColorFlag = 1;
+               }
+               if (!gdGetWord(sx, in)) {
+                       goto fail1;
+               }
+       }
+       if (!gdGetWord(sy, in)) {
+               goto fail1;
+       }
 
-  im = gdImageCreate (*sx, *sy);
+       GD2_DBG(printf("Image is %dx%d\n", *sx, *sy));
 
-  if (!_gdGetColors (in, im, gd2xFlag))
-    {
-      goto fail2;
-    }
+       if (trueColorFlag) {
+               im = gdImageCreateTrueColor(*sx, *sy);
+       } else {
+               im = gdImageCreate(*sx, *sy);
+       }
+       if (!_gdGetColors(in, im, gd2xFlag)) {
+               goto fail2;
+       }
 
-  return im;
+       return im;
 fail2:
-  gdImageDestroy (im);
+       gdImageDestroy(im);
 fail1:
-  return 0;
+       return 0;
 }
 
-gdImagePtr
-gdImageCreateFromGd (FILE * inFile)
+gdImagePtr gdImageCreateFromGd (FILE * inFile)
 {
-  gdImagePtr im;
-  gdIOCtx *in;
+       gdImagePtr im;
+       gdIOCtx *in;
 
-  in = gdNewFileCtx (inFile);
-  im = gdImageCreateFromGdCtx (in);
+       in = gdNewFileCtx(inFile);
+       im = gdImageCreateFromGdCtx(in);
 
-  in->gd_free (in);
+       in->gd_free(in);
 
-  return im;
+       return im;
 }
 
-gdImagePtr
-gdImageCreateFromGdCtx (gdIOCtxPtr in)
+gdImagePtr gdImageCreateFromGdCtx (gdIOCtxPtr in)
 {
-  int sx, sy;
-  int x, y;
-  gdImagePtr im;
-
-  /* Read the header */
-  im = _gdCreateFromFile (in, &sx, &sy);
-
-  if (im == NULL)
-    {
-      goto fail1;
-    };
-
-  /* Then the data... */
-  for (y = 0; (y < sy); y++)
-    {
-      for (x = 0; (x < sx); x++)
-       {
-         int ch;
-         ch = gdGetC (in);
-         if (ch == EOF)
-           {
-             goto fail2;
-           }
-         /* ROW-MAJOR IN GD 1.3 */
-         im->pixels[y][x] = ch;
+       int sx, sy;
+       int x, y;
+       gdImagePtr im;
+
+       /* Read the header */
+       im = _gdCreateFromFile(in, &sx, &sy);
+
+       if (im == NULL) {
+               goto fail1;
        }
-    }
 
-  return im;
+       /* Then the data... */
+       /* 2.0.12: support truecolor properly in .gd as well as in .gd2. Problem reported by Andreas Pfaller. */
+       if (im->trueColor) {
+               for (y = 0; y < sy; y++) {
+                       for (x = 0; x < sx; x++) {
+                               int pix;
+                               if (!gdGetInt(&pix, in)) {
+                                       goto fail2;
+                               }
+                               im->tpixels[y][x] = pix;
+                       }
+               }
+       } else {
+               for (y = 0; y < sy; y++) {
+                       for (x = 0; x < sx; x++) {
+                               int ch;
+                               ch = gdGetC(in);
+                               if (ch == EOF) {
+                                       goto fail2;
+                               }
+                               /* ROW-MAJOR IN GD 1.3 */
+                               im->pixels[y][x] = ch;
+                       }
+               }
+       }
+
+       return im;
 
 fail2:
-  gdImageDestroy (im);
+       gdImageDestroy (im);
 fail1:
-  return 0;
+       return 0;
 }
 
-void
-_gdPutColors (gdImagePtr im, gdIOCtx * out)
+void _gdPutColors (gdImagePtr im, gdIOCtx * out)
 {
-  int i;
-
-  gdPutC (im->trueColor, out);
-  if (!im->trueColor)
-    {
-      gdPutWord (im->colorsTotal, out);
-    }
-  gdPutInt (im->transparent, out);
-  if (!im->trueColor)
-    {
-      for (i = 0; (i < gdMaxColors); i++)
-       {
-         gdPutC ((unsigned char) im->red[i], out);
-         gdPutC ((unsigned char) im->green[i], out);
-         gdPutC ((unsigned char) im->blue[i], out);
-         gdPutC ((unsigned char) im->alpha[i], out);
+       int i;
+
+       gdPutC(im->trueColor, out);
+       if (!im->trueColor) {
+               gdPutWord(im->colorsTotal, out);
+       }
+       gdPutInt(im->transparent, out);
+       if (!im->trueColor) {
+               for (i = 0; i < gdMaxColors; i++) {
+                       gdPutC((unsigned char) im->red[i], out);
+                       gdPutC((unsigned char) im->green[i], out);
+                       gdPutC((unsigned char) im->blue[i], out);
+                       gdPutC((unsigned char) im->alpha[i], out);
+               }
        }
-    }
 }
 
-static
-void
-_gdPutHeader (gdImagePtr im, gdIOCtx * out)
+static void _gdPutHeader (gdImagePtr im, gdIOCtx * out)
 {
-  /* 65535 indicates this is a gd 2.x .gd file. */
-  gdPutWord (65535, out);
-  gdPutWord (im->sx, out);
-  gdPutWord (im->sy, out);
-
-  _gdPutColors (im, out);
+       /* 65535 indicates this is a gd 2.x .gd file.  
+        * 2.0.12: 65534 indicates truecolor.
+        */
+       if (im->trueColor) {
+               gdPutWord(65534, out);
+       } else {
+               gdPutWord(65535, out);
+       }
+       gdPutWord(im->sx, out);
+       gdPutWord(im->sy, out);
 
+       _gdPutColors(im, out);
 }
 
-static void
-_gdImageGd (gdImagePtr im, gdIOCtx * out)
+static void _gdImageGd (gdImagePtr im, gdIOCtx * out)
 {
-  int x, y;
-
-  _gdPutHeader (im, out);
-
-  for (y = 0; (y < im->sy); y++)
-    {
-      for (x = 0; (x < im->sx); x++)
-       {
-         /* ROW-MAJOR IN GD 1.3 */
-         if (im->trueColor)
-           {
-             gdPutInt (im->tpixels[y][x], out);
-           }
-         else
-           {
-             gdPutC ((unsigned char) im->pixels[y][x], out);
-           }
+       int x, y;
+
+       _gdPutHeader(im, out);
+
+       for (y = 0; y < im->sy; y++) {
+               for (x = 0; x < im->sx; x++) {
+                       /* ROW-MAJOR IN GD 1.3 */
+                       if (im->trueColor) {
+                               gdPutInt(im->tpixels[y][x], out);
+                       } else {
+                               gdPutC((unsigned char) im->pixels[y][x], out);
+                       }
+               }
        }
-    }
 }
 
-void
-gdImageGd (gdImagePtr im, FILE * outFile)
+void gdImageGd (gdImagePtr im, FILE * outFile)
 {
-  gdIOCtx *out = gdNewFileCtx (outFile);
-  _gdImageGd (im, out);
-  out->gd_free (out);
+       gdIOCtx *out = gdNewFileCtx(outFile);
+       _gdImageGd(im, out);
+       out->gd_free(out);
 }
 
-void *
-gdImageGdPtr (gdImagePtr im, int *size)
+void *gdImageGdPtr (gdImagePtr im, int *size)
 {
-  void *rv;
-  gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
-  _gdImageGd (im, out);
-  rv = gdDPExtractData (out, size);
-  out->gd_free (out);
-  return rv;
+       void *rv;
+       gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+       _gdImageGd(im, out);
+       rv = gdDPExtractData(out, size);
+       out->gd_free(out);
+       return rv;
 }
index 59c711763ba16545a276a6110570d68d635e62a3..00a69e9d87658b1549ed3de504ca85e1e0635a2d 100644 (file)
@@ -293,7 +293,7 @@ gdImagePtr gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
                        if (gd2_compressed(fmt)) {
                                chunkLen = chunkMax;
 
-                               if (!_gd2ReadChunk(chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, chunkBuf, &chunkLen, in)) {
+                               if (!_gd2ReadChunk(chunkIdx[chunkNum].offset, compBuf, chunkIdx[chunkNum].size, (char *) chunkBuf, &chunkLen, in)) {
                                        GD2_DBG(php_gd_error("Error reading comproessed chunk\n"));
                                        goto fail2;
                                }
@@ -391,9 +391,11 @@ gdImagePtr gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w,
        int x, y, ylo, yhi, xlo, xhi;
        int dstart, dpos;
        int i;
-       int ch, vers, fmt;
+       /* 2.0.12: unsigned is correct; fixes problems with color munging. Thanks to Steven Brown. */
+       unsigned int ch;
+       int vers, fmt;
        t_chunk_info *chunkIdx = NULL;
-       char *chunkBuf = NULL;
+       unsigned char *chunkBuf = NULL;
        int chunkNum;
        int chunkMax = 0;
        uLongf chunkLen;
index c28379abd85e984cf54a5931ed137969c8757e7e..a2da9cf031ecca89c1a697958f5730549590e0f5 100644 (file)
@@ -2,6 +2,10 @@
 #define GD_IO_H 1
 
 #include <stdio.h>
+
+#ifdef VMS
+#define Putchar gdPutchar
+#endif
  
 typedef struct gdIOCtx {
        int     (*getC)(struct gdIOCtx*);
index 7794dc890bc9ba9fec47311a3b8e9bdef72af5af..d6ea05f69960ecacd6b5397aedab8f78c57a5928 100644 (file)
@@ -46,8 +46,7 @@ typedef struct _jmpbuf_wrapper
 } jmpbuf_wrapper;
 
 /* Called by the IJG JPEG library upon encountering a fatal error */
-static void
-fatal_jpeg_error (j_common_ptr cinfo)
+static void fatal_jpeg_error (j_common_ptr cinfo)
 {
        jmpbuf_wrapper *jmpbufw;
 
@@ -76,16 +75,14 @@ fatal_jpeg_error (j_common_ptr cinfo)
  * library documentation for more details.
  */
 
-void
-gdImageJpeg (gdImagePtr im, FILE * outFile, int quality)
+void gdImageJpeg (gdImagePtr im, FILE * outFile, int quality)
 {
        gdIOCtx *out = gdNewFileCtx (outFile);
        gdImageJpegCtx (im, out, quality);
        out->gd_free (out);
 }
 
-void *
-gdImageJpegPtr (gdImagePtr im, int *size, int quality)
+void *gdImageJpegPtr (gdImagePtr im, int *size, int quality)
 {
        void *rv;
        gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
@@ -98,8 +95,7 @@ gdImageJpegPtr (gdImagePtr im, int *size, int quality)
 
 void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile);
 
-void
-gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
+void gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
 {
        struct jpeg_compress_struct cinfo;
        struct jpeg_error_mgr jerr;
@@ -210,12 +206,11 @@ gdImageJpegCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
        gdFree (row);
 }
 
-gdImagePtr
-gdImageCreateFromJpeg (FILE * inFile)
+gdImagePtr gdImageCreateFromJpeg (FILE * inFile)
 {
        gdImagePtr im;
-       gdIOCtx *in = gdNewFileCtx (inFile);
-       im = gdImageCreateFromJpegCtx (in);
+       gdIOCtx *in = gdNewFileCtx(inFile);
+       im = gdImageCreateFromJpegCtx(in);
        in->gd_free (in);
 
        return im;
@@ -227,8 +222,7 @@ void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile);
  * Create a gd-format image from the JPEG-format INFILE.  Returns the
  * image, or NULL upon error.
  */
-gdImagePtr
-gdImageCreateFromJpegCtx (gdIOCtx * infile)
+gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile)
 {
        struct jpeg_decompress_struct cinfo;
        struct jpeg_error_mgr jerr;
@@ -388,8 +382,7 @@ typedef my_source_mgr *my_src_ptr;
  * before any data is actually read.
  */
 
-void
-init_source (j_decompress_ptr cinfo)
+void init_source (j_decompress_ptr cinfo)
 {
        my_src_ptr src = (my_src_ptr) cinfo->src;
 
@@ -436,21 +429,21 @@ init_source (j_decompress_ptr cinfo)
 
 #define END_JPEG_SEQUENCE "\r\n[*]--:END JPEG:--[*]\r\n"
 
-safeboolean
-fill_input_buffer (j_decompress_ptr cinfo)
+safeboolean fill_input_buffer (j_decompress_ptr cinfo)
 {
        my_src_ptr src = (my_src_ptr) cinfo->src;
-       size_t nbytes = 0;
-  
-       /* size_t got; */
+       /* 2.0.12: signed size. Thanks to Geert Jansen */
+       ssize_t nbytes = 0;
+
+       /* ssize_t got; */
        /* char *s; */
-       memset (src->buffer, 0, INPUT_BUF_SIZE);
-  
+       memset(src->buffer, 0, INPUT_BUF_SIZE);
+
        while (nbytes < INPUT_BUF_SIZE) {
-               int got = gdGetBuf (src->buffer + nbytes,  INPUT_BUF_SIZE - nbytes, src->infile);
-      
-               if ((got == EOF) || (got == 0)) {
-                 /* EOF or error. If we got any data, don't worry about it. If we didn't, then this is unexpected. */ 
+               int got = gdGetBuf(src->buffer + nbytes, INPUT_BUF_SIZE - nbytes, src->infile);
+
+               if (got == EOF || got == 0) {
+                       /* EOF or error. If we got any data, don't worry about it. If we didn't, then this is unexpected. */ 
                        if (!nbytes) {
                                nbytes = -1;
                        }
@@ -490,8 +483,7 @@ fill_input_buffer (j_decompress_ptr cinfo)
  * buffer is the application writer's problem.
  */
 
-void
-skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
 {
        my_src_ptr src = (my_src_ptr) cinfo->src;
 
@@ -530,8 +522,7 @@ skip_input_data (j_decompress_ptr cinfo, long num_bytes)
  * for error exit.
  */
 
-void
-term_source (j_decompress_ptr cinfo)
+void term_source (j_decompress_ptr cinfo)
 {
 #if 0
        * never used */
@@ -546,8 +537,7 @@ term_source (j_decompress_ptr cinfo)
  * for closing it after finishing decompression.
  */
 
-void
-jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile)
+void jpeg_gdIOCtx_src (j_decompress_ptr cinfo, gdIOCtx * infile)
 {
        my_src_ptr src;
 
@@ -595,8 +585,7 @@ typedef my_destination_mgr *my_dest_ptr;
  * before any data is actually written.
  */
 
-void
-init_destination (j_compress_ptr cinfo)
+void init_destination (j_compress_ptr cinfo)
 {
        my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
 
@@ -631,8 +620,7 @@ init_destination (j_compress_ptr cinfo)
  * write it out when emptying the buffer externally.
  */
 
-safeboolean
-empty_output_buffer (j_compress_ptr cinfo)
+safeboolean empty_output_buffer (j_compress_ptr cinfo)
 {
        my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
 
@@ -656,8 +644,7 @@ empty_output_buffer (j_compress_ptr cinfo)
  * for error exit.
  */
 
-void
-term_destination (j_compress_ptr cinfo)
+void term_destination (j_compress_ptr cinfo)
 {
        my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
        size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
@@ -675,8 +662,7 @@ term_destination (j_compress_ptr cinfo)
  * for closing it after finishing compression.
  */
 
-void
-jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile)
+void jpeg_gdIOCtx_dest (j_compress_ptr cinfo, gdIOCtx * outfile)
 {
        my_dest_ptr dest;
 
index a5850c6511789b7af694cce4a34b8b9c5e37f49c..9e01872f0c99010005535eff874a7af1464552d1 100644 (file)
 
 #ifndef PNG_SETJMP_NOT_SUPPORTED
 typedef struct _jmpbuf_wrapper
-  {
-    jmp_buf jmpbuf;
-  }
-jmpbuf_wrapper;
+{
+       jmp_buf jmpbuf;
+} jmpbuf_wrapper;
 
 static jmpbuf_wrapper gdPngJmpbufStruct;
 
-static void
-gdPngErrorHandler (png_structp png_ptr, png_const_charp msg)
+static void gdPngErrorHandler (png_structp png_ptr, png_const_charp msg)
 {
-  jmpbuf_wrapper *jmpbuf_ptr;
-
-  /* This function, aside from the extra step of retrieving the "error
-   * pointer" (below) and the fact that it exists within the application
-   * rather than within libpng, is essentially identical to libpng's
-   * default error handler.  The second point is critical:  since both
-   * setjmp() and longjmp() are called from the same code, they are
-   * guaranteed to have compatible notions of how big a jmp_buf is,
-   * regardless of whether _BSD_SOURCE or anything else has (or has not)
-   * been defined. */
-
-  php_gd_error_ex(E_ERROR, "gd-png:  fatal libpng error: %s\n", msg);
-
-  jmpbuf_ptr = png_get_error_ptr (png_ptr);
-  if (jmpbuf_ptr == NULL)
-    {                          /* we are completely hosed now */
-      php_gd_error_ex(E_ERROR, "gd-png:  EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
-      exit (99);
-    }
+       jmpbuf_wrapper *jmpbuf_ptr;
+
+       /* This function, aside from the extra step of retrieving the "error
+        * pointer" (below) and the fact that it exists within the application
+        * rather than within libpng, is essentially identical to libpng's
+        * default error handler.  The second point is critical:  since both
+        * setjmp() and longjmp() are called from the same code, they are
+        * guaranteed to have compatible notions of how big a jmp_buf is,
+        * regardless of whether _BSD_SOURCE or anything else has (or has not)
+        * been defined.
+        */
+
+       php_gd_error_ex(E_ERROR, "gd-png:  fatal libpng error: %s\n", msg);
+
+       jmpbuf_ptr = png_get_error_ptr (png_ptr);
+       if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
+               php_gd_error_ex(E_ERROR, "gd-png:  EXTREMELY fatal error: jmpbuf unrecoverable; terminating.\n");
+       }
 
-  longjmp (jmpbuf_ptr->jmpbuf, 1);
+       longjmp (jmpbuf_ptr->jmpbuf, 1);
 }
 #endif
 
-static void
-gdPngReadData (png_structp png_ptr,
-              png_bytep data, png_size_t length)
+static void gdPngReadData (png_structp png_ptr, png_bytep data, png_size_t length)
 {
-  gdGetBuf (data, length, (gdIOCtx *)
-           png_get_io_ptr (png_ptr));
+       gdGetBuf(data, length, (gdIOCtx *) png_get_io_ptr(png_ptr));
 }
 
-static void
-gdPngWriteData (png_structp png_ptr,
-               png_bytep data, png_size_t length)
+static void gdPngWriteData (png_structp png_ptr, png_bytep data, png_size_t length)
 {
-  gdPutBuf (data, length, (gdIOCtx *)
-           png_get_io_ptr (png_ptr));
+       gdPutBuf (data, length, (gdIOCtx *) png_get_io_ptr(png_ptr));
 }
 
-static void
-gdPngFlushData (png_structp png_ptr)
+static void gdPngFlushData (png_structp png_ptr)
 {
 }
 
-gdImagePtr
-gdImageCreateFromPng (FILE * inFile)
+gdImagePtr gdImageCreateFromPng (FILE * inFile)
 {
-  gdImagePtr im;
-  gdIOCtx *in = gdNewFileCtx (inFile);
-  im = gdImageCreateFromPngCtx (in);
-  in->gd_free (in);
-  return im;
+       gdImagePtr im;
+       gdIOCtx *in = gdNewFileCtx(inFile);
+       im = gdImageCreateFromPngCtx(in);
+       in->gd_free(in);
+
+       return im;
 }
 
 
 /* This routine is based in part on the Chapter 13 demo code in "PNG: The
  *  Definitive Guide" (http://www.cdrom.com/pub/png/pngbook.html).
  */
-gdImagePtr
-gdImageCreateFromPngCtx (gdIOCtx * infile)
+gdImagePtr gdImageCreateFromPngCtx (gdIOCtx * infile)
 {
-  png_byte sig[8];
-  png_structp png_ptr;
-  png_infop info_ptr;
-  png_uint_32 width, height, rowbytes, w, h;
-  int bit_depth, color_type, interlace_type;
-  int num_palette, num_trans;
-  png_colorp palette;
-  png_color_16p trans_gray_rgb;
-  png_color_16p trans_color_rgb;
-  png_bytep trans;
-  png_bytep image_data = NULL;
-  png_bytepp row_pointers = NULL;
-  gdImagePtr im = NULL;
-  int i, j, *open = NULL;
-  volatile int transparent = -1;
-  volatile int palette_allocated = FALSE;
-
-  /* Make sure the signature can't match by dumb luck -- TBB */
-  /* GRR: isn't sizeof(infile) equal to the size of the pointer? */
-  memset (infile, 0, sizeof (infile));
-
-  /* first do a quick check that the file really is a PNG image; could
-   * have used slightly more general png_sig_cmp() function instead */
-  gdGetBuf (sig, 8, infile);
-  if (!png_check_sig (sig, 8))
-    return NULL;               /* bad signature */
+       png_byte sig[8];
+       png_structp png_ptr;
+       png_infop info_ptr;
+       png_uint_32 width, height, rowbytes, w, h;
+       int bit_depth, color_type, interlace_type;
+       int num_palette, num_trans;
+       png_colorp palette;
+       png_color_16p trans_gray_rgb;
+       png_color_16p trans_color_rgb;
+       png_bytep trans;
+       png_bytep image_data = NULL;
+       png_bytepp row_pointers = NULL;
+       gdImagePtr im = NULL;
+       int i, j, *open = NULL;
+       volatile int transparent = -1;
+       volatile int palette_allocated = FALSE;
+
+       /* Make sure the signature can't match by dumb luck -- TBB */
+       /* GRR: isn't sizeof(infile) equal to the size of the pointer? */
+       memset (infile, 0, sizeof(infile));
+
+         /* first do a quick check that the file really is a PNG image; could
+          * have used slightly more general png_sig_cmp() function instead 
+          */
+       gdGetBuf(sig, 8, infile);
+       if (!png_check_sig (sig, 8)) { /* bad signature */
+               return NULL;
+       }
 
 #ifndef PNG_SETJMP_NOT_SUPPORTED
-  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct,
-                                   gdPngErrorHandler, NULL);
+       png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct, gdPngErrorHandler, NULL);
 #else
-  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+       png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 #endif
-  if (png_ptr == NULL)
-    {
-      php_gd_error("gd-png error: cannot allocate libpng main struct\n");
-      return NULL;
-    }
+       if (png_ptr == NULL) {
+               php_gd_error("gd-png error: cannot allocate libpng main struct\n");
+               return NULL;
+       }
 
-  info_ptr = png_create_info_struct (png_ptr);
-  if (info_ptr == NULL)
-    {
-      php_gd_error("gd-png error: cannot allocate libpng info struct\n");
-      png_destroy_read_struct (&png_ptr, NULL, NULL);
-      return NULL;
-    }
+       info_ptr = png_create_info_struct(png_ptr);
+       if (info_ptr == NULL) {
+               php_gd_error("gd-png error: cannot allocate libpng info struct\n");
+               png_destroy_read_struct (&png_ptr, NULL, NULL);
 
-  /* we could create a second info struct here (end_info), but it's only
-   * useful if we want to keep pre- and post-IDAT chunk info separated
-   * (mainly for PNG-aware image editors and converters) */
+               return NULL;
+       }
 
-  /* setjmp() must be called in every non-callback function that calls a
-   * PNG-reading libpng function */
+       /* we could create a second info struct here (end_info), but it's only
+        * useful if we want to keep pre- and post-IDAT chunk info separated
+        * (mainly for PNG-aware image editors and converters) 
+        */
+
+       /* setjmp() must be called in every non-callback function that calls a
+        * PNG-reading libpng function
+        */
 #ifndef PNG_SETJMP_NOT_SUPPORTED
-  if (setjmp (gdPngJmpbufStruct.jmpbuf))
-    {
-      php_gd_error("gd-png error: setjmp returns error condition\n");
-      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-      return NULL;
-    }
-#endif
+       if (setjmp(gdPngJmpbufStruct.jmpbuf)) {
+               php_gd_error("gd-png error: setjmp returns error condition\n");
+               png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
 
-  png_set_sig_bytes (png_ptr, 8);      /* we already read the 8 signature bytes */
+               return NULL;
+       }
+#endif
 
-  png_set_read_fn (png_ptr, (void *) infile, gdPngReadData);
-  png_read_info (png_ptr, info_ptr);   /* read all PNG info up to image data */
+       png_set_sig_bytes(png_ptr, 8);  /* we already read the 8 signature bytes */
 
-  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
-               &interlace_type, NULL, NULL);
-  if ((color_type == PNG_COLOR_TYPE_RGB) ||
-      (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
-    {
-      im = gdImageCreateTrueColor ((int) width, (int) height);
-    }
-  else
-    {
-      im = gdImageCreate ((int) width, (int) height);
-    }
-  if (im == NULL)
-    {
-      php_gd_error("gd-png error: cannot allocate gdImage struct\n");
-      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-      gdFree (image_data);
-      gdFree (row_pointers);
-      return NULL;
-    }
+       png_set_read_fn(png_ptr, (void *) infile, gdPngReadData);
+       png_read_info(png_ptr, info_ptr);       /* read all PNG info up to image data */
 
-  if (bit_depth == 16)
-    png_set_strip_16 (png_ptr);
-  else if (bit_depth < 8)
-    png_set_packing (png_ptr); /* expand to 1 byte per pixel */
-  switch (color_type)
-    {
-    case PNG_COLOR_TYPE_PALETTE:
-      png_get_PLTE (png_ptr, info_ptr, &palette, &num_palette);
-#ifdef DEBUG
-      php_gd_error("gd-png color_type is palette, colors: %d\n",
-              num_palette);
-#endif /* DEBUG */
-      if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
-       {
-         /* gd 2.0: we support this rather thoroughly now. Grab the
-            first fully transparent entry, if any, as the value of 
-            the simple-transparency index, mostly for backwards
-            binary compatibility. The alpha channel is where it's
-            really at these days. */
-         int firstZero = 1;
-         png_get_tRNS (png_ptr, info_ptr, &trans, &num_trans, NULL);
-         for (i = 0; i < num_trans; ++i)
-           {
-             im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
-             if ((trans[i] == 0) && (firstZero))
-               {
-                 transparent = i;
-                 firstZero = 0;
-               }
-           }
-       }
-      break;
-
-    case PNG_COLOR_TYPE_GRAY:
-    case PNG_COLOR_TYPE_GRAY_ALPHA:
-      /* create a fake palette and check for single-shade transparency */
-      if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL)
-       {
-         php_gd_error("gd-png error: cannot allocate gray palette\n");
-         png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-         return NULL;
-       }
-      palette_allocated = TRUE;
-      if (bit_depth < 8)
-       {
-         num_palette = 1 << bit_depth;
-         for (i = 0; i < 256; ++i)
-           {
-             j = (255 * i) / (num_palette - 1);
-             palette[i].red = palette[i].green = palette[i].blue = j;
-           }
+       png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
+       if ((color_type == PNG_COLOR_TYPE_RGB) || (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
+               im = gdImageCreateTrueColor((int) width, (int) height);
+       } else {
+               im = gdImageCreate((int) width, (int) height);
        }
-      else
-       {
-         num_palette = 256;
-         for (i = 0; i < 256; ++i)
-           {
-             palette[i].red = palette[i].green = palette[i].blue = i;
-           }
+       if (im == NULL) {
+               php_gd_error("gd-png error: cannot allocate gdImage struct\n");
+               png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+               gdFree(image_data);
+               gdFree(row_pointers);
+
+               return NULL;
        }
-      if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
-       {
-         png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
-         if (bit_depth == 16)  /* png_set_strip_16() not yet in effect */
-           transparent = trans_gray_rgb->gray >> 8;
-         else
-           transparent = trans_gray_rgb->gray;
-         /* Note slight error in 16-bit case:  up to 256 16-bit shades
-          * may get mapped to a single 8-bit shade, and only one of them
-          * is supposed to be transparent.  IOW, both opaque pixels and
-          * transparent pixels will be mapped into the transparent entry.
-          * There is no particularly good way around this in the case
-          * that all 256 8-bit shades are used, but one could write some
-          * custom 16-bit code to handle the case where there are gdFree
-          * palette entries.  This error will be extremely rare in
-          * general, though.  (Quite possibly there is only one such
-          * image in existence.) */
+
+       if (bit_depth == 16) {
+               png_set_strip_16(png_ptr);
+       } else if (bit_depth < 8) {
+               png_set_packing (png_ptr); /* expand to 1 byte per pixel */
        }
-      break;
-
-    case PNG_COLOR_TYPE_RGB:
-    case PNG_COLOR_TYPE_RGB_ALPHA:
-      /* gd 2.0: we now support truecolor. See the comment above
-         for a rare situation in which the transparent pixel may not
-         work properly with 16-bit channels. */
-      if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
-       {
-         png_get_tRNS (png_ptr, info_ptr, NULL, NULL, &trans_color_rgb);
-         if (bit_depth == 16)  /* png_set_strip_16() not yet in effect */
-           transparent = gdTrueColor (trans_color_rgb->red >> 8,
-                                      trans_color_rgb->green >> 8,
-                                      trans_color_rgb->blue >> 8);
-         else
-           transparent = gdTrueColor (trans_color_rgb->red,
-                                      trans_color_rgb->green,
-                                      trans_color_rgb->blue);
+
+       switch (color_type) {
+               case PNG_COLOR_TYPE_PALETTE:
+                       png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+#ifdef DEBUG
+                       php_gd_error("gd-png color_type is palette, colors: %d\n", num_palette);
+#endif /* DEBUG */
+                       if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
+                               /* gd 2.0: we support this rather thoroughly now. Grab the
+                                * first fully transparent entry, if any, as the value of 
+                                * the simple-transparency index, mostly for backwards
+                                * binary compatibility. The alpha channel is where it's
+                                * really at these days.
+                                */
+                               int firstZero = 1;
+                               png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
+                               for (i = 0; i < num_trans; ++i) {
+                                       im->alpha[i] = gdAlphaMax - (trans[i] >> 1);
+                                       if ((trans[i] == 0) && (firstZero)) {
+                                               transparent = i;
+                                               firstZero = 0;
+                                       }
+                               }
+                       }
+                       break;
+               case PNG_COLOR_TYPE_GRAY:
+               case PNG_COLOR_TYPE_GRAY_ALPHA:
+                       /* create a fake palette and check for single-shade transparency */
+                       if ((palette = (png_colorp) gdMalloc (256 * sizeof (png_color))) == NULL) {
+                               php_gd_error("gd-png error: cannot allocate gray palette\n");
+                               png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+                               return NULL;
+                       }
+                       palette_allocated = TRUE;
+                       if (bit_depth < 8) {
+                               num_palette = 1 << bit_depth;
+                               for (i = 0; i < 256; ++i) {
+                                       j = (255 * i) / (num_palette - 1);
+                                       palette[i].red = palette[i].green = palette[i].blue = j;
+                               }
+                       } else {
+                               num_palette = 256;
+                               for (i = 0; i < 256; ++i) {
+                                       palette[i].red = palette[i].green = palette[i].blue = i;
+                               }
+                       }
+                       if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+                               png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_gray_rgb);
+                               if (bit_depth == 16) {  /* png_set_strip_16() not yet in effect */
+                                       transparent = trans_gray_rgb->gray >> 8;
+                               } else {
+                                       transparent = trans_gray_rgb->gray;
+                               }
+                               /* Note slight error in 16-bit case:  up to 256 16-bit shades
+                                * may get mapped to a single 8-bit shade, and only one of them
+                                * is supposed to be transparent.  IOW, both opaque pixels and
+                                * transparent pixels will be mapped into the transparent entry.
+                                * There is no particularly good way around this in the case
+                                * that all 256 8-bit shades are used, but one could write some
+                                * custom 16-bit code to handle the case where there are gdFree
+                                * palette entries.  This error will be extremely rare in
+                                * general, though.  (Quite possibly there is only one such
+                                * image in existence.) 
+                                */
+                       }
+                       break;
+
+                       case PNG_COLOR_TYPE_RGB:
+                       case PNG_COLOR_TYPE_RGB_ALPHA:
+                               /* gd 2.0: we now support truecolor. See the comment above
+                                * for a rare situation in which the transparent pixel may not
+                                * work properly with 16-bit channels. 
+                                */
+                               if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+                                       png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_color_rgb);
+                                       if (bit_depth == 16) { /* png_set_strip_16() not yet in effect */
+                                               transparent = gdTrueColor(trans_color_rgb->red >> 8, 
+                                                                       trans_color_rgb->green >> 8,
+                                                                       trans_color_rgb->blue >> 8);
+                                       } else {
+                                               transparent = gdTrueColor(trans_color_rgb->red, 
+                                                                       trans_color_rgb->green,
+                                                                       trans_color_rgb->blue);
+                                       }
+                               }
+                               break;
        }
-      break;
-    }
 
-  png_read_update_info (png_ptr, info_ptr);
+       png_read_update_info(png_ptr, info_ptr);
 
-  /* allocate space for the PNG image data */
-  rowbytes = png_get_rowbytes (png_ptr, info_ptr);
-  if ((image_data = (png_bytep) gdMalloc (rowbytes * height)) == NULL)
-    {
-      php_gd_error("gd-png error: cannot allocate image data\n");
-      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-      return NULL;
-    }
-  if ((row_pointers = (png_bytepp) gdMalloc (height * sizeof (png_bytep))) == NULL)
-    {
-      php_gd_error("gd-png error: cannot allocate row pointers\n");
-      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-      gdFree (image_data);
-      return NULL;
-    }
+       /* allocate space for the PNG image data */
+       rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+       image_data = (png_bytep) gdMalloc (rowbytes * height);
 
-  /* set the individual row_pointers to point at the correct offsets */
-  for (h = 0; h < height; ++h)
-    {
-      row_pointers[h] = image_data + h * rowbytes;
-    }
+       row_pointers = (png_bytepp) gdMalloc (height * sizeof (png_bytep));
 
-  png_read_image (png_ptr, row_pointers);      /* read whole image... */
-  png_read_end (png_ptr, NULL);        /* ...done! */
-
-  if (!im->trueColor)
-    {
-      im->colorsTotal = num_palette;
-      im->transparent = transparent;
-      /* load the palette and mark all entries "open" (unused) for now */
-      open = im->open;
-      for (i = 0; i < num_palette; ++i)
-       {
-         im->red[i] = palette[i].red;
-         im->green[i] = palette[i].green;
-         im->blue[i] = palette[i].blue;
-         open[i] = 1;
-       }
-      for (i = num_palette; i < gdMaxColors; ++i)
-       {
-         open[i] = 1;
-       }
-    }
-  im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
-
-  /* can't nuke structs until done with palette */
-  png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-  switch (color_type)
-    {
-    case PNG_COLOR_TYPE_RGB:
-      for (h = 0; h < height; h++)
-       {
-         int boffset = 0;
-         for (w = 0; w < width; w++)
-           {
-             register png_byte r = row_pointers[h][boffset++];
-             register png_byte g = row_pointers[h][boffset++];
-             register png_byte b = row_pointers[h][boffset++];
-             im->tpixels[h][w] = gdTrueColor (r, g, b);
-           }
+       /* set the individual row_pointers to point at the correct offsets */
+       for (h = 0; h < height; ++h) {
+               row_pointers[h] = image_data + h * rowbytes;
        }
-      break;
-    case PNG_COLOR_TYPE_RGB_ALPHA:
-      for (h = 0; h < height; h++)
-       {
-         int boffset = 0;
-         for (w = 0; w < width; w++)
-           {
-             register png_byte r = row_pointers[h][boffset++];
-             register png_byte g = row_pointers[h][boffset++];
-             register png_byte b = row_pointers[h][boffset++];
-             /* gd has only 7 bits of alpha channel resolution, and
-                127 is transparent, 0 opaque. A moment of convenience, 
-                a lifetime of compatibility. */
-             register png_byte a = gdAlphaMax -
-             (row_pointers[h][boffset++] >> 1);
-             im->tpixels[h][w] = gdTrueColorAlpha (r, g, b, a);
-           }
+
+       png_read_image(png_ptr, row_pointers);  /* read whole image... */
+       png_read_end(png_ptr, NULL);            /* ...done! */
+
+       if (!im->trueColor) {
+               im->colorsTotal = num_palette;
+               /* load the palette and mark all entries "open" (unused) for now */
+               open = im->open;
+               for (i = 0; i < num_palette; ++i) {
+                       im->red[i] = palette[i].red;
+                       im->green[i] = palette[i].green;
+                       im->blue[i] = palette[i].blue;
+                       open[i] = 1;
+               }
+               for (i = num_palette; i < gdMaxColors; ++i) {
+                       open[i] = 1;
+               }
        }
-      break;
-    default:
-      /* Palette image, or something coerced to be one */
-      for (h = 0; h < height; ++h)
-       {
-         for (w = 0; w < width; ++w)
-           {
-             register png_byte idx = row_pointers[h][w];
-             im->pixels[h][w] = idx;
-             open[idx] = 0;
-           }
+       /* 2.0.12: Slaven Rezic: palette images are not the only images
+        * with a simple transparent color setting.
+        */
+       im->transparent = transparent;
+       im->interlace = (interlace_type == PNG_INTERLACE_ADAM7);
+
+       /* can't nuke structs until done with palette */
+       png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+       switch (color_type) {
+               case PNG_COLOR_TYPE_RGB:
+                       for (h = 0; h < height; h++) {
+                               int boffset = 0;
+                               for (w = 0; w < width; w++) {
+                                       register png_byte r = row_pointers[h][boffset++];
+                                       register png_byte g = row_pointers[h][boffset++];
+                                       register png_byte b = row_pointers[h][boffset++];
+                                       im->tpixels[h][w] = gdTrueColor (r, g, b);
+                               }
+                       }
+                       break;
+
+               case PNG_COLOR_TYPE_RGB_ALPHA:
+                       for (h = 0; h < height; h++) {
+                               int boffset = 0;
+                               for (w = 0; w < width; w++) {
+                                       register png_byte r = row_pointers[h][boffset++];
+                                       register png_byte g = row_pointers[h][boffset++];
+                                       register png_byte b = row_pointers[h][boffset++];
+
+                                       /* gd has only 7 bits of alpha channel resolution, and
+                                        * 127 is transparent, 0 opaque. A moment of convenience, 
+                                        *  a lifetime of compatibility.
+                                        */
+
+                                       register png_byte a = gdAlphaMax - (row_pointers[h][boffset++] >> 1);
+                                       im->tpixels[h][w] = gdTrueColorAlpha(r, g, b, a);
+                               }
+                       }
+                       break;
+
+               default:
+                       /* Palette image, or something coerced to be one */
+                       for (h = 0; h < height; ++h) {
+                               for (w = 0; w < width; ++w) {
+                                       register png_byte idx = row_pointers[h][w];
+                                       im->pixels[h][w] = idx;
+                                       open[idx] = 0;
+                               }
+                       }
        }
-    }
 #ifdef DEBUG
-  if (!im->trueColor)
-    {
-      for (i = num_palette; i < gdMaxColors; ++i)
-       {
-         if (!open[i])
-           {
-             php_gd_error("gd-png warning: image data references out-of-range"
-                      " color index (%d)\n", i);
-           }
+       if (!im->trueColor) {
+               for (i = num_palette; i < gdMaxColors; ++i) {
+                       if (!open[i]) {
+                               php_gd_error("gd-png warning: image data references out-of-range color index (%d)\n", i);
+                       }
+               }
        }
-    }
 #endif
 
-  if (palette_allocated)
-    gdFree (palette);
-  gdFree (image_data);
-  gdFree (row_pointers);
+       if (palette_allocated) {
+               gdFree(palette);
+       }
+       gdFree(image_data);
+       gdFree(row_pointers);
+
+       return im;
+}
+
+void gdImagePngEx (gdImagePtr im, FILE * outFile, int level)
+{
+       gdIOCtx *out = gdNewFileCtx(outFile);
+       gdImagePngCtxEx(im, out, level);
+       out->gd_free(out);
+}
 
-  return im;
+void gdImagePng (gdImagePtr im, FILE * outFile)
+{
+       gdIOCtx *out = gdNewFileCtx(outFile);
+       gdImagePngCtxEx(im, out, -1);
+       out->gd_free(out);
 }
 
+void * gdImagePngPtr (gdImagePtr im, int *size)
+{
+       void *rv;
+       gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+       gdImagePngCtxEx(im, out, -1);
+       rv = gdDPExtractData(out, size);
+       out->gd_free(out);
+
+       return rv;
+}
 
-void
-gdImagePng (gdImagePtr im, FILE * outFile)
+void * gdImagePngPtrEx (gdImagePtr im, int *size, int level)
 {
-  gdIOCtx *out = gdNewFileCtx (outFile);
-  gdImagePngCtx (im, out);
-  out->gd_free (out);
+       void *rv;
+       gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
+       gdImagePngCtxEx(im, out, level);
+       rv = gdDPExtractData(out, size);
+       out->gd_free(out);
+       return rv;
 }
 
-void *
-gdImagePngPtr (gdImagePtr im, int *size)
+void gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile)
 {
-  void *rv;
-  gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
-  gdImagePngCtx (im, out);
-  rv = gdDPExtractData (out, size);
-  out->gd_free (out);
-  return rv;
+       return gdImagePngCtxEx(im, outfile, -1);
 }
 
 /* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
  *  and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
  *  (http://www.cdrom.com/pub/png/pngbook.html).
  */
-void
-gdImagePngCtx (gdImagePtr im, gdIOCtx * outfile)
+void gdImagePngCtxEx (gdImagePtr im, gdIOCtx * outfile, int level)
 {
-  int i, j, bit_depth = 0, interlace_type;
-  int width = im->sx;
-  int height = im->sy;
-  int colors = im->colorsTotal;
-  int *open = im->open;
-  int mapping[gdMaxColors];    /* mapping[gd_index] == png_index */
-  png_byte trans_values[256];
-  png_color_16 trans_rgb_value;
-  png_color palette[gdMaxColors];
-  png_structp png_ptr;
-  png_infop info_ptr;
-  volatile int transparent = im->transparent;
-  volatile int remap = FALSE;
-
+       int i, j, bit_depth = 0, interlace_type;
+       int width = im->sx;
+       int height = im->sy;
+       int colors = im->colorsTotal;
+       int *open = im->open;
+       int mapping[gdMaxColors];       /* mapping[gd_index] == png_index */
+       png_byte trans_values[256];
+       png_color_16 trans_rgb_value;
+       png_color palette[gdMaxColors];
+       png_structp png_ptr;
+       png_infop info_ptr;
+       volatile int transparent = im->transparent;
+       volatile int remap = FALSE;
 
 #ifndef PNG_SETJMP_NOT_SUPPORTED
-  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
-                              &gdPngJmpbufStruct, gdPngErrorHandler, NULL);
+       png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, &gdPngJmpbufStruct, gdPngErrorHandler, NULL);
 #else
-  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+       png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 #endif
-  if (png_ptr == NULL)
-    {
-      php_gd_error("gd-png error: cannot allocate libpng main struct\n");
-      return;
-    }
+       if (png_ptr == NULL) {
+               php_gd_error("gd-png error: cannot allocate libpng main struct\n");
+               return;
+       }
 
-  info_ptr = png_create_info_struct (png_ptr);
-  if (info_ptr == NULL)
-    {
-      php_gd_error("gd-png error: cannot allocate libpng info struct\n");
-      png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
-      return;
+       info_ptr = png_create_info_struct(png_ptr);
+       if (info_ptr == NULL) {
+               php_gd_error("gd-png error: cannot allocate libpng info struct\n");
+               png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
+
+               return;
     }
 
 #ifndef PNG_SETJMP_NOT_SUPPORTED
-  if (setjmp (gdPngJmpbufStruct.jmpbuf))
-    {
-      php_gd_error("gd-png error: setjmp returns error condition\n");
-      png_destroy_write_struct (&png_ptr, &info_ptr);
-      return;
-    }
+       if (setjmp (gdPngJmpbufStruct.jmpbuf)) {
+               php_gd_error("gd-png error: setjmp returns error condition\n");
+               png_destroy_write_struct (&png_ptr, &info_ptr);
+
+               return;
+       }
 #endif
 
-  png_set_write_fn (png_ptr, (void *) outfile, gdPngWriteData, gdPngFlushData);
+       png_set_write_fn(png_ptr, (void *) outfile, gdPngWriteData, gdPngFlushData);
 
-  /* This is best for palette images, and libpng defaults to it for
-     palette images anyway, so we don't need to do it explicitly.
-     What to ideally do for truecolor images depends, alas, on the image.
-     gd is intentionally imperfect and doesn't spend a lot of time
-     fussing with such things. */
-/*  png_set_filter(png_ptr, 0, PNG_FILTER_NONE);  */
+       /* This is best for palette images, and libpng defaults to it for
+        * palette images anyway, so we don't need to do it explicitly.
+        * What to ideally do for truecolor images depends, alas, on the image.
+        * gd is intentionally imperfect and doesn't spend a lot of time
+        * fussing with such things.
+        */
+       
+       /*  png_set_filter(png_ptr, 0, PNG_FILTER_NONE);  */
 
-  /* may want to force maximum compression, but time penalty is large */
-/*  png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);  */
+       /* 2.0.12: this is finally a parameter */
+       png_set_compression_level(png_ptr, level);
 
-  /* can set this to a smaller value without compromising compression if all
-   * image data is 16K or less; will save some decoder memory [min == 8] */
-/*  png_set_compression_window_bits(png_ptr, 15);  */
+       /* can set this to a smaller value without compromising compression if all
+        * image data is 16K or less; will save some decoder memory [min == 8] 
+        */
 
-  if (!im->trueColor)
-    {
-      if (transparent >= im->colorsTotal ||
-         (transparent >= 0 && open[transparent]))
-       transparent = -1;
-    }
-  if (!im->trueColor)
-    {
-      for (i = 0; i < gdMaxColors; ++i)
-       mapping[i] = -1;
-    }
-  if (!im->trueColor)
-    {
-      /* count actual number of colors used (colorsTotal == high-water mark) */
-      colors = 0;
-      for (i = 0; i < im->colorsTotal; ++i)
-       {
-         if (!open[i])
-           {
-             mapping[i] = colors;
-             ++colors;
-           }
-       }
-      if (colors < im->colorsTotal)
-       {
-         remap = TRUE;
-       }
-      if (colors <= 2)
-       bit_depth = 1;
-      else if (colors <= 4)
-       bit_depth = 2;
-      else if (colors <= 16)
-       bit_depth = 4;
-      else
-       bit_depth = 8;
-    }
-  interlace_type = im->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
-
-  if (im->trueColor)
-    {
-      if (im->saveAlphaFlag)
-       {
-         png_set_IHDR (png_ptr, info_ptr, width, height, 8,
-                       PNG_COLOR_TYPE_RGB_ALPHA, interlace_type,
-                    PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+       /*  png_set_compression_window_bits(png_ptr, 15);  */
+
+       if (!im->trueColor) {
+               if (transparent >= im->colorsTotal || (transparent >= 0 && open[transparent])) {
+                       transparent = -1;
+               }
+
+               for (i = 0; i < gdMaxColors; ++i) {
+                       mapping[i] = -1;
+               }
+
+               /* count actual number of colors used (colorsTotal == high-water mark) */
+               colors = 0;
+               for (i = 0; i < im->colorsTotal; ++i) {
+                       if (!open[i]) {
+                               mapping[i] = colors;
+                               ++colors;
+                       }
+               }
+               if (colors < im->colorsTotal) {
+                       remap = TRUE;
+               }
+               if (colors <= 2) {
+                       bit_depth = 1;
+               } else if (colors <= 4) {
+                       bit_depth = 2;
+               } else if (colors <= 16) { 
+                       bit_depth = 4;
+               } else {
+                       bit_depth = 8;
+               }
        }
-      else
-       {
-         png_set_IHDR (png_ptr, info_ptr, width, height, 8,
-                       PNG_COLOR_TYPE_RGB, interlace_type,
-                    PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+       
+       interlace_type = im->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
+
+       if (im->trueColor) {
+               if (im->saveAlphaFlag) {
+                       png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, interlace_type,
+                                       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+               } else {
+                       png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, interlace_type,
+                                       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+               }
+       } else {
+               png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_PALETTE, interlace_type,
+                       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
        }
-    }
-  else
-    {
-      png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth,
-                   PNG_COLOR_TYPE_PALETTE, interlace_type,
-                   PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-    }
-  if (im->trueColor && (!im->saveAlphaFlag) && (transparent >= 0))
-    {
-       /* 2.0.9: fixed by Thomas Winzig */
-      trans_rgb_value.red = gdTrueColorGetRed (im->transparent);
-      trans_rgb_value.green = gdTrueColorGetGreen (im->transparent);
-      trans_rgb_value.blue = gdTrueColorGetBlue (im->transparent);
-      png_set_tRNS (png_ptr, info_ptr, 0, 0, &trans_rgb_value);
-    }
-  if (!im->trueColor)
-    {
-      /* Oy veh. Remap the PNG palette to put the 
-         entries with interesting alpha channel
-         values first. This minimizes the size
-         of the tRNS chunk and thus the size
-         of the PNG file as a whole. */
-      int tc = 0;
-      int i;
-      int j;
-      int k;
-      for (i = 0; (i < im->colorsTotal); i++)
-       {
-         if ((!im->open[i]) &&
-             (im->alpha[i] != gdAlphaOpaque))
-           {
-             tc++;
-           }
+
+       if (im->trueColor && !im->saveAlphaFlag && (transparent >= 0)) {
+               /* 2.0.9: fixed by Thomas Winzig */
+               trans_rgb_value.red = gdTrueColorGetRed (im->transparent);
+               trans_rgb_value.green = gdTrueColorGetGreen (im->transparent);
+               trans_rgb_value.blue = gdTrueColorGetBlue (im->transparent);
+               png_set_tRNS(png_ptr, info_ptr, 0, 0, &trans_rgb_value);
        }
-      if (tc)
-       {
+
+       if (!im->trueColor) {
+               /* Oy veh. Remap the PNG palette to put the entries with interesting alpha channel
+                * values first. This minimizes the size of the tRNS chunk and thus the size
+                * of the PNG file as a whole. 
+                */
+               
+               int tc = 0;
+               int i;
+               int j;
+               int k;
+
+               for (i = 0; (i < im->colorsTotal); i++) {
+                       if ((!im->open[i]) && (im->alpha[i] != gdAlphaOpaque)) {
+                               tc++;
+                       }
+               }
+               if (tc) {
 #if 0
-         for (i = 0; (i < im->colorsTotal); i++)
-           {
-             trans_values[i] = 255 -
-               ((im->alpha[i] << 1) +
-                (im->alpha[i] >> 6));
-           }
-         png_set_tRNS (png_ptr, info_ptr, trans_values, 256, NULL);
+                       for (i = 0; (i < im->colorsTotal); i++) {
+                               trans_values[i] = 255 - ((im->alpha[i] << 1) + (im->alpha[i] >> 6));
+                       }
+                       png_set_tRNS (png_ptr, info_ptr, trans_values, 256, NULL);
 #endif
-         if (!remap)
-           {
-             remap = TRUE;
-           }
-         /* (Semi-)transparent indexes come up from the bottom
-            of the list of real colors; opaque
-            indexes come down from the top */
-         j = 0;
-         k = colors - 1;
-         for (i = 0; (i < im->colorsTotal); i++)
-           {
-             if (!im->open[i])
-               {
-                 if (im->alpha[i] != gdAlphaOpaque)
-                   {
-                      /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */ 
-                     trans_values[j] = 255 -
-                       ((im->alpha[i] << 1) +
-                        (im->alpha[i] >> 6));
-                     mapping[i] = j++;
-                   }
-                 else
-                   {
-                     mapping[i] = k--;
-                   }
+                       if (!remap) {
+                               remap = TRUE;
+                       }
+
+                       /* (Semi-)transparent indexes come up from the bottom of the list of real colors; opaque
+                        * indexes come down from the top
+                        */
+                       j = 0;
+                       k = colors - 1;
+
+                       for (i = 0; i < im->colorsTotal; i++) {
+                               if (!im->open[i]) {
+                                       if (im->alpha[i] != gdAlphaOpaque) {
+                                               /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */ 
+                                               trans_values[j] = 255 - ((im->alpha[i] << 1) + (im->alpha[i] >> 6));
+                                               mapping[i] = j++;
+                                       } else {
+                                               mapping[i] = k--;
+                                       }
+                               }
+                       }
+                       png_set_tRNS(png_ptr, info_ptr, trans_values, tc, NULL);
                }
-           }
-         png_set_tRNS (png_ptr, info_ptr, trans_values, tc, NULL);
        }
-    }
-
-  /* convert palette to libpng layout */
-  if (!im->trueColor)
-    {
-      if (remap)
-       for (i = 0; i < im->colorsTotal; ++i)
-         {
-           if (mapping[i] < 0)
-             continue;
-           palette[mapping[i]].red = im->red[i];
-           palette[mapping[i]].green = im->green[i];
-           palette[mapping[i]].blue = im->blue[i];
-         }
-      else
-       for (i = 0; i < colors; ++i)
-         {
-           palette[i].red = im->red[i];
-           palette[i].green = im->green[i];
-           palette[i].blue = im->blue[i];
-         }
-      png_set_PLTE (png_ptr, info_ptr, palette, colors);
-    }
 
-  /* write out the PNG header info (everything up to first IDAT) */
-  png_write_info (png_ptr, info_ptr);
-
-  /* make sure < 8-bit images are packed into pixels as tightly as possible */
-  png_set_packing (png_ptr);
-
-  /* This code allocates a set of row buffers and copies the gd image data
-   * into them only in the case that remapping is necessary; in gd 1.3 and
-   * later, the im->pixels array is laid out identically to libpng's row
-   * pointers and can be passed to png_write_image() function directly.
-   * The remapping case could be accomplished with less memory for non-
-   * interlaced images, but interlacing causes some serious complications. */
-  if (im->trueColor)
-    {
-      int channels = im->saveAlphaFlag ? 4 : 3;
-      /* Our little 7-bit alpha channel trick costs us a bit here. */
-      png_bytep *row_pointers;
-      row_pointers = gdMalloc (sizeof (png_bytep) * height);
-      for (j = 0; j < height; ++j)
-       {
-         int bo = 0;
-         row_pointers[j] = (png_bytep) gdMalloc (width * channels);
-         for (i = 0; i < width; ++i)
-           {
-             unsigned char a;
-             row_pointers[j][bo++] = gdTrueColorGetRed (im->tpixels[j][i]);
-             row_pointers[j][bo++] = gdTrueColorGetGreen (im->tpixels[j][i]);
-             row_pointers[j][bo++] = gdTrueColorGetBlue (im->tpixels[j][i]);
-             if (im->saveAlphaFlag)
-               {
-                 /* convert the 7-bit alpha channel to an 8-bit alpha channel.
-                    We do a little bit-flipping magic, repeating the MSB
-                    as the LSB, to ensure that 0 maps to 0 and
-                    127 maps to 255. We also have to invert to match
-                    PNG's convention in which 255 is opaque. */
-                 a = gdTrueColorGetAlpha (im->tpixels[j][i]);
-                  /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */ 
-                 row_pointers[j][bo++] = 255 - ((a << 1) + (a >> 6));
+       /* convert palette to libpng layout */
+       if (!im->trueColor) {
+               if (remap) {
+                       for (i = 0; i < im->colorsTotal; ++i) {
+                               if (mapping[i] < 0) {
+                                       continue;
+                               }
+
+                               palette[mapping[i]].red = im->red[i];
+                               palette[mapping[i]].green = im->green[i];
+                               palette[mapping[i]].blue = im->blue[i];
+                       }
+               } else {
+                       for (i = 0; i < colors; ++i) {
+                               palette[i].red = im->red[i];
+                               palette[i].green = im->green[i];
+                               palette[i].blue = im->blue[i];
+                       }
                }
-           }
+               png_set_PLTE(png_ptr, info_ptr, palette, colors);
        }
 
-      png_write_image (png_ptr, row_pointers);
-      png_write_end (png_ptr, info_ptr);
+       /* write out the PNG header info (everything up to first IDAT) */
+       png_write_info(png_ptr, info_ptr);
+
+       /* make sure < 8-bit images are packed into pixels as tightly as possible */
+       png_set_packing(png_ptr);
+
+       /* This code allocates a set of row buffers and copies the gd image data
+        * into them only in the case that remapping is necessary; in gd 1.3 and
+        * later, the im->pixels array is laid out identically to libpng's row
+        * pointers and can be passed to png_write_image() function directly.
+        * The remapping case could be accomplished with less memory for non-
+        * interlaced images, but interlacing causes some serious complications.
+        */
+
+       if (im->trueColor) {
+               int channels = im->saveAlphaFlag ? 4 : 3;
+               /* Our little 7-bit alpha channel trick costs us a bit here. */
+               png_bytep *row_pointers;
+               row_pointers = gdMalloc(sizeof (png_bytep) * height);
+               for (j = 0; j < height; ++j) {
+                       int bo = 0;
+                       row_pointers[j] = (png_bytep) gdMalloc(width * channels);
+                       for (i = 0; i < width; ++i) {
+                               unsigned char a;
+                               row_pointers[j][bo++] = gdTrueColorGetRed(im->tpixels[j][i]);
+                               row_pointers[j][bo++] = gdTrueColorGetGreen(im->tpixels[j][i]);
+                               row_pointers[j][bo++] = gdTrueColorGetBlue(im->tpixels[j][i]);
+                               if (im->saveAlphaFlag) {
+                                       /* convert the 7-bit alpha channel to an 8-bit alpha channel.
+                                        * We do a little bit-flipping magic, repeating the MSB
+                                        * as the LSB, to ensure that 0 maps to 0 and
+                                        * 127 maps to 255. We also have to invert to match
+                                        * PNG's convention in which 255 is opaque.
+                                        */
+                                       a = gdTrueColorGetAlpha(im->tpixels[j][i]);
+                                       /* Andrew Hull: >> 6, not >> 7! (gd 2.0.5) */ 
+                                       row_pointers[j][bo++] = 255 - ((a << 1) + (a >> 6));
+                               }
+                       }
+               }
 
-      for (j = 0; j < height; ++j)
-       gdFree (row_pointers[j]);
-      gdFree (row_pointers);
-    }
-  else
-    {
-      if (remap)
-       {
-         png_bytep *row_pointers;
-         row_pointers = gdMalloc (sizeof (png_bytep) * height);
-         for (j = 0; j < height; ++j)
-           {
-             row_pointers[j] = (png_bytep) gdMalloc (width);
-             for (i = 0; i < width; ++i) 
-               row_pointers[j][i] = mapping[im->pixels[j][i]];
-           }
-
-         png_write_image (png_ptr, row_pointers);
-         png_write_end (png_ptr, info_ptr);
-
-         for (j = 0; j < height; ++j)
-           gdFree (row_pointers[j]);
-         gdFree (row_pointers);
-       }
-      else
-       {
-         png_write_image (png_ptr, im->pixels);
-         png_write_end (png_ptr, info_ptr);
+               png_write_image(png_ptr, row_pointers);
+               png_write_end(png_ptr, info_ptr);
+
+               for (j = 0; j < height; ++j) {
+                       gdFree(row_pointers[j]);
+               }
+       
+               gdFree(row_pointers);
+       } else {
+               if (remap) {
+                       png_bytep *row_pointers;
+                       row_pointers = gdMalloc(sizeof (png_bytep) * height);
+                       for (j = 0; j < height; ++j) {
+                               row_pointers[j] = (png_bytep) gdMalloc(width);
+                               for (i = 0; i < width; ++i) {
+                                       row_pointers[j][i] = mapping[im->pixels[j][i]];
+                               }
+                       }
+
+                       png_write_image(png_ptr, row_pointers);
+                       png_write_end(png_ptr, info_ptr);
+
+                       for (j = 0; j < height; ++j) {
+                               gdFree(row_pointers[j]);
+                       }
+
+                       gdFree(row_pointers);
+               } else {
+                       png_write_image(png_ptr, im->pixels);
+                       png_write_end(png_ptr, info_ptr);
+               }
        }
-    }
-  /* 1.6.3: maybe we should give that memory BACK! TBB */
-  png_destroy_write_struct (&png_ptr, &info_ptr);
+       /* 1.6.3: maybe we should give that memory BACK! TBB */
+       png_destroy_write_struct(&png_ptr, &info_ptr);
 }
 
-
 #endif /* HAVE_LIBPNG */
index b3cf0d5b87c618b47b8f120d469799c0d45b7aae..77fb4139b27760f3da89cb1de2c6fe880f7c64d9 100644 (file)
@@ -1,29 +1,50 @@
-
+/* 2.0.12: a new adaptation from the same original, this time
+ * by Barend Gahrels. My attempt to incorporate alpha channel
+ * into the result worked poorly and degraded the quality of
+ * palette conversion even when the source contained no
+ * alpha channel data. This version does not attempt to produce
+ * an output file with transparency in some of the palette
+ * indexes, which, in practice, doesn't look so hot anyway. TBB
+ */
 
 /*
- * gd_topal.c 
- * 
- * This code is adapted pretty much entirely from jquant2.c,
- * Copyright (C) 1991-1996, Thomas G. Lane. That file is
- * part of the Independent JPEG Group's software. Conditions of
- * use are compatible with the gd license. See the gd license 
- * statement and README-JPEG.TXT for additional information.
+ * gd_topal, adapted from jquant2.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains 2-pass color quantization (color mapping) routines.
  * These routines provide selection of a custom color map for an image,
  * followed by mapping of the image to that color map, with optional
  * Floyd-Steinberg dithering.
- *
  * It is also possible to use just the second pass to map to an arbitrary
  * externally-given color map.
  *
  * Note: ordered dithering is not supported, since there isn't any fast
  * way to compute intercolor distances; it's unclear that ordered dither's
  * fundamental assumptions even hold with an irregularly spaced color map.
- *
- * SUPPORT FOR ALPHA CHANNELS WAS HACKED IN BY THOMAS BOUTELL, who also
- * adapted the code to work within gd rather than within libjpeg, and
- * may not have done a great job of either. It's not Thomas G. Lane's fault.
+ */
+
+#ifdef ORIGINAL_LIB_JPEG
+
+#define JPEG_INTERNALS
+
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#else
+
+/*
+ * THOMAS BOUTELL & BAREND GEHRELS, february 2003
+ * adapted the code to work within gd rather than within libjpeg.
+ * If it is not working, it's not Thomas G. Lane's fault.
+ */
+
+/* 
+ * SETTING THIS ONE CAUSES STRIPED IMAGE
+ *  to be done: solve this
+ * #define ORIGINAL_LIB_JPEG_REVERSE_ODD_ROWS
  */
 
 #include "gd.h"
 #include <string.h>
 #include <stdlib.h>
 
+/* (Re)define some defines known by libjpeg */
+#define QUANT_2PASS_SUPPORTED
+
+#define RGB_RED                0
+#define RGB_GREEN      1
+#define RGB_BLUE       2
+
+#define JSAMPLE unsigned char
+#define MAXJSAMPLE (gdMaxColors-1)
+#define BITS_IN_JSAMPLE 8
+
+#define JSAMPROW int*
+#define JDIMENSION int
+
+#define METHODDEF(type) static type
+#define LOCAL(type)    static type
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity.  This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit.  But some
+ * C compilers implement >> with an unsigned shift.  For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
+ * It is only applied with constant shift counts.  SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS    INT32 shift_temp;
+#define RIGHT_SHIFT(x,shft)  \
+       ((shift_temp = (x)) < 0 ? \
+        (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
+        (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x,shft)    ((x) >> (shft))
+#endif
+
+
+#define range_limit(x) { if(x<0) x=0; if (x>255) x=255; }
+
+
+#ifndef INT16
+#define INT16  short
+#endif
+
+#ifndef UINT16
+#define UINT16 unsigned short
+#endif
+
+#ifndef INT32
+#define INT32 int
+#endif
+
+#ifndef FAR
+#define FAR
+#endif
+
+#ifndef boolean
+#define boolean int
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define input_buf (im->tpixels)
+#define output_buf (im->pixels)
+
+#endif
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+
 /*
  * This module implements the well-known Heckbert paradigm for color
  * quantization.  Most of the ideas used here can be traced back to
  * The present code works in the post-conversion color space, typically RGB.
  *
  * To improve the visual quality of the results, we actually work in scaled
- * RGBA space, giving G distances more weight than R, and R in turn more than
- * B.  Alpha is weighted least. To do everything in integer math, we must 
- * use integer scale factors. The 2/3/1 scale factors used here correspond 
- * loosely to the relative weights of the colors in the NTSC grayscale 
- * equation. 
+ * RGB space, giving G distances more weight than R, and R in turn more than
+ * B.  To do everything in integer math, we must use integer scale factors.
+ * The 2/3/1 scale factors used here correspond loosely to the relative
+ * weights of the colors in the NTSC grayscale equation.
+ * If you want to use this code to quantize a non-RGB color space, you'll
+ * probably need to change these scale factors.
  */
 
-#ifndef TRUE
-#define TRUE 1
-#endif /* TRUE */
-
-#ifndef FALSE
-#define FALSE 0
-#endif /* FALSE */
-
 #define R_SCALE 2              /* scale R distances by this much */
 #define G_SCALE 3              /* scale G distances by this much */
 #define B_SCALE 1              /* and B by this much */
-#define A_SCALE 4              /* and alpha by this much. This really
-                                  only scales by 1 because alpha
-                                  values are 7-bit to begin with. */
 
-/* Channel ordering (fixed in gd) */
+/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined
+ * in jmorecfg.h.  As the code stands, it will do the right thing for R,G,B
+ * and B,G,R orders.  If you define some other weird order in jmorecfg.h,
+ * you'll get compile errors until you extend this logic.  In that case
+ * you'll probably want to tweak the histogram sizes too.
+ */
+
+#if RGB_RED == 0
 #define C0_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 0
+#define C0_SCALE B_SCALE
+#endif
+#if RGB_GREEN == 1
 #define C1_SCALE G_SCALE
+#endif
+#if RGB_RED == 2
+#define C2_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 2
 #define C2_SCALE B_SCALE
-#define C3_SCALE A_SCALE
+#endif
+
 
 /*
  * First we have the histogram data structure and routines for creating it.
  * arrays are in far memory (same arrangement as we use for image arrays).
  */
 
-#define MAXNUMCOLORS  (gdMaxColors)    /* maximum size of colormap */
+#define MAXNUMCOLORS  (MAXJSAMPLE+1)   /* maximum size of colormap */
 
-#define HIST_C0_BITS  5                /* bits of precision in R histogram */
+/* These will do the right thing for either R,G,B or B,G,R color order,
+ * but you may not like the results for other color orders.
+ */
+#define HIST_C0_BITS  5                /* bits of precision in R/B histogram */
 #define HIST_C1_BITS  6                /* bits of precision in G histogram */
-#define HIST_C2_BITS  5                /* bits of precision in B histogram */
-#define HIST_C3_BITS  3                /* bits of precision in A histogram */
+#define HIST_C2_BITS  5                /* bits of precision in B/R histogram */
 
 /* Number of elements along histogram axes. */
 #define HIST_C0_ELEMS  (1<<HIST_C0_BITS)
 #define HIST_C1_ELEMS  (1<<HIST_C1_BITS)
 #define HIST_C2_ELEMS  (1<<HIST_C2_BITS)
-#define HIST_C3_ELEMS  (1<<HIST_C3_BITS)
 
 /* These are the amounts to shift an input value to get a histogram index. */
-#define C0_SHIFT  (8-HIST_C0_BITS)
-#define C1_SHIFT  (8-HIST_C1_BITS)
-#define C2_SHIFT  (8-HIST_C2_BITS)
-/* Beware! Alpha is 7 bit to begin with */
-#define C3_SHIFT  (7-HIST_C3_BITS)
+#define C0_SHIFT  (BITS_IN_JSAMPLE-HIST_C0_BITS)
+#define C1_SHIFT  (BITS_IN_JSAMPLE-HIST_C1_BITS)
+#define C2_SHIFT  (BITS_IN_JSAMPLE-HIST_C2_BITS)
 
 
-typedef unsigned short histcell;       /* histogram cell; prefer an unsigned type */
+typedef UINT16 histcell;       /* histogram cell; prefer an unsigned type */
 
-typedef histcell *histptr;     /* for pointers to histogram cells */
+typedef histcell FAR *histptr; /* for pointers to histogram cells */
 
-typedef histcell hist1d[HIST_C3_ELEMS];                /* typedefs for the array */
-typedef hist1d *hist2d;                /* type for the 2nd-level pointers */
-typedef hist2d *hist3d;                /* type for third-level pointer */
-typedef hist3d *hist4d;                /* type for top-level pointer */
+typedef histcell hist1d[HIST_C2_ELEMS];        /* typedefs for the array */
+typedef hist1d FAR *hist2d;    /* type for the 2nd-level pointers */
+typedef hist2d *hist3d;                /* type for top-level pointer */
 
 
 /* Declarations for Floyd-Steinberg dithering.
-
+ *
  * Errors are accumulated into the array fserrors[], at a resolution of
  * 1/16th of a pixel count.  The error at a given pixel is propagated
  * to its not-yet-processed neighbors using the standard F-S fractions,
- *              ...     (here)  7/16
- *              3/16    5/16    1/16
+ *             ...     (here)  7/16
+ *             3/16    5/16    1/16
  * We work left-to-right on even rows, right-to-left on odd rows.
  *
  * We can get away with a single array (holding one row's worth of errors)
@@ -174,91 +280,112 @@ typedef hist3d *hist4d;          /* type for top-level pointer */
  * each end saves us from special-casing the first and last pixels.
  * Each entry is three values long, one value for each color component.
  *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
  */
 
-typedef signed short FSERROR;  /* 16 bits should be enough */
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR;         /* 16 bits should be enough */
 typedef int LOCFSERROR;                /* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR;         /* may need more than 16 bits */
+typedef INT32 LOCFSERROR;      /* be sure calculation temps are big enough */
+#endif
 
-typedef FSERROR *FSERRPTR;     /* pointer to error array */
+typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
 
-/* Private object */
+/* Private subobject */
 
 typedef struct
-  {
-    hist4d histogram;          /* pointer to the histogram */
-    int needs_zeroed;          /* TRUE if next pass must zero histogram */
-
-    /* Variables for Floyd-Steinberg dithering */
-    FSERRPTR fserrors;         /* accumulated errors */
-    int on_odd_row;            /* flag to remember which row we are on */
-    int *error_limiter;                /* table for clamping the applied error */
-    int *error_limiter_storage;        /* gdMalloc'd storage for the above */
-    int transparentIsPresent;  /* TBB: for rescaling to ensure that */
-    int opaqueIsPresent;       /* 100% opacity & transparency are preserved */
-  }
-my_cquantizer;
+{
+#ifdef ORIGINAL_LIB_JPEG
+       struct jpeg_color_quantizer pub;        /* public fields */
+
+       /* Space for the eventually created colormap is stashed here */
+       JSAMPARRAY sv_colormap; /* colormap allocated at init time */
+       int desired;            /* desired # of colors = size of colormap */
+       boolean needs_zeroed;   /* TRUE if next pass must zero histogram */
+#endif
+
+         /* Variables for accumulating image statistics */
+       hist3d histogram;       /* pointer to the histogram */
+
+
+       /* Variables for Floyd-Steinberg dithering */
+       FSERRPTR fserrors;      /* accumulated errors */
+
+       boolean on_odd_row;     /* flag to remember which row we are on */
+       int *error_limiter;     /* table for clamping the applied error */
+#ifndef ORIGINAL_LIB_JPEG
+       int *error_limiter_storage;     /* gdMalloc'd storage for the above */
+#endif
+} my_cquantizer;
 
 typedef my_cquantizer *my_cquantize_ptr;
 
+
 /*
- * Prescan the pixel array. 
- * 
- * The prescan simply updates the histogram, which has been
+ * Prescan some rows of pixels.
+ * In this module the prescan simply updates the histogram, which has been
  * initialized to zeroes by start_pass.
- *
+ * An output_buf parameter is required by the method signature, but no data
+ * is actually output (in fact the buffer controller is probably passing a
+ * NULL pointer).
  */
 
-static void
+METHODDEF (void)
+#ifndef ORIGINAL_LIB_JPEG
 prescan_quantize (gdImagePtr im, my_cquantize_ptr cquantize)
 {
-  register histptr histp;
-  register hist4d histogram = cquantize->histogram;
-  int row;
-  int col;
-  int *ptr;
-  int width = im->sx;
-
-  for (row = 0; row < im->sy; row++)
-    {
-      ptr = im->tpixels[row];
-      for (col = width; col > 0; col--)
-       {
-         /* get pixel value and index into the histogram */
-         int r, g, b, a;
-         r = gdTrueColorGetRed (*ptr) >> C0_SHIFT;
-         g = gdTrueColorGetGreen (*ptr) >> C1_SHIFT;
-         b = gdTrueColorGetBlue (*ptr) >> C2_SHIFT;
-         a = gdTrueColorGetAlpha (*ptr);
-         /* We must have 100% opacity and transparency available
-            in the color map to do an acceptable job with alpha 
-            channel, if opacity and transparency are present in the
-            original, because of the visual properties of large
-            flat-color border areas (requiring 100% transparency) 
-            and the behavior of poorly implemented browsers 
-            (requiring 100% opacity). Test for the presence of
-            these here, and rescale the most opaque and transparent
-            palette entries at the end if so. This avoids the need
-            to develop a fuller understanding I have not been able
-            to reach so far in my study of this subject. TBB */
-         if (a == gdAlphaTransparent)
-           {
-             cquantize->transparentIsPresent = 1;
-           }
-         if (a == gdAlphaOpaque)
-           {
-             cquantize->opaqueIsPresent = 1;
-           }
-         a >>= C3_SHIFT;
-         histp = &histogram[r][g][b][a];
-         /* increment, check for overflow and undo increment if so. */
-         if (++(*histp) <= 0)
-           (*histp)--;
-         ptr++;
+#else
+prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+{
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+#endif
+       register JSAMPROW ptr;
+       register histptr histp;
+       register hist3d histogram = cquantize->histogram;
+       int row;
+       JDIMENSION col;
+#ifdef ORIGINAL_LIB_JPEG
+       JDIMENSION width = cinfo->output_width;
+#else
+       int width = im->sx;
+       int num_rows = im->sy;
+#endif
+
+       for (row = 0; row < num_rows; row++) {
+               ptr = input_buf[row];
+               for (col = width; col > 0; col--) {
+#ifdef ORIGINAL_LIB_JPEG
+                       int r = GETJSAMPLE(ptr[0]) >> C0_SHIFT;
+                       int g = GETJSAMPLE(ptr[1]) >> C1_SHIFT;
+                       int b = GETJSAMPLE(ptr[2]) >> C2_SHIFT;
+#else
+                       int r = gdTrueColorGetRed(*ptr) >> C0_SHIFT;
+                       int g = gdTrueColorGetGreen(*ptr) >> C1_SHIFT;
+                       int b = gdTrueColorGetBlue(*ptr) >> C2_SHIFT;
+                       /* 2.0.12: Steven Brown: support a single totally transparent color in the original. */
+                       if ((im->transparent >= 0) && (*ptr == im->transparent)) {
+                               ptr++;
+                               continue;
+                       }
+#endif
+                       /* get pixel value and index into the histogram */
+                       histp = &histogram[r][g][b];
+                       /* increment, check for overflow and undo increment if so. */
+                       if (++(*histp) == 0) {
+                               (*histp)--;
+                       }
+#ifdef ORIGINAL_LIB_JPEG
+                       ptr += 3;
+#else
+                       ptr++;
+#endif
+               }
        }
-    }
 }
 
-
 /*
  * Next we have the really interesting routines: selection of a colormap
  * given the completed histogram.
@@ -268,436 +395,417 @@ prescan_quantize (gdImagePtr im, my_cquantize_ptr cquantize)
 
 typedef struct
 {
-  /* The bounds of the box (inclusive); expressed as histogram indexes */
-  int c0min, c0max;
-  int c1min, c1max;
-  int c2min, c2max;
-  int c3min, c3max;
-  /* The volume (actually 2-norm) of the box */
-  int volume;
-  /* The number of nonzero histogram cells within this box */
-  long colorcount;
-}
-box;
+       /* The bounds of the box (inclusive); expressed as histogram indexes */
+       int c0min, c0max;
+       int c1min, c1max;
+       int c2min, c2max;
+       /* The volume (actually 2-norm) of the box */
+       INT32 volume;
+       /* The number of nonzero histogram cells within this box */
+       long colorcount;
+} box;
 
 typedef box *boxptr;
 
-static boxptr
-find_biggest_color_pop (boxptr boxlist, int numboxes)
+LOCAL (boxptr) find_biggest_color_pop (boxptr boxlist, int numboxes)
 /* Find the splittable box with the largest color population */
 /* Returns NULL if no splittable boxes remain */
 {
-  register boxptr boxp;
-  register int i;
-  register long maxc = 0;
-  boxptr which = NULL;
-
-  for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++)
-    {
-      if (boxp->colorcount > maxc && boxp->volume > 0)
-       {
-         which = boxp;
-         maxc = boxp->colorcount;
+       register boxptr boxp;
+       register int i;
+       register long maxc = 0;
+       boxptr which = NULL;
+
+       for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+               if (boxp->colorcount > maxc && boxp->volume > 0) {
+                       which = boxp;
+                       maxc = boxp->colorcount;
+               }
        }
-    }
-  return which;
+
+       return which;
 }
 
 
-static boxptr
-find_biggest_volume (boxptr boxlist, int numboxes)
+LOCAL (boxptr) find_biggest_volume (boxptr boxlist, int numboxes)
 /* Find the splittable box with the largest (scaled) volume */
 /* Returns NULL if no splittable boxes remain */
 {
-  register boxptr boxp;
-  register int i;
-  register int maxv = 0;
-  boxptr which = NULL;
-
-  for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++)
-    {
-      if (boxp->volume > maxv)
-       {
-         which = boxp;
-         maxv = boxp->volume;
+       register boxptr boxp;
+       register int i;
+       register INT32 maxv = 0;
+       boxptr which = NULL;
+
+       for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+               if (boxp->volume > maxv) {
+                       which = boxp;
+                       maxv = boxp->volume;
+               }
        }
-    }
-  return which;
+
+       return which;
 }
 
 
-static void
-update_box (gdImagePtr im, my_cquantize_ptr cquantize, boxptr boxp)
+LOCAL (void)
+#ifndef ORIGINAL_LIB_JPEG
+  update_box (gdImagePtr im, my_cquantize_ptr cquantize, boxptr boxp)
+{
+#else
+  update_box (j_decompress_ptr cinfo, boxptr boxp)
 /* Shrink the min/max bounds of a box to enclose only nonzero elements, */
 /* and recompute its volume and population */
 {
-  hist4d histogram = cquantize->histogram;
-  histptr histp;
-  int c0, c1, c2, c3;
-  int c0min, c0max, c1min, c1max, c2min, c2max, c3min, c3max;
-  int dist0, dist1, dist2, dist3;
-  long ccount;
-
-  c0min = boxp->c0min;
-  c0max = boxp->c0max;
-  c1min = boxp->c1min;
-  c1max = boxp->c1max;
-  c2min = boxp->c2min;
-  c2max = boxp->c2max;
-  c3min = boxp->c3min;
-  c3max = boxp->c3max;
-
-  if (c0max > c0min)
-    {
-      for (c0 = c0min; c0 <= c0max; c0++)
-       {
-         for (c1 = c1min; c1 <= c1max; c1++)
-           {
-             for (c2 = c2min; c2 <= c2max; c2++)
-               {
-                 histp = &histogram[c0][c1][c2][c3min];
-                 for (c3 = c3min; c3 <= c3max; c3++)
-                   {
-                     if (*histp++ != 0)
-                       {
-                         boxp->c0min = c0min = c0;
-                         goto have_c0min;
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+#endif
+       hist3d histogram = cquantize->histogram;
+       histptr histp;
+       int c0, c1, c2;
+       int c0min, c0max, c1min, c1max, c2min, c2max;
+       INT32 dist0, dist1, dist2;
+       long ccount;
+
+       c0min = boxp->c0min;
+       c0max = boxp->c0max;
+       c1min = boxp->c1min;
+       c1max = boxp->c1max;
+       c2min = boxp->c2min;
+       c2max = boxp->c2max;
+
+       if (c0max > c0min) {
+               for (c0 = c0min; c0 <= c0max; c0++) {
+                       for (c1 = c1min; c1 <= c1max; c1++) {
+                               histp = &histogram[c0][c1][c2min];
+                               for (c2 = c2min; c2 <= c2max; c2++) {
+                                       if (*histp++ != 0) {
+                                               boxp->c0min = c0min = c0;
+                                               goto have_c0min;
+                                       }
+                               }
                        }
-                   }
                }
-           }
        }
-    }
 have_c0min:
-  if (c0max > c0min)
-    {
-      for (c0 = c0max; c0 >= c0min; c0--)
-       {
-         for (c1 = c1min; c1 <= c1max; c1++)
-           {
-             for (c2 = c2min; c2 <= c2max; c2++)
-               {
-                 histp = &histogram[c0][c1][c2][c3min];
-                 for (c3 = c3min; c3 <= c3max; c3++)
-                   {
-                     if (*histp++ != 0)
-                       {
-                         boxp->c0max = c0max = c0;
-                         goto have_c0max;
+       if (c0max > c0min) {
+               for (c0 = c0max; c0 >= c0min; c0--) {
+                       for (c1 = c1min; c1 <= c1max; c1++) {
+                               histp = &histogram[c0][c1][c2min];
+                               for (c2 = c2min; c2 <= c2max; c2++) {
+                                       if (*histp++ != 0) {
+                                               boxp->c0max = c0max = c0;
+                                               goto have_c0max;
+                                       }
+                               }
                        }
-                   }
                }
-           }
        }
-    }
 have_c0max:
-  if (c1max > c1min)
-    for (c1 = c1min; c1 <= c1max; c1++)
-      for (c0 = c0min; c0 <= c0max; c0++)
-       {
-         for (c2 = c2min; c2 <= c2max; c2++)
-           {
-             histp = &histogram[c0][c1][c2][c3min];
-             for (c3 = c3min; c3 <= c3max; c3++)
-               if (*histp++ != 0)
-                 {
-                   boxp->c1min = c1min = c1;
-                   goto have_c1min;
-                 }
-           }
+       if (c1max > c1min) {
+               for (c1 = c1min; c1 <= c1max; c1++) {
+                       for (c0 = c0min; c0 <= c0max; c0++) {
+                               histp = &histogram[c0][c1][c2min];
+                               for (c2 = c2min; c2 <= c2max; c2++) {
+                                       if (*histp++ != 0) {
+                                               boxp->c1min = c1min = c1;
+                                               goto have_c1min;
+                                       }
+                               }
+                       }
+               }
        }
 have_c1min:
-  if (c1max > c1min)
-    for (c1 = c1max; c1 >= c1min; c1--)
-      for (c0 = c0min; c0 <= c0max; c0++)
-       {
-         for (c2 = c2min; c2 <= c2max; c2++)
-           {
-             histp = &histogram[c0][c1][c2][c3min];
-             for (c3 = c3min; c3 <= c3max; c3++)
-               if (*histp++ != 0)
-                 {
-                   boxp->c1max = c1max = c1;
-                   goto have_c1max;
-                 }
-           }
+       if (c1max > c1min) {
+               for (c1 = c1max; c1 >= c1min; c1--) {
+                       for (c0 = c0min; c0 <= c0max; c0++) {
+                               histp = &histogram[c0][c1][c2min];
+                               for (c2 = c2min; c2 <= c2max; c2++) {
+                                       if (*histp++ != 0) {
+                                               boxp->c1max = c1max = c1;
+                                               goto have_c1max;
+                                       }
+                               }
+                       }
+               }
        }
 have_c1max:
-  /* The original version hand-rolled the array lookup a little, but
-     with four dimensions, I don't even want to think about it. TBB */
-  if (c2max > c2min)
-    for (c2 = c2min; c2 <= c2max; c2++)
-      for (c0 = c0min; c0 <= c0max; c0++)
-       for (c1 = c1min; c1 <= c1max; c1++)
-         for (c3 = c3min; c3 <= c3max; c3++)
-           if (histogram[c0][c1][c2][c3] != 0)
-             {
-               boxp->c2min = c2min = c2;
-               goto have_c2min;
-             }
+       if (c2max > c2min) {
+               for (c2 = c2min; c2 <= c2max; c2++) {
+                       for (c0 = c0min; c0 <= c0max; c0++) {
+                               histp = &histogram[c0][c1min][c2];
+                               for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) {
+                                       if (*histp != 0) {
+                                               boxp->c2min = c2min = c2;
+                                               goto have_c2min;
+                                       }
+                               }
+                       }
+               }
+       }
 have_c2min:
-  if (c2max > c2min)
-    for (c2 = c2max; c2 >= c2min; c2--)
-      for (c0 = c0min; c0 <= c0max; c0++)
-       for (c1 = c1min; c1 <= c1max; c1++)
-         for (c3 = c3min; c3 <= c3max; c3++)
-           if (histogram[c0][c1][c2][c3] != 0)
-             {
-               boxp->c2max = c2max = c2;
-               goto have_c2max;
-             }
+       if (c2max > c2min) {
+               for (c2 = c2max; c2 >= c2min; c2--) {
+                       for (c0 = c0min; c0 <= c0max; c0++) {
+                               histp = &histogram[c0][c1min][c2];
+                               for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) { 
+                                       if (*histp != 0) {
+                                               boxp->c2max = c2max = c2;
+                                               goto have_c2max;
+                                       }
+                               }
+                       }
+               }
+       }
 have_c2max:
-  if (c3max > c3min)
-    for (c3 = c3min; c3 <= c3max; c3++)
-      for (c0 = c0min; c0 <= c0max; c0++)
-       for (c1 = c1min; c1 <= c1max; c1++)
-         for (c2 = c2min; c2 <= c2max; c2++)
-           if (histogram[c0][c1][c2][c3] != 0)
-             {
-               boxp->c3min = c3min = c3;
-               goto have_c3min;
-             }
-have_c3min:
-  if (c3max > c3min)
-    for (c3 = c3max; c3 >= c3min; c3--)
-      for (c0 = c0min; c0 <= c0max; c0++)
-       for (c1 = c1min; c1 <= c1max; c1++)
-         for (c2 = c2min; c2 <= c2max; c2++)
-           if (histogram[c0][c1][c2][c3] != 0)
-             {
-               boxp->c3max = c3max = c3;
-               goto have_c3max;
-             }
-have_c3max:
-  /* Update box volume.
-   * We use 2-norm rather than real volume here; this biases the method
-   * against making long narrow boxes, and it has the side benefit that
-   * a box is splittable iff norm > 0.
-   * Since the differences are expressed in histogram-cell units,
-   * we have to shift back to 8-bit units to get consistent distances; 
-   * after which, we scale according to the selected distance scale factors.
-   * TBB: alpha shifts back to 7 bit units. That was accounted for in the
-   * alpha scale factor. 
-   */
-  dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
-  dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;
-  dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;
-  dist3 = ((c3max - c3min) << C3_SHIFT) * C3_SCALE;
-  boxp->volume = dist0 * dist0 + dist1 * dist1 + dist2 * dist2 + dist3 * dist3;
-
-  /* Now scan remaining volume of box and compute population */
-  ccount = 0;
-  for (c0 = c0min; c0 <= c0max; c0++)
-    for (c1 = c1min; c1 <= c1max; c1++)
-      for (c2 = c2min; c2 <= c2max; c2++)
-       {
-         histp = &histogram[c0][c1][c2][c3min];
-         for (c3 = c3min; c3 <= c3max; c3++, histp++)
-           if (*histp != 0)
-             {
-               ccount++;
-             }
+
+       /* Update box volume.
+        * We use 2-norm rather than real volume here; this biases the method
+        * against making long narrow boxes, and it has the side benefit that
+        * a box is splittable iff norm > 0.
+        * Since the differences are expressed in histogram-cell units,
+        * we have to shift back to JSAMPLE units to get consistent distances;
+        * after which, we scale according to the selected distance scale factors.
+        */
+       dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
+       dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;
+       dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;
+       boxp->volume = dist0 * dist0 + dist1 * dist1 + dist2 * dist2;
+
+       /* Now scan remaining volume of box and compute population */
+       ccount = 0;
+       for (c0 = c0min; c0 <= c0max; c0++) {
+               for (c1 = c1min; c1 <= c1max; c1++) {
+                       histp = &histogram[c0][c1][c2min];
+                       for (c2 = c2min; c2 <= c2max; c2++, histp++) {
+                               if (*histp != 0) {
+                                       ccount++;
+                               }
+                       }
+               }
        }
-  boxp->colorcount = ccount;
+       boxp->colorcount = ccount;
 }
 
 
-static int
-median_cut (gdImagePtr im, my_cquantize_ptr cquantize,
-           boxptr boxlist, int numboxes,
-           int desired_colors)
+LOCAL (int)
+#ifdef ORIGINAL_LIB_JPEG
+median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, int desired_colors)
+#else
+median_cut (gdImagePtr im, my_cquantize_ptr cquantize, boxptr boxlist, int numboxes, int desired_colors)
+#endif
 /* Repeatedly select and split the largest box until we have enough boxes */
 {
-  int n, lb;
-  int c0, c1, c2, c3, cmax;
-  register boxptr b1, b2;
-
-  while (numboxes < desired_colors)
-    {
-      /* Select box to split.
-       * Current algorithm: by population for first half, then by volume.
-       */
-      if (numboxes * 2 <= desired_colors)
-       {
-         b1 = find_biggest_color_pop (boxlist, numboxes);
-       }
-      else
-       {
-         b1 = find_biggest_volume (boxlist, numboxes);
-       }
-      if (b1 == NULL)          /* no splittable boxes left! */
-       break;
-      b2 = &boxlist[numboxes]; /* where new box will go */
-      /* Copy the color bounds to the new box. */
-      b2->c0max = b1->c0max;
-      b2->c1max = b1->c1max;
-      b2->c2max = b1->c2max;
-      b2->c3max = b1->c3max;
-      b2->c0min = b1->c0min;
-      b2->c1min = b1->c1min;
-      b2->c2min = b1->c2min;
-      b2->c3min = b1->c3min;
-      /* Choose which axis to split the box on.
-       * Current algorithm: longest scaled axis.
-       * See notes in update_box about scaling distances.
-       */
-      c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;
-      c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;
-      c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;
-      c3 = ((b1->c3max - b1->c3min) << C3_SHIFT) * C3_SCALE;
-      /* We want to break any ties in favor of green, then red, then blue, 
-         with alpha last. */
-      cmax = c1;
-      n = 1;
-      if (c0 > cmax)
-       {
-         cmax = c0;
-         n = 0;
-       }
-      if (c2 > cmax)
-       {
-         cmax = c2;
-         n = 2;
-       }
-      if (c3 > cmax)
-       {
-         n = 3;
-       }
-      /* Choose split point along selected axis, and update box bounds.
-       * Current algorithm: split at halfway point.
-       * (Since the box has been shrunk to minimum volume,
-       * any split will produce two nonempty subboxes.)
-       * Note that lb value is max for lower box, so must be < old max.
-       */
-      switch (n)
-       {
-       case 0:
-         lb = (b1->c0max + b1->c0min) / 2;
-         b1->c0max = lb;
-         b2->c0min = lb + 1;
-         break;
-       case 1:
-         lb = (b1->c1max + b1->c1min) / 2;
-         b1->c1max = lb;
-         b2->c1min = lb + 1;
-         break;
-       case 2:
-         lb = (b1->c2max + b1->c2min) / 2;
-         b1->c2max = lb;
-         b2->c2min = lb + 1;
-         break;
-       case 3:
-         lb = (b1->c3max + b1->c3min) / 2;
-         b1->c3max = lb;
-         b2->c3min = lb + 1;
-         break;
+       int n, lb;
+       int c0, c1, c2, cmax;
+       register boxptr b1, b2;
+
+       while (numboxes < desired_colors) {
+               /* Select box to split.
+                * Current algorithm: by population for first half, then by volume.
+                */
+               if (numboxes * 2 <= desired_colors) {
+                       b1 = find_biggest_color_pop(boxlist, numboxes);
+               } else {
+                       b1 = find_biggest_volume(boxlist, numboxes);
+               }
+               if (b1 == NULL) { /* no splittable boxes left! */
+                       break;
+               }
+               b2 = &boxlist[numboxes];        /* where new box will go */
+               /* Copy the color bounds to the new box. */
+               b2->c0max = b1->c0max;
+               b2->c1max = b1->c1max;
+               b2->c2max = b1->c2max;
+               b2->c0min = b1->c0min;
+               b2->c1min = b1->c1min;
+               b2->c2min = b1->c2min;
+               /* Choose which axis to split the box on.
+                * Current algorithm: longest scaled axis.
+                * See notes in update_box about scaling distances.
+                */
+               c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;
+               c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;
+               c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;
+               /* We want to break any ties in favor of green, then red, blue last.
+                * This code does the right thing for R,G,B or B,G,R color orders only.
+                */
+#if RGB_RED == 0
+               cmax = c1;
+               n = 1;
+               if (c0 > cmax) {
+                       cmax = c0;
+                       n = 0;
+               }
+               if (c2 > cmax) {
+                       n = 2;
+               }
+#else
+               cmax = c1;
+               n = 1;
+               if (c2 > cmax) {
+                       cmax = c2;
+                       n = 2;
+               }
+               if (c0 > cmax) {
+                       n = 0;
+               }
+#endif
+               /* Choose split point along selected axis, and update box bounds.
+                * Current algorithm: split at halfway point.
+                * (Since the box has been shrunk to minimum volume,
+                * any split will produce two nonempty subboxes.)
+                * Note that lb value is max for lower box, so must be < old max.
+                */
+               switch (n) {
+                       case 0:
+                               lb = (b1->c0max + b1->c0min) / 2;
+                               b1->c0max = lb;
+                               b2->c0min = lb + 1;
+                               break;
+                       case 1:
+                               lb = (b1->c1max + b1->c1min) / 2;
+                               b1->c1max = lb;
+                               b2->c1min = lb + 1;
+                               break;
+                       case 2:
+                               lb = (b1->c2max + b1->c2min) / 2;
+                               b1->c2max = lb;
+                               b2->c2min = lb + 1;
+                               break;
+               }
+                       /* Update stats for boxes */
+#ifdef ORIGINAL_LIB_JPEG
+               update_box(cinfo, b1);
+               update_box(cinfo, b2);
+#else
+               update_box(im, cquantize, b1);
+               update_box(im, cquantize, b2);
+#endif
+               numboxes++;
        }
-      /* Update stats for boxes */
-      update_box (im, cquantize, b1);
-      update_box (im, cquantize, b2);
-      numboxes++;
-    }
-  return numboxes;
+
+       return numboxes;
 }
 
 
-static void
-compute_color (gdImagePtr im, my_cquantize_ptr cquantize,
-              boxptr boxp, int icolor)
-/* 
-   Compute representative color for a box, put it in 
-   palette index icolor */
+LOCAL (void)
+#ifndef ORIGINAL_LIB_JPEG
+ compute_color (gdImagePtr im, my_cquantize_ptr cquantize, boxptr boxp, int icolor)
+{
+#else
+ compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor)
+/* Compute representative color for a box, put it in colormap[icolor] */
 {
-  /* Current algorithm: mean weighted by pixels (not colors) */
-  /* Note it is important to get the rounding correct! */
-  hist4d histogram = cquantize->histogram;
-  histptr histp;
-  int c0, c1, c2, c3;
-  int c0min, c0max, c1min, c1max, c2min, c2max, c3min, c3max;
-  long count;
-  long total = 0;
-  long c0total = 0;
-  long c1total = 0;
-  long c2total = 0;
-  long c3total = 0;
-
-  c0min = boxp->c0min;
-  c0max = boxp->c0max;
-  c1min = boxp->c1min;
-  c1max = boxp->c1max;
-  c2min = boxp->c2min;
-  c2max = boxp->c2max;
-  c3min = boxp->c3min;
-  c3max = boxp->c3max;
-
-  for (c0 = c0min; c0 <= c0max; c0++)
-    {
-      for (c1 = c1min; c1 <= c1max; c1++)
-       {
-         for (c2 = c2min; c2 <= c2max; c2++)
-           {
-             histp = &histogram[c0][c1][c2][c3min];
-             for (c3 = c3min; c3 <= c3max; c3++)
-               {
-                 if ((count = *histp++) != 0)
-                   {
-                     total += count;
-                     c0total += ((c0 << C0_SHIFT) + ((1 << C0_SHIFT) >> 1)) * count;
-                     c1total += ((c1 << C1_SHIFT) + ((1 << C1_SHIFT) >> 1)) * count;
-                     c2total += ((c2 << C2_SHIFT) + ((1 << C2_SHIFT) >> 1)) * count;
-                     c3total += ((c3 << C3_SHIFT) + ((1 << C3_SHIFT) >> 1)) * count;
-                   }
+       /* Current algorithm: mean weighted by pixels (not colors) */
+       /* Note it is important to get the rounding correct! */
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+#endif
+       hist3d histogram = cquantize->histogram;
+       histptr histp;
+       int c0, c1, c2;
+       int c0min, c0max, c1min, c1max, c2min, c2max;
+       long count;
+       long total = 0;
+       long c0total = 0;
+       long c1total = 0;
+       long c2total = 0;
+
+       c0min = boxp->c0min;
+       c0max = boxp->c0max;
+       c1min = boxp->c1min;
+       c1max = boxp->c1max;
+       c2min = boxp->c2min;
+       c2max = boxp->c2max;
+
+       for (c0 = c0min; c0 <= c0max; c0++) {
+               for (c1 = c1min; c1 <= c1max; c1++) {
+                       histp = &histogram[c0][c1][c2min];
+                       for (c2 = c2min; c2 <= c2max; c2++) {
+                               if ((count = *histp++) != 0) {
+                                       total += count;
+                                       c0total += ((c0 << C0_SHIFT) + ((1 << C0_SHIFT) >> 1)) * count;
+                                       c1total += ((c1 << C1_SHIFT) + ((1 << C1_SHIFT) >> 1)) * count;
+                                       c2total += ((c2 << C2_SHIFT) + ((1 << C2_SHIFT) >> 1)) * count;
+                               }
+                       }
                }
-           }
        }
-    }
-  im->red[icolor] = (int) ((c0total + (total >> 1)) / total);
-  im->green[icolor] = (int) ((c1total + (total >> 1)) / total);
-  im->blue[icolor] = (int) ((c2total + (total >> 1)) / total);
-  im->alpha[icolor] = (int) ((c3total + (total >> 1)) / total);
-  im->open[icolor] = 0;
-  if (im->colorsTotal <= icolor)
-    {
-      im->colorsTotal = icolor + 1;
-    }
+
+#ifdef ORIGINAL_LIB_JPEG
+       cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total >> 1)) / total);
+       cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total >> 1)) / total);
+       cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total >> 1)) / total);
+#else
+       im->red[icolor] = (int) ((c0total + (total >> 1)) / total);
+       im->green[icolor] = (int) ((c1total + (total >> 1)) / total);
+       im->blue[icolor] = (int) ((c2total + (total >> 1)) / total);
+#endif
 }
 
-static void
+
+LOCAL (void)
+#ifdef ORIGINAL_LIB_JPEG
+select_colors (j_decompress_ptr cinfo, int desired_colors)
+#else
 select_colors (gdImagePtr im, my_cquantize_ptr cquantize, int desired_colors)
+#endif
 /* Master routine for color selection */
 {
-  boxptr boxlist;
-  int numboxes;
-  int i;
-
-  /* Allocate workspace for box list */
-  boxlist = (boxptr) gdMalloc (desired_colors * sizeof (box));
-  /* Initialize one box containing whole space */
-  numboxes = 1;
-  /* Note maxval for alpha is different */
-  boxlist[0].c0min = 0;
-  boxlist[0].c0max = 255 >> C0_SHIFT;
-  boxlist[0].c1min = 0;
-  boxlist[0].c1max = 255 >> C1_SHIFT;
-  boxlist[0].c2min = 0;
-  boxlist[0].c2max = 255 >> C2_SHIFT;
-  boxlist[0].c3min = 0;
-  boxlist[0].c3max = gdAlphaMax >> C3_SHIFT;
-  /* Shrink it to actually-used volume and set its statistics */
-  update_box (im, cquantize, &boxlist[0]);
-  /* Perform median-cut to produce final box list */
-  numboxes = median_cut (im, cquantize, boxlist, numboxes, desired_colors);
-  /* Compute the representative color for each box, fill colormap */
-  for (i = 0; i < numboxes; i++)
-    compute_color (im, cquantize, &boxlist[i], i);
-  /* TBB: if the image contains colors at both scaled ends
-     of the alpha range, rescale slightly to make sure alpha 
-     covers the full spectrum from 100% transparent to 100% 
-     opaque. Even a faint distinct background color is 
-     generally considered failure with regard to alpha. */
-
-  im->colorsTotal = numboxes;
-  gdFree (boxlist);
+       boxptr boxlist;
+       int numboxes;
+       int i;
+
+       /* Allocate workspace for box list */
+#ifdef ORIGINAL_LIB_JPEG
+       boxlist = (boxptr) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF (box));
+#else
+       boxlist = (boxptr) gdMalloc (desired_colors * sizeof (box));
+#endif
+       /* Initialize one box containing whole space */
+       numboxes = 1;
+       boxlist[0].c0min = 0;
+       boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
+       boxlist[0].c1min = 0;
+       boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
+       boxlist[0].c2min = 0;
+       boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
+#ifdef ORIGINAL_LIB_JPEG
+       /* Shrink it to actually-used volume and set its statistics */
+       update_box(cinfo, &boxlist[0]);
+       /* Perform median-cut to produce final box list */
+       numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors);
+       /* Compute the representative color for each box, fill colormap */
+       for (i = 0; i < numboxes; i++) {
+               compute_color(cinfo, &boxlist[i], i);
+       }
+       cinfo->actual_number_of_colors = numboxes;
+       TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes);
+#else
+       /* Shrink it to actually-used volume and set its statistics */
+       update_box(im, cquantize, &boxlist[0]);
+       /* Perform median-cut to produce final box list */
+       numboxes = median_cut(im, cquantize, boxlist, numboxes, desired_colors);
+       /* Compute the representative color for each box, fill colormap */
+       for (i = 0; i < numboxes; i++) {
+               compute_color(im, cquantize, &boxlist[i], i);
+       }
+       im->colorsTotal = numboxes;
+
+       /* If we had a pure transparency color, add it as the last palette entry.
+        * Skip incrementing the color count so that the dither / matching phase
+        * won't use it on pixels that shouldn't have been transparent. We'll
+        * increment it after all that finishes.
+        */
+       if (im->transparent >= 0) {
+               /* Save the transparent color. */
+               im->red[im->colorsTotal] = gdTrueColorGetRed(im->transparent);
+               im->green[im->colorsTotal] = gdTrueColorGetGreen(im->transparent);
+               im->blue[im->colorsTotal] = gdTrueColorGetBlue(im->transparent);
+               im->alpha[im->colorsTotal] = gdAlphaTransparent;
+               im->open[im->colorsTotal] = 0;
+       }
+
+       gdFree(boxlist);
+#endif
 }
 
 
@@ -759,17 +867,14 @@ select_colors (gdImagePtr im, my_cquantize_ptr cquantize, int desired_colors)
 #define BOX_C0_LOG  (HIST_C0_BITS-3)
 #define BOX_C1_LOG  (HIST_C1_BITS-3)
 #define BOX_C2_LOG  (HIST_C2_BITS-3)
-#define BOX_C3_LOG  (HIST_C3_BITS-3)
 
 #define BOX_C0_ELEMS  (1<<BOX_C0_LOG)  /* # of hist cells in update box */
 #define BOX_C1_ELEMS  (1<<BOX_C1_LOG)
 #define BOX_C2_ELEMS  (1<<BOX_C2_LOG)
-#define BOX_C3_ELEMS  (1<<BOX_C3_LOG)
 
 #define BOX_C0_SHIFT  (C0_SHIFT + BOX_C0_LOG)
 #define BOX_C1_SHIFT  (C1_SHIFT + BOX_C1_LOG)
 #define BOX_C2_SHIFT  (C2_SHIFT + BOX_C2_LOG)
-#define BOX_C3_SHIFT  (C3_SHIFT + BOX_C3_LOG)
 
 
 /*
@@ -780,9 +885,14 @@ select_colors (gdImagePtr im, my_cquantize_ptr cquantize, int desired_colors)
  * inner-loop variables.
  */
 
-static int
-find_nearby_colors (gdImagePtr im, my_cquantize_ptr cquantize,
-               int minc0, int minc1, int minc2, int minc3, int colorlist[])
+LOCAL (int)
+find_nearby_colors (
+#ifdef ORIGINAL_LIB_JPEG
+       j_decompress_ptr cinfo,
+#else
+       gdImagePtr im, my_cquantize_ptr cquantize,
+#endif
+       int minc0, int minc1, int minc2, JSAMPLE colorlist[])
 /* Locate the colormap entries close enough to an update box to be candidates
  * for the nearest entry to some cell(s) in the update box.  The update box
  * is specified by the center coordinates of its first cell.  The number of
@@ -792,185 +902,149 @@ find_nearby_colors (gdImagePtr im, my_cquantize_ptr cquantize,
  * the colors that need further consideration.
  */
 {
-  int numcolors = im->colorsTotal;
-  int maxc0, maxc1, maxc2, maxc3;
-  int centerc0, centerc1, centerc2, centerc3;
-  int i, x, ncolors;
-  int minmaxdist, min_dist, max_dist, tdist;
-  int mindist[MAXNUMCOLORS];   /* min distance to colormap entry i */
-
-  /* Compute true coordinates of update box's upper corner and center.
-   * Actually we compute the coordinates of the center of the upper-corner
-   * histogram cell, which are the upper bounds of the volume we care about.
-   * Note that since ">>" rounds down, the "center" values may be closer to
-   * min than to max; hence comparisons to them must be "<=", not "<".
-   */
-  maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));
-  centerc0 = (minc0 + maxc0) >> 1;
-  maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));
-  centerc1 = (minc1 + maxc1) >> 1;
-  maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));
-  centerc2 = (minc2 + maxc2) >> 1;
-  maxc3 = minc3 + ((1 << BOX_C3_SHIFT) - (1 << C3_SHIFT));
-  centerc3 = (minc3 + maxc3) >> 1;
-
-  /* For each color in colormap, find:
-   *  1. its minimum squared-distance to any point in the update box
-   *     (zero if color is within update box);
-   *  2. its maximum squared-distance to any point in the update box.
-   * Both of these can be found by considering only the corners of the box.
-   * We save the minimum distance for each color in mindist[];
-   * only the smallest maximum distance is of interest.
-   */
-  minmaxdist = 0x7FFFFFFFL;
-
-  for (i = 0; i < numcolors; i++)
-    {
-      /* We compute the squared-c0-distance term, then add in the other three. */
-      x = im->red[i];
-      if (x < minc0)
-       {
-         tdist = (x - minc0) * C0_SCALE;
-         min_dist = tdist * tdist;
-         tdist = (x - maxc0) * C0_SCALE;
-         max_dist = tdist * tdist;
-       }
-      else if (x > maxc0)
-       {
-         tdist = (x - maxc0) * C0_SCALE;
-         min_dist = tdist * tdist;
-         tdist = (x - minc0) * C0_SCALE;
-         max_dist = tdist * tdist;
-       }
-      else
-       {
-         /* within cell range so no contribution to min_dist */
-         min_dist = 0;
-         if (x <= centerc0)
-           {
-             tdist = (x - maxc0) * C0_SCALE;
-             max_dist = tdist * tdist;
-           }
-         else
-           {
-             tdist = (x - minc0) * C0_SCALE;
-             max_dist = tdist * tdist;
-           }
-       }
+#ifdef ORIGINAL_LIB_JPEG
+       int numcolors = cinfo->actual_number_of_colors;
+#else
+       int numcolors = im->colorsTotal;
+#endif
+       int maxc0, maxc1, maxc2;
+       int centerc0, centerc1, centerc2;
+       int i, x, ncolors;
+       INT32 minmaxdist, min_dist, max_dist, tdist;
+       INT32 mindist[MAXNUMCOLORS];    /* min distance to colormap entry i */
+
+       /* Compute true coordinates of update box's upper corner and center.
+        * Actually we compute the coordinates of the center of the upper-corner
+        * histogram cell, which are the upper bounds of the volume we care about.
+        * Note that since ">>" rounds down, the "center" values may be closer to
+        * min than to max; hence comparisons to them must be "<=", not "<".
+        */
+       maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));
+       centerc0 = (minc0 + maxc0) >> 1;
+       maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));
+       centerc1 = (minc1 + maxc1) >> 1;
+       maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));
+       centerc2 = (minc2 + maxc2) >> 1;
+
+       /* For each color in colormap, find:
+        *  1. its minimum squared-distance to any point in the update box
+        *     (zero if color is within update box);
+        *  2. its maximum squared-distance to any point in the update box.
+        * Both of these can be found by considering only the corners of the box.
+        * We save the minimum distance for each color in mindist[];
+        * only the smallest maximum distance is of interest.
+        */
+       minmaxdist = 0x7FFFFFFFL;
+
+       for (i = 0; i < numcolors; i++) {
+               /* We compute the squared-c0-distance term, then add in the other two. */
+#ifdef ORIGINAL_LIB_JPEG
+               x = GETJSAMPLE(cinfo->colormap[0][i]);
+#else
+               x = im->red[i];
+#endif
+               if (x < minc0) {
+                       tdist = (x - minc0) * C0_SCALE;
+                       min_dist = tdist * tdist;
+                       tdist = (x - maxc0) * C0_SCALE;
+                       max_dist = tdist * tdist;
+               } else if (x > maxc0) {
+                       tdist = (x - maxc0) * C0_SCALE;
+                       min_dist = tdist * tdist;
+                       tdist = (x - minc0) * C0_SCALE;
+                       max_dist = tdist * tdist;
+               } else {
+                       /* within cell range so no contribution to min_dist */
+                       min_dist = 0;
+                       if (x <= centerc0) {
+                               tdist = (x - maxc0) * C0_SCALE;
+                               max_dist = tdist * tdist;
+                       } else {
+                               tdist = (x - minc0) * C0_SCALE;
+                               max_dist = tdist * tdist;
+                       }
+               }
 
-      x = im->green[i];
-      if (x < minc1)
-       {
-         tdist = (x - minc1) * C1_SCALE;
-         min_dist += tdist * tdist;
-         tdist = (x - maxc1) * C1_SCALE;
-         max_dist += tdist * tdist;
-       }
-      else if (x > maxc1)
-       {
-         tdist = (x - maxc1) * C1_SCALE;
-         min_dist += tdist * tdist;
-         tdist = (x - minc1) * C1_SCALE;
-         max_dist += tdist * tdist;
-       }
-      else
-       {
-         /* within cell range so no contribution to min_dist */
-         if (x <= centerc1)
-           {
-             tdist = (x - maxc1) * C1_SCALE;
-             max_dist += tdist * tdist;
-           }
-         else
-           {
-             tdist = (x - minc1) * C1_SCALE;
-             max_dist += tdist * tdist;
-           }
-       }
+#ifdef ORIGINAL_LIB_JPEG
+               x = GETJSAMPLE(cinfo->colormap[1][i]);
+#else
+               x = im->green[i];
+#endif
+               if (x < minc1) {
+                       tdist = (x - minc1) * C1_SCALE;
+                       min_dist += tdist * tdist;
+                       tdist = (x - maxc1) * C1_SCALE;
+                       max_dist += tdist * tdist;
+               } else if (x > maxc1) {
+                       tdist = (x - maxc1) * C1_SCALE;
+                       min_dist += tdist * tdist;
+                       tdist = (x - minc1) * C1_SCALE;
+                       max_dist += tdist * tdist;
+               } else {
+                       /* within cell range so no contribution to min_dist */
+                       if (x <= centerc1) {
+                               tdist = (x - maxc1) * C1_SCALE;
+                               max_dist += tdist * tdist;
+                       } else {
+                               tdist = (x - minc1) * C1_SCALE;
+                               max_dist += tdist * tdist;
+                       }
+               }
 
-      x = im->blue[i];
-      if (x < minc2)
-       {
-         tdist = (x - minc2) * C2_SCALE;
-         min_dist += tdist * tdist;
-         tdist = (x - maxc2) * C2_SCALE;
-         max_dist += tdist * tdist;
-       }
-      else if (x > maxc2)
-       {
-         tdist = (x - maxc2) * C2_SCALE;
-         min_dist += tdist * tdist;
-         tdist = (x - minc2) * C2_SCALE;
-         max_dist += tdist * tdist;
-       }
-      else
-       {
-         /* within cell range so no contribution to min_dist */
-         if (x <= centerc2)
-           {
-             tdist = (x - maxc2) * C2_SCALE;
-             max_dist += tdist * tdist;
-           }
-         else
-           {
-             tdist = (x - minc2) * C2_SCALE;
-             max_dist += tdist * tdist;
-           }
-       }
+#ifdef ORIGINAL_LIB_JPEG
+               x = GETJSAMPLE (cinfo->colormap[2][i]);
+#else
+               x = im->blue[i];
+#endif
+               if (x < minc2) {
+                       tdist = (x - minc2) * C2_SCALE;
+                       min_dist += tdist * tdist;
+                       tdist = (x - maxc2) * C2_SCALE;
+                       max_dist += tdist * tdist;
+               } else if (x > maxc2) {
+                       tdist = (x - maxc2) * C2_SCALE;
+                       min_dist += tdist * tdist;
+                       tdist = (x - minc2) * C2_SCALE;
+                       max_dist += tdist * tdist;
+               } else {
+                       /* within cell range so no contribution to min_dist */
+                       if (x <= centerc2) {
+                               tdist = (x - maxc2) * C2_SCALE;
+                               max_dist += tdist * tdist;
+                       } else {
+                               tdist = (x - minc2) * C2_SCALE;
+                               max_dist += tdist * tdist;
+                       }
+               }
 
-      x = im->alpha[i];
-      if (x < minc3)
-       {
-         tdist = (x - minc3) * C3_SCALE;
-         min_dist += tdist * tdist;
-         tdist = (x - maxc3) * C3_SCALE;
-         max_dist += tdist * tdist;
-       }
-      else if (x > maxc3)
-       {
-         tdist = (x - maxc3) * C3_SCALE;
-         min_dist += tdist * tdist;
-         tdist = (x - minc3) * C3_SCALE;
-         max_dist += tdist * tdist;
-       }
-      else
-       {
-         /* within cell range so no contribution to min_dist */
-         if (x <= centerc3)
-           {
-             tdist = (x - maxc3) * C3_SCALE;
-             max_dist += tdist * tdist;
-           }
-         else
-           {
-             tdist = (x - minc3) * C3_SCALE;
-             max_dist += tdist * tdist;
-           }
+               mindist[i] = min_dist;  /* save away the results */
+               if (max_dist < minmaxdist)
+               minmaxdist = max_dist;
        }
 
-      mindist[i] = min_dist;   /* save away the results */
-      if (max_dist < minmaxdist)
-       minmaxdist = max_dist;
-    }
-
-  /* Now we know that no cell in the update box is more than minmaxdist
-   * away from some colormap entry.  Therefore, only colors that are
-   * within minmaxdist of some part of the box need be considered.
-   */
-  ncolors = 0;
-  for (i = 0; i < numcolors; i++)
-    {
-      if (mindist[i] <= minmaxdist)
-       colorlist[ncolors++] = i;
-    }
-  return ncolors;
+       /* Now we know that no cell in the update box is more than minmaxdist
+        * away from some colormap entry.       Therefore, only colors that are
+        * within minmaxdist of some part of the box need be considered.
+        */
+       ncolors = 0;
+       for (i = 0; i < numcolors; i++) {
+               if (mindist[i] <= minmaxdist) {
+                       colorlist[ncolors++] = (JSAMPLE) i;
+               }
+       }
+       return ncolors;
 }
 
 
-static void
-find_best_colors (gdImagePtr im, my_cquantize_ptr cquantize,
-                 int minc0, int minc1, int minc2, int minc3,
-                 int numcolors, int colorlist[], int bestcolor[])
+LOCAL (void) find_best_colors (
+#ifdef ORIGINAL_LIB_JPEG
+       j_decompress_ptr cinfo,
+#else
+       gdImagePtr im, my_cquantize_ptr cquantize,
+#endif
+       int minc0, int minc1, int minc2,
+       int numcolors, JSAMPLE colorlist[],
+       JSAMPLE bestcolor[])
 /* Find the closest colormap entry for each cell in the update box,
  * given the list of candidate colors prepared by find_nearby_colors.
  * Return the indexes of the closest entries in the bestcolor[] array.
@@ -978,48 +1052,59 @@ find_best_colors (gdImagePtr im, my_cquantize_ptr cquantize,
  * find the distance from a colormap entry to successive cells in the box.
  */
 {
-  int ic0, ic1, ic2;
-  int i, icolor;
-  register int *bptr;          /* pointer into bestdist[] array */
-  int *cptr;                   /* pointer into bestcolor[] array */
-  int dist0, dist1, dist2;     /* initial distance values */
-  int xx0, xx1, xx2;           /* distance increments */
-  int inc0, inc1, inc2, inc3;  /* initial values for increments */
-  /* This array holds the distance to the nearest-so-far color for each cell */
-  int bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS * BOX_C3_ELEMS];
-
-  /* Initialize best-distance for each cell of the update box */
-  bptr = bestdist;
-  for (i = BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS * BOX_C3_ELEMS - 1; i >= 0; i--)
-    *bptr++ = 0x7FFFFFFFL;
-
-  /* For each color selected by find_nearby_colors,
-   * compute its distance to the center of each cell in the box.
-   * If that's less than best-so-far, update best distance and color number.
-   */
-
-  /* Nominal steps between cell centers ("x" in Thomas article) */
-#define STEP_C0  ((1 << C0_SHIFT) * C0_SCALE)
-#define STEP_C1  ((1 << C1_SHIFT) * C1_SCALE)
-#define STEP_C2  ((1 << C2_SHIFT) * C2_SCALE)
-#define STEP_C3  ((1 << C3_SHIFT) * C3_SCALE)
-
-       for (i = 0; i < numcolors; i++) {
+       int ic0, ic1, ic2;
+       int i, icolor;
+       register INT32 *bptr;           /* pointer into bestdist[] array */
+       JSAMPLE *cptr;          /* pointer into bestcolor[] array */
+       INT32 dist0, dist1;             /* initial distance values */
+       register INT32 dist2;           /* current distance in inner loop */
+       INT32 xx0, xx1;         /* distance increments */
+       register INT32 xx2;
+       INT32 inc0, inc1, inc2; /* initial values for increments */
+       /* This array holds the distance to the nearest-so-far color for each cell */
+       INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+       /* Initialize best-distance for each cell of the update box */
+       bptr = bestdist;
+       for (i = BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS - 1; i >= 0; i--) {
+               *bptr++ = 0x7FFFFFFFL;
+       }
+
+       /* For each color selected by find_nearby_colors,
+        * compute its distance to the center of each cell in the box.
+        * If that's less than best-so-far, update best distance and color number.
+        */
+
+       /* Nominal steps between cell centers ("x" in Thomas article) */
+#define STEP_C0        ((1 << C0_SHIFT) * C0_SCALE)
+#define STEP_C1        ((1 << C1_SHIFT) * C1_SCALE)
+#define STEP_C2        ((1 << C2_SHIFT) * C2_SCALE)
+
+       for (i = 0; i < numcolors; i++) {
+               int r, g, b;
+#ifdef ORIGINAL_LIB_JPEG
+               icolor = GETJSAMPLE(colorlist[i]);
+               r = GETJSAMPLE(cinfo->colormap[0][icolor]);
+               g = GETJSAMPLE(cinfo->colormap[1][icolor]);
+               b = GETJSAMPLE(cinfo->colormap[2][icolor]);
+#else
                icolor = colorlist[i];
+               r = im->red[icolor];
+               g = im->green[icolor];
+               b = im->blue[icolor];
+#endif
+
                /* Compute (square of) distance from minc0/c1/c2 to this color */
-               inc0 = (minc0 - (im->red[icolor])) * C0_SCALE;
+               inc0 = (minc0 - r) * C0_SCALE;
                dist0 = inc0 * inc0;
-               inc1 = (minc1 - (im->green[icolor])) * C1_SCALE;
+               inc1 = (minc1 - g) * C1_SCALE;
                dist0 += inc1 * inc1;
-               inc2 = (minc2 - (im->blue[icolor])) * C2_SCALE;
+               inc2 = (minc2 - b) * C2_SCALE;
                dist0 += inc2 * inc2;
-               inc3 = (minc3 - (im->alpha[icolor])) * C3_SCALE;
-               dist0 += inc3 * inc3;
                /* Form the initial difference increments */
                inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
                inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;
                inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;
-               inc3 = inc3 * (2 * STEP_C3) + STEP_C3 * STEP_C3;
                /* Now loop over all cells in box, updating distance per Thomas method */
                bptr = bestdist;
                cptr = bestcolor;
@@ -1031,21 +1116,14 @@ find_best_colors (gdImagePtr im, my_cquantize_ptr cquantize,
                                dist2 = dist1;
                                xx2 = inc2;
                                for (ic2 = BOX_C2_ELEMS - 1; ic2 >= 0; ic2--) {
-                                       register int dist3 = dist2;             /* current distance in inner loop */
-                                       register int xx3 = inc3;
-                                       register int ic3;
-                                       for (ic3 = BOX_C3_ELEMS - 1; ic3 >= 0; ic3--) {
-                                               if (dist3 < *bptr) {
-                                                       *bptr = dist3;
-                                                       *cptr = icolor;
-                                               }
-                                               dist3 += xx3;
-                                               xx3 += 2 * STEP_C3 * STEP_C3;
-                                               bptr++;
-                                               cptr++;
+                                       if (dist2 < *bptr) {
+                                               *bptr = dist2;
+                                               *cptr = (JSAMPLE) icolor;
                                        }
                                        dist2 += xx2;
                                        xx2 += 2 * STEP_C2 * STEP_C2;
+                                       bptr++;
+                                       cptr++;
                                }
                                dist1 += xx1;
                                xx1 += 2 * STEP_C1 * STEP_C1;
@@ -1057,67 +1135,75 @@ find_best_colors (gdImagePtr im, my_cquantize_ptr cquantize,
 }
 
 
-static void
-fill_inverse_cmap (gdImagePtr im, my_cquantize_ptr cquantize,
-                  int c0, int c1, int c2, int c3)
+LOCAL (void)
+fill_inverse_cmap (
+#ifdef ORIGINAL_LIB_JPEG
+       j_decompress_ptr cinfo,
+#else
+       gdImagePtr im, my_cquantize_ptr cquantize,
+#endif
+       int c0, int c1, int c2)
 /* Fill the inverse-colormap entries in the update box that contains */
-/* histogram cell c0/c1/c2/c3.  (Only that one cell MUST be filled, but */
+/* histogram cell c0/c1/c2.    (Only that one cell MUST be filled, but */
 /* we can fill as many others as we wish.) */
 {
-  hist4d histogram = cquantize->histogram;
-  int minc0, minc1, minc2, minc3;      /* lower left corner of update box */
-  int ic0, ic1, ic2, ic3;
-  register int *cptr;          /* pointer into bestcolor[] array */
-  register histptr cachep;     /* pointer into main cache array */
-  /* This array lists the candidate colormap indexes. */
-  int colorlist[MAXNUMCOLORS];
-  int numcolors;               /* number of candidate colors */
-  /* This array holds the actually closest colormap index for each cell. */
-  int bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS * BOX_C3_ELEMS];
-
-  /* Convert cell coordinates to update box ID */
-  c0 >>= BOX_C0_LOG;
-  c1 >>= BOX_C1_LOG;
-  c2 >>= BOX_C2_LOG;
-  c3 >>= BOX_C3_LOG;
-
-  /* Compute true coordinates of update box's origin corner.
-   * Actually we compute the coordinates of the center of the corner
-   * histogram cell, which are the lower bounds of the volume we care about.
-   */
-  minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);
-  minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);
-  minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);
-  minc3 = (c3 << BOX_C3_SHIFT) + ((1 << C3_SHIFT) >> 1);
-  /* Determine which colormap entries are close enough to be candidates
-   * for the nearest entry to some cell in the update box.
-   */
-  numcolors = find_nearby_colors (im, cquantize, minc0, minc1, minc2, minc3, colorlist);
-
-  /* Determine the actually nearest colors. */
-  find_best_colors (im, cquantize, minc0, minc1, minc2, minc3, numcolors, colorlist,
-                   bestcolor);
-
-  /* Save the best color numbers (plus 1) in the main cache array */
-  c0 <<= BOX_C0_LOG;           /* convert ID back to base cell indexes */
-  c1 <<= BOX_C1_LOG;
-  c2 <<= BOX_C2_LOG;
-  c3 <<= BOX_C3_LOG;
-  cptr = bestcolor;
-  for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++)
-    {
-      for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++)
-       {
-         for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++)
-           {
-             cachep = &histogram[c0 + ic0][c1 + ic1][c2 + ic2][c3];
-             for (ic3 = 0; ic3 < BOX_C3_ELEMS; ic3++)
-               {
-                 *cachep++ = (histcell) ((*cptr++) + 1);
+#ifdef ORIGINAL_LIB_JPEG
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+#endif
+       hist3d histogram = cquantize->histogram;
+       int minc0, minc1, minc2;        /* lower left corner of update box */
+       int ic0, ic1, ic2;
+       register JSAMPLE *cptr; /* pointer into bestcolor[] array */
+       register histptr cachep;        /* pointer into main cache array */
+       /* This array lists the candidate colormap indexes. */
+       JSAMPLE colorlist[MAXNUMCOLORS];
+       int numcolors;          /* number of candidate colors */
+       /* This array holds the actually closest colormap index for each cell. */
+       JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+       /* Convert cell coordinates to update box ID */
+       c0 >>= BOX_C0_LOG;
+       c1 >>= BOX_C1_LOG;
+       c2 >>= BOX_C2_LOG;
+
+       /* Compute true coordinates of update box's origin corner.
+        * Actually we compute the coordinates of the center of the corner
+        * histogram cell, which are the lower bounds of the volume we care about.
+        */
+       minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);
+       minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);
+       minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);
+
+       /* Determine which colormap entries are close enough to be candidates
+        * for the nearest entry to some cell in the update box.
+        */
+#ifdef ORIGINAL_LIB_JPEG
+       numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
+
+       /* Determine the actually nearest colors. */
+       find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, bestcolor);
+#else
+       numcolors = find_nearby_colors(im, cquantize, minc0, minc1, minc2, colorlist);
+       find_best_colors(im, cquantize, minc0, minc1, minc2, numcolors, colorlist, bestcolor);
+#endif
+
+       /* Save the best color numbers (plus 1) in the main cache array */
+       c0 <<= BOX_C0_LOG;              /* convert ID back to base cell indexes */
+       c1 <<= BOX_C1_LOG;
+       c2 <<= BOX_C2_LOG;
+       cptr = bestcolor;
+       for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) {
+               for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {
+                       cachep = &histogram[c0 + ic0][c1 + ic1][c2];
+                       for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {
+#ifdef ORIGINAL_LIB_JPEG
+                               *cachep++ = (histcell) (GETJSAMPLE (*cptr++) + 1);
+#else
+                               *cachep++ = (histcell) ((*cptr++) + 1);
+#endif
+                       }
                }
-           }
        }
-    }
 }
 
 
@@ -1125,429 +1211,583 @@ fill_inverse_cmap (gdImagePtr im, my_cquantize_ptr cquantize,
  * Map some rows of pixels to the output colormapped representation.
  */
 
-void
+METHODDEF (void)
+#ifndef ORIGINAL_LIB_JPEG
 pass2_no_dither (gdImagePtr im, my_cquantize_ptr cquantize)
+{
+       register int *inptr;
+       register unsigned char *outptr;
+       int width = im->sx;
+       int num_rows = im->sy;
+#else
+pass2_no_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
 /* This version performs no dithering */
 {
-  hist4d histogram = cquantize->histogram;
-  register int *inptr;
-  register unsigned char *outptr;
-  register histptr cachep;
-  register int c0, c1, c2, c3;
-  int row;
-  int col;
-  int width = im->sx;
-  int num_rows = im->sy;
-  for (row = 0; row < num_rows; row++)
-    {
-      inptr = im->tpixels[row];
-      outptr = im->pixels[row];
-      for (col = 0; col < width; col++)
-       {
-         int r, g, b, a;
-         /* get pixel value and index into the cache */
-         r = gdTrueColorGetRed (*inptr);
-         g = gdTrueColorGetGreen (*inptr);
-         b = gdTrueColorGetBlue (*inptr);
-         a = gdTrueColorGetAlpha (*inptr++);
-         c0 = r >> C0_SHIFT;
-         c1 = g >> C1_SHIFT;
-         c2 = b >> C2_SHIFT;
-         c3 = a >> C3_SHIFT;
-         cachep = &histogram[c0][c1][c2][c3];
-         /* If we have not seen this color before, find nearest colormap entry */
-         /* and update the cache */
-         if (*cachep == 0)
-           {
-#if 0
-             /* TBB: quick and dirty approach for use when testing
-                fill_inverse_cmap for errors */
-             int i;
-             int best = -1;
-             int mindist = 0x7FFFFFFF;
-             for (i = 0; (i < im->colorsTotal); i++)
-               {
-                 int rdist = (im->red[i] >> C0_SHIFT) - c0;
-                 int gdist = (im->green[i] >> C1_SHIFT) - c1;
-                 int bdist = (im->blue[i] >> C2_SHIFT) - c2;
-                 int adist = (im->alpha[i] >> C3_SHIFT) - c3;
-                 int dist = (rdist * rdist) * R_SCALE +
-                 (gdist * gdist) * G_SCALE +
-                 (bdist * bdist) * B_SCALE +
-                 (adist * adist) * A_SCALE;
-                 if (dist < mindist)
-                   {
-                     best = i;
-                     mindist = dist;
-                   }
-               }
-             *cachep = best + 1;
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+       register JSAMPROW inptr, outptr;
+       JDIMENSION width = cinfo->output_width;
 #endif
-             fill_inverse_cmap (im, cquantize, c0, c1, c2, c3);
-           }
-         /* Now emit the colormap index for this cell */
-         *outptr++ = (*cachep - 1);
-       }
-    }
-}
-
-/* We assume that right shift corresponds to signed division by 2 with
- * rounding towards minus infinity.  This is correct for typical "arithmetic
- * shift" instructions that shift in copies of the sign bit.  But some
- * C compilers implement >> with an unsigned shift.  For these machines you
- * must define RIGHT_SHIFT_IS_UNSIGNED.
- * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
- * It is only applied with constant shift counts.  SHIFT_TEMPS must be
- * included in the variables of any routine using RIGHT_SHIFT.
- */
-
-#ifdef RIGHT_SHIFT_IS_UNSIGNED
-#define SHIFT_TEMPS    INT32 shift_temp;
-#define RIGHT_SHIFT(x,shft)  \
-       ((shift_temp = (x)) < 0 ? \
-        (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
-        (shift_temp >> (shft)))
+       hist3d histogram = cquantize->histogram;
+       register int c0, c1, c2;
+       int row;
+       JDIMENSION col;
+       register histptr cachep;
+
+
+       for (row = 0; row < num_rows; row++) {
+               inptr = input_buf[row];
+               outptr = output_buf[row];
+               for (col = width; col > 0; col--){
+                       /* get pixel value and index into the cache */
+                       int r, g, b;
+#ifdef ORIGINAL_LIB_JPEG
+                       r = GETJSAMPLE(*inptr++);
+                       g = GETJSAMPLE(*inptr++);
+                       b = GETJSAMPLE(*inptr++);
 #else
-#define SHIFT_TEMPS
-#define RIGHT_SHIFT(x,shft)    ((x) >> (shft))
+                       r = gdTrueColorGetRed(*inptr);
+                       g = gdTrueColorGetGreen(*inptr);
+                       b = gdTrueColorGetBlue(*inptr++);
+
+                       /* If the pixel is transparent, we assign it the palette index that
+                        * will later be added at the end of the palette as the transparent
+                        * index.
+                        */
+                       if ((im->transparent >= 0) && (im->transparent == *inptr)) {
+                               *outptr++ = im->colorsTotal;
+                               continue;
+                       }
 #endif
+                       c0 = r >> C0_SHIFT;
+                       c1 = g >> C1_SHIFT;
+                       c2 = b >> C2_SHIFT;
+                       cachep = &histogram[c0][c1][c2];
+                       /* If we have not seen this color before, find nearest colormap entry
+                        * and update the cache
+                        */
+                       if (*cachep == 0) {
+#ifdef ORIGINAL_LIB_JPEG
+                               fill_inverse_cmap(cinfo, c0, c1, c2);
+#else
+                               fill_inverse_cmap(im, cquantize, c0, c1, c2);
+#endif
+                       }
+                       /* Now emit the colormap index for this cell */
+#ifdef ORIGINAL_LIB_JPEG
+                       *outptr++ = (JSAMPLE) (*cachep - 1);
+#else
+                       *outptr++ = (*cachep - 1);
+#endif 
+               }
+       }
+}
 
 
-void
+METHODDEF (void)
+#ifndef ORIGINAL_LIB_JPEG
 pass2_fs_dither (gdImagePtr im, my_cquantize_ptr cquantize)
-
+{
+#else
+pass2_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
 /* This version performs Floyd-Steinberg dithering */
 {
-  hist4d histogram = cquantize->histogram;
-  register LOCFSERROR cur0, cur1, cur2, cur3;  /* current error or pixel value */
-  LOCFSERROR belowerr0, belowerr1, belowerr2, belowerr3;       /* error for pixel below cur */
-  LOCFSERROR bpreverr0, bpreverr1, bpreverr2, bpreverr3;       /* error for below/prev col */
-  register FSERRPTR errorptr;  /* => fserrors[] at column before current */
-  int *inptr;                  /* => current input pixel */
-  unsigned char *outptr;       /* => current output pixel */
-  histptr cachep;
-  int dir;                     /* +1 or -1 depending on direction */
-  int dir4;                    /* 4*dir, for advancing errorptr */
-  int row;
-  int col;
-  int width = im->sx;
-  int num_rows = im->sy;
-  int *error_limit = cquantize->error_limiter;
-  int *colormap0 = im->red;
-  int *colormap1 = im->green;
-  int *colormap2 = im->blue;
-  int *colormap3 = im->alpha;
-  SHIFT_TEMPS
-
-    for (row = 0; row < num_rows; row++)
-    {
-      inptr = im->tpixels[row];
-      outptr = im->pixels[row];
-      if (cquantize->on_odd_row)
-       {
-         /* work right to left in this row */
-         inptr += (width - 1); /* so point to rightmost pixel */
-         outptr += width - 1;
-         dir = -1;
-         dir4 = -4;
-         errorptr = cquantize->fserrors + (width + 1) * 4;     /* => entry after last column */
-         cquantize->on_odd_row = FALSE;        /* flip for next time */
-       }
-      else
-       {
-         /* work left to right in this row */
-         dir = 1;
-         dir4 = 4;
-         errorptr = cquantize->fserrors;       /* => entry before first real column */
-         cquantize->on_odd_row = TRUE;         /* flip for next time */
-       }
-      /* Preset error values: no error propagated to first pixel from left */
-      cur0 = cur1 = cur2 = cur3 = 0;
-      /* and no error propagated to row below yet */
-      belowerr0 = belowerr1 = belowerr2 = belowerr3 = 0;
-      bpreverr0 = bpreverr1 = bpreverr2 = bpreverr3 = 0;
-
-      for (col = width; col > 0; col--)
-       {
-         int a;
-         /* curN holds the error propagated from the previous pixel on the
-          * current line.  Add the error propagated from the previous line
-          * to form the complete error correction term for this pixel, and
-          * round the error term (which is expressed * 16) to an integer.
-          * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
-          * for either sign of the error value.
-          * Note: errorptr points to *previous* column's array entry.
-          */
-         cur0 = RIGHT_SHIFT (cur0 + errorptr[dir4 + 0] + 8, 4);
-         cur1 = RIGHT_SHIFT (cur1 + errorptr[dir4 + 1] + 8, 4);
-         cur2 = RIGHT_SHIFT (cur2 + errorptr[dir4 + 2] + 8, 4);
-         cur3 = RIGHT_SHIFT (cur3 + errorptr[dir4 + 3] + 8, 4);
-         /* Limit the error using transfer function set by init_error_limit.
-          * See comments with init_error_limit for rationale.
-          */
-         cur0 = error_limit[cur0];
-         cur1 = error_limit[cur1];
-         cur2 = error_limit[cur2];
-         cur3 = error_limit[cur3];
-         /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
-          * The maximum error is +- MAXJSAMPLE (or less with error limiting);
-          * but we'll be lazy and just clamp this with an if test (TBB).
-          */
-         cur0 += gdTrueColorGetRed (*inptr);
-         cur1 += gdTrueColorGetGreen (*inptr);
-         cur2 += gdTrueColorGetBlue (*inptr);
-         /* Expand to 8 bits for consistency with dithering algorithm -- TBB */
-         a = gdTrueColorGetAlpha (*inptr);
-         cur3 += (a << 1) + (a >> 6);
-         if (cur0 < 0)
-           {
-             cur0 = 0;
-           }
-         if (cur0 > 255)
-           {
-             cur0 = 255;
-           }
-         if (cur1 < 0)
-           {
-             cur1 = 0;
-           }
-         if (cur1 > 255)
-           {
-             cur1 = 255;
-           }
-         if (cur2 < 0)
-           {
-             cur2 = 0;
-           }
-         if (cur2 > 255)
-           {
-             cur2 = 255;
-           }
-         if (cur3 < 0)
-           {
-             cur3 = 0;
-           }
-         if (cur3 > 255)
-           {
-             cur3 = 255;
-           }
-         /* Index into the cache with adjusted pixel value */
-         cachep = &histogram
-           [cur0 >> C0_SHIFT]
-           [cur1 >> C1_SHIFT]
-           [cur2 >> C2_SHIFT]
-           [cur3 >> (C3_SHIFT + 1)];
-         /* If we have not seen this color before, find nearest colormap */
-         /* entry and update the cache */
-         if (*cachep == 0)
-           fill_inverse_cmap (im, cquantize,
-                      cur0 >> C0_SHIFT, cur1 >> C1_SHIFT, cur2 >> C2_SHIFT,
-                              cur3 >> (C3_SHIFT + 1));
-         /* Now emit the colormap index for this cell */
-         {
-           register int pixcode = *cachep - 1;
-           *outptr = pixcode;
-           /* Compute representation error for this pixel */
-           cur0 -= colormap0[pixcode];
-           cur1 -= colormap1[pixcode];
-           cur2 -= colormap2[pixcode];
-           cur3 -= ((colormap3[pixcode] << 1) + (colormap3[pixcode] >> 6));
-         }
-         /* Compute error fractions to be propagated to adjacent pixels.
-          * Add these into the running sums, and simultaneously shift the
-          * next-line error sums left by 1 column.
-          */
-         {
-           register LOCFSERROR bnexterr, delta;
-
-           bnexterr = cur0;    /* Process component 0 */
-           delta = cur0 * 2;
-           cur0 += delta;      /* form error * 3 */
-           errorptr[0] = (FSERROR) (bpreverr0 + cur0);
-           cur0 += delta;      /* form error * 5 */
-           bpreverr0 = belowerr0 + cur0;
-           belowerr0 = bnexterr;
-           cur0 += delta;      /* form error * 7 */
-           bnexterr = cur1;    /* Process component 1 */
-           delta = cur1 * 2;
-           cur1 += delta;      /* form error * 3 */
-           errorptr[1] = (FSERROR) (bpreverr1 + cur1);
-           cur1 += delta;      /* form error * 5 */
-           bpreverr1 = belowerr1 + cur1;
-           belowerr1 = bnexterr;
-           cur1 += delta;      /* form error * 7 */
-           bnexterr = cur2;    /* Process component 2 */
-           delta = cur2 * 2;
-           cur2 += delta;      /* form error * 3 */
-           errorptr[2] = (FSERROR) (bpreverr2 + cur2);
-           cur2 += delta;      /* form error * 5 */
-           bpreverr2 = belowerr2 + cur2;
-           belowerr2 = bnexterr;
-           cur2 += delta;      /* form error * 7 */
-           bnexterr = cur3;    /* Process component 3 */
-           delta = cur3 * 2;
-           cur3 += delta;      /* form error * 3 */
-           errorptr[3] = (FSERROR) (bpreverr3 + cur3);
-           cur3 += delta;      /* form error * 5 */
-           bpreverr3 = belowerr3 + cur3;
-           belowerr3 = bnexterr;
-           cur3 += delta;      /* form error * 7 */
-         }
-         /* At this point curN contains the 7/16 error value to be propagated
-          * to the next pixel on the current line, and all the errors for the
-          * next line have been shifted over.  We are therefore ready to move on.
-          */
-         inptr += dir;         /* Advance pixel pointers to next column */
-         outptr += dir;
-         errorptr += dir4;     /* advance errorptr to current column */
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+       JSAMPROW inptr;         /* => current input pixel */
+#endif
+       hist3d histogram = cquantize->histogram;
+       register LOCFSERROR cur0, cur1, cur2;   /* current error or pixel value */
+       LOCFSERROR belowerr0, belowerr1, belowerr2;     /* error for pixel below cur */
+       LOCFSERROR bpreverr0, bpreverr1, bpreverr2;     /* error for below/prev col */
+       register FSERRPTR errorptr;     /* => fserrors[] at column before current */
+       histptr cachep;
+       int dir;                        /* +1 or -1 depending on direction */
+       int dir3;                       /* 3*dir, for advancing inptr & errorptr */
+       int row;
+       JDIMENSION col;
+#ifdef ORIGINAL_LIB_JPEG
+       JSAMPROW outptr;                /* => current output pixel */
+       JDIMENSION width = cinfo->output_width;
+       JSAMPLE *range_limit = cinfo->sample_range_limit;
+       JSAMPROW colormap0 = cinfo->colormap[0];
+       JSAMPROW colormap1 = cinfo->colormap[1];
+       JSAMPROW colormap2 = cinfo->colormap[2];
+#else
+       int *inptr;                     /* => current input pixel */
+       unsigned char *outptr;  /* => current output pixel */
+       int width = im->sx;
+       int num_rows = im->sy;
+       int *colormap0 = im->red;
+       int *colormap1 = im->green;
+       int *colormap2 = im->blue;
+#endif
+       int *error_limit = cquantize->error_limiter;
+
+
+       SHIFT_TEMPS for (row = 0; row < num_rows; row++) {
+               inptr = input_buf[row];
+               outptr = output_buf[row];
+               if (cquantize->on_odd_row) {
+                       /* work right to left in this row */
+                       inptr += (width - 1) * 3;       /* so point to rightmost pixel */
+                       outptr += width - 1;
+                       dir = -1;
+                       dir3 = -3;
+                       errorptr = cquantize->fserrors + (width + 1) * 3;       /* => entry after last column */
+#ifdef ORIGINAL_LIB_JPEG_REVERSE_ODD_ROWS
+                       cquantize->on_odd_row = FALSE;  /* flip for next time */
+#endif
+               } else {
+                       /* work left to right in this row */
+                       dir = 1;
+                       dir3 = 3;
+                       errorptr = cquantize->fserrors; /* => entry before first real column */
+#ifdef ORIGINAL_LIB_JPEG_REVERSE_ODD_ROWS
+                       cquantize->on_odd_row = TRUE;   /* flip for next time */
+#endif
+               }
+               /* Preset error values: no error propagated to first pixel from left */
+               cur0 = cur1 = cur2 = 0;
+               /* and no error propagated to row below yet */
+               belowerr0 = belowerr1 = belowerr2 = 0;
+               bpreverr0 = bpreverr1 = bpreverr2 = 0;
+
+               for (col = width; col > 0; col--) {
+                       /* If this pixel is transparent, we want to assign it to the special
+                        * transparency color index past the end of the palette rather than
+                        * go through matching / dithering. */
+                       if ((im->transparent >= 0) && (*inptr == im->transparent)) {
+                               *outptr = im->colorsTotal;
+                               errorptr[0] = 0;
+                               errorptr[1] = 0;
+                               errorptr[2] = 0;
+                               errorptr[3] = 0;
+                               inptr += dir;
+                               outptr += dir;
+                               errorptr += dir3;
+                               continue;
+                       }
+                       /* curN holds the error propagated from the previous pixel on the
+                        * current line.        Add the error propagated from the previous line
+                        * to form the complete error correction term for this pixel, and
+                        * round the error term (which is expressed * 16) to an integer.
+                        * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+                        * for either sign of the error value.
+                        * Note: errorptr points to *previous* column's array entry.
+                        */
+                       cur0 = RIGHT_SHIFT (cur0 + errorptr[dir3 + 0] + 8, 4);
+                       cur1 = RIGHT_SHIFT (cur1 + errorptr[dir3 + 1] + 8, 4);
+                       cur2 = RIGHT_SHIFT (cur2 + errorptr[dir3 + 2] + 8, 4);
+                       /* Limit the error using transfer function set by init_error_limit.
+                        * See comments with init_error_limit for rationale.
+                        */
+                       cur0 = error_limit[cur0];
+                       cur1 = error_limit[cur1];
+                       cur2 = error_limit[cur2];
+                       /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+                        * The maximum error is +- MAXJSAMPLE (or less with error limiting);
+                        * this sets the required size of the range_limit array.
+                        */
+#ifdef ORIGINAL_LIB_JPEG
+                       cur0 += GETJSAMPLE (inptr[0]);
+                       cur1 += GETJSAMPLE (inptr[1]);
+                       cur2 += GETJSAMPLE (inptr[2]);
+                       cur0 = GETJSAMPLE (range_limit[cur0]);
+                       cur1 = GETJSAMPLE (range_limit[cur1]);
+                       cur2 = GETJSAMPLE (range_limit[cur2]);
+#else
+                       cur0 += gdTrueColorGetRed (*inptr);
+                       cur1 += gdTrueColorGetGreen (*inptr);
+                       cur2 += gdTrueColorGetBlue (*inptr);
+                       range_limit (cur0);
+                       range_limit (cur1);
+                       range_limit (cur2);
+#endif
+
+                       /* Index into the cache with adjusted pixel value */
+                       cachep = &histogram[cur0 >> C0_SHIFT][cur1 >> C1_SHIFT][cur2 >> C2_SHIFT];
+                       /* If we have not seen this color before, find nearest colormap */
+                       /* entry and update the cache */
+                       if (*cachep == 0) {
+#ifdef ORIGINAL_LIB_JPEG
+                               fill_inverse_cmap(cinfo, cur0 >> C0_SHIFT, cur1 >> C1_SHIFT, cur2 >> C2_SHIFT);
+#else
+                               fill_inverse_cmap(im, cquantize, cur0 >> C0_SHIFT, cur1 >> C1_SHIFT, cur2 >> C2_SHIFT);
+#endif
+                       }
+                       /* Now emit the colormap index for this cell */
+                       {
+                               register int pixcode = *cachep - 1;
+                               *outptr = (JSAMPLE) pixcode;
+                               /* Compute representation error for this pixel */
+#define GETJSAMPLE
+                               cur0 -= GETJSAMPLE(colormap0[pixcode]);
+                               cur1 -= GETJSAMPLE(colormap1[pixcode]);
+                               cur2 -= GETJSAMPLE(colormap2[pixcode]);
+#undef GETJSAMPLE
+                       }
+                       /* Compute error fractions to be propagated to adjacent pixels.
+                        * Add these into the running sums, and simultaneously shift the
+                        * next-line error sums left by 1 column.
+                        */
+                       {
+                               register LOCFSERROR bnexterr, delta;
+
+                               bnexterr = cur0;        /* Process component 0 */
+                               delta = cur0 * 2;
+                               cur0 += delta;  /* form error * 3 */
+                               errorptr[0] = (FSERROR) (bpreverr0 + cur0);
+                               cur0 += delta;  /* form error * 5 */
+                               bpreverr0 = belowerr0 + cur0;
+                               belowerr0 = bnexterr;
+                               cur0 += delta;  /* form error * 7 */
+                               bnexterr = cur1;        /* Process component 1 */
+                               delta = cur1 * 2;
+                               cur1 += delta;  /* form error * 3 */
+                               errorptr[1] = (FSERROR) (bpreverr1 + cur1);
+                               cur1 += delta;  /* form error * 5 */
+                               bpreverr1 = belowerr1 + cur1;
+                               belowerr1 = bnexterr;
+                               cur1 += delta;  /* form error * 7 */
+                               bnexterr = cur2;        /* Process component 2 */
+                               delta = cur2 * 2;
+                               cur2 += delta;  /* form error * 3 */
+                               errorptr[2] = (FSERROR) (bpreverr2 + cur2);
+                               cur2 += delta;  /* form error * 5 */
+                               bpreverr2 = belowerr2 + cur2;
+                               belowerr2 = bnexterr;
+                               cur2 += delta;  /* form error * 7 */
+                       }
+                       /* At this point curN contains the 7/16 error value to be propagated
+                        * to the next pixel on the current line, and all the errors for the
+                        * next line have been shifted over.    We are therefore ready to move on.
+                        */
+#ifdef ORIGINAL_LIB_JPEG
+                       inptr += dir3;  /* Advance pixel pointers to next column */
+#else
+                       inptr += dir;           /* Advance pixel pointers to next column */
+#endif
+                       outptr += dir;
+                       errorptr += dir3;       /* advance errorptr to current column */
+               }
+               /* Post-loop cleanup: we must unload the final error values into the
+                * final fserrors[] entry.      Note we need not unload belowerrN because
+                * it is for the dummy column before or after the actual array.
+                */
+               errorptr[0] = (FSERROR) bpreverr0;      /* unload prev errs into array */
+               errorptr[1] = (FSERROR) bpreverr1;
+               errorptr[2] = (FSERROR) bpreverr2;
        }
-      /* Post-loop cleanup: we must unload the final error values into the
-       * final fserrors[] entry.  Note we need not unload belowerrN because
-       * it is for the dummy column before or after the actual array.
-       */
-      errorptr[0] = (FSERROR) bpreverr0;       /* unload prev errs into array */
-      errorptr[1] = (FSERROR) bpreverr1;
-      errorptr[2] = (FSERROR) bpreverr2;
-      errorptr[3] = (FSERROR) bpreverr3;
-    }
 }
 
 
 /*
  * Initialize the error-limiting transfer function (lookup table).
  * The raw F-S error computation can potentially compute error values of up to
- * +- MAXJSAMPLE.  But we want the maximum correction applied to a pixel to be
- * much less, otherwise obviously wrong pixels will be created.  (Typical
+ * +- MAXJSAMPLE.      But we want the maximum correction applied to a pixel to be
+ * much less, otherwise obviously wrong pixels will be created.        (Typical
  * effects include weird fringes at color-area boundaries, isolated bright
- * pixels in a dark area, etc.)  The standard advice for avoiding this problem
+ * pixels in a dark area, etc.)        The standard advice for avoiding this problem
  * is to ensure that the "corners" of the color cube are allocated as output
  * colors; then repeated errors in the same direction cannot cause cascading
- * error buildup.  However, that only prevents the error from getting
+ * error buildup.      However, that only prevents the error from getting
  * completely out of hand; Aaron Giles reports that error limiting improves
  * the results even with corner colors allocated.
  * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
- * well, but the smoother transfer function used below is even better.  Thanks
+ * well, but the smoother transfer function used below is even better. Thanks
  * to Aaron Giles for this idea.
  */
 
-static int
+LOCAL (void)
+#ifdef ORIGINAL_LIB_JPEG
+init_error_limit (j_decompress_ptr cinfo)
+#else
 init_error_limit (gdImagePtr im, my_cquantize_ptr cquantize)
+#endif
 /* Allocate and fill in the error_limiter table */
 {
-  int *table;
-  int in, out;
-
-  cquantize->error_limiter_storage = (int *) gdMalloc ((255 * 2 + 1) * sizeof (int));
-  if (!cquantize->error_limiter_storage)
-    {
-      return 0;
-    }
-  /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
-  cquantize->error_limiter = cquantize->error_limiter_storage + 255;
-  table = cquantize->error_limiter;
-#define STEPSIZE ((255+1)/16)
-  /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
-  out = 0;
-  for (in = 0; in < STEPSIZE; in++, out++)
-    {
-      table[in] = out;
-      table[-in] = -out;
-    }
-  /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
-  for (; in < STEPSIZE * 3; in++, out += (in & 1) ? 0 : 1)
-    {
-      table[in] = out;
-      table[-in] = -out;
-    }
-  /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
-  for (; in <= 255; in++)
-    {
-      table[in] = out;
-      table[-in] = -out;
-    }
+       int *table;
+       int in, out;
+#ifdef ORIGINAL_LIB_JPEG
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+       table = (int *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE * 2 + 1) * SIZEOF (int));
+#else
+       cquantize->error_limiter_storage = (int *) gdMalloc ((MAXJSAMPLE * 2 + 1) * sizeof (int));
+       if (!cquantize->error_limiter_storage) {
+               return;
+       }
+       table = cquantize->error_limiter_storage;
+#endif
+
+       table += MAXJSAMPLE;            /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
+       cquantize->error_limiter = table;
+
+#define STEPSIZE ((MAXJSAMPLE+1)/16)
+       /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
+       out = 0;
+       for (in = 0; in < STEPSIZE; in++, out++){
+               table[in] = out;
+               table[-in] = -out;
+       }
+       /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
+       for (; in < STEPSIZE * 3; in++, out += (in & 1) ? 0 : 1) {
+               table[in] = out;
+               table[-in] = -out;
+       }
+       /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
+       for (; in <= MAXJSAMPLE; in++) {
+               table[in] = out;
+               table[-in] = -out;
+       }
 #undef STEPSIZE
-  return 1;
 }
 
-static void
-zeroHistogram (hist4d histogram)
+
+/*
+ * Finish up at the end of each pass.
+ */
+
+#ifdef ORIGINAL_LIB_JPEG
+METHODDEF (void) finish_pass1 (j_decompress_ptr cinfo)
+{
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+       /* Select the representative colors and fill in cinfo->colormap */
+       cinfo->colormap = cquantize->sv_colormap;
+       select_colors (cinfo, cquantize->desired);
+       /* Force next pass to zero the color index table */
+       cquantize->needs_zeroed = TRUE;
+}
+
+
+METHODDEF (void) finish_pass2 (j_decompress_ptr cinfo)
+{
+       /* no work */
+}
+
+/*
+ * Initialize for each processing pass.
+ */
+
+METHODDEF (void) start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+       hist3d histogram = cquantize->histogram;
+       int i;
+
+       /* Only F-S dithering or no dithering is supported. */
+       /* If user asks for ordered dither, give him F-S. */
+       if (cinfo->dither_mode != JDITHER_NONE) {
+               cinfo->dither_mode = JDITHER_FS;
+       }
+
+       if (is_pre_scan){
+               /* Set up method pointers */
+               cquantize->pub.color_quantize = prescan_quantize;
+               cquantize->pub.finish_pass = finish_pass1;
+               cquantize->needs_zeroed = TRUE; /* Always zero histogram */
+       } else {
+               /* Set up method pointers */
+               if (cinfo->dither_mode == JDITHER_FS) {
+                       cquantize->pub.color_quantize = pass2_fs_dither;
+               } else {
+                       cquantize->pub.color_quantize = pass2_no_dither;
+               }
+               cquantize->pub.finish_pass = finish_pass2;
+
+               /* Make sure color count is acceptable */
+               i = cinfo->actual_number_of_colors;
+               if (i < 1) {
+                       ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1);
+               }
+               if (i > MAXNUMCOLORS) {
+                       ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+               }
+
+               if (cinfo->dither_mode == JDITHER_FS) {
+                       size_t arraysize = (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF (FSERROR)));
+                       /* Allocate Floyd-Steinberg workspace if we didn't already. */
+                       if (cquantize->fserrors == NULL) {
+                               cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+                       }
+                       /* Initialize the propagated errors to zero. */
+                       jzero_far((void FAR *) cquantize->fserrors, arraysize);
+                       /* Make the error-limit table if we didn't already. */
+                       if (cquantize->error_limiter == NULL) {
+                               init_error_limit(cinfo);
+                       }
+                       cquantize->on_odd_row = FALSE;
+               }
+
+       }
+       /* Zero the histogram or inverse color map, if necessary */
+       if (cquantize->needs_zeroed) {
+               for (i = 0; i < HIST_C0_ELEMS; i++) {
+                       jzero_far((void FAR *) histogram[i], HIST_C1_ELEMS * HIST_C2_ELEMS * SIZEOF (histcell));
+               }
+               cquantize->needs_zeroed = FALSE;
+       }
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+METHODDEF (void) new_color_map_2_quant (j_decompress_ptr cinfo)
 {
-  int i;
-  int j;
-  /* Zero the histogram or inverse color map */
-  for (i = 0; i < HIST_C0_ELEMS; i++)
-    {
-      for (j = 0; j < HIST_C1_ELEMS; j++)
-       {
-         memset (histogram[i][j],
-                 0,
-                 HIST_C2_ELEMS * HIST_C3_ELEMS * sizeof (histcell));
+       my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+       /* Reset the inverse color map */
+       cquantize->needs_zeroed = TRUE;
+}
+#else
+static void zeroHistogram (hist3d histogram)
+{
+       int i;
+       /* Zero the histogram or inverse color map */
+       for (i = 0; i < HIST_C0_ELEMS; i++) {
+               memset (histogram[i], 0, HIST_C1_ELEMS * HIST_C2_ELEMS * sizeof (histcell));
        }
-    }
 }
+#endif
+
+/*
+ * Module initialization routine for 2-pass color quantization.
+ */
 
-/* Here we go at last. */
+#ifdef ORIGINAL_LIB_JPEG
+GLOBAL (void)
+jinit_2pass_quantizer (j_decompress_ptr cinfo)
+#else
 void
 gdImageTrueColorToPalette (gdImagePtr im, int dither, int colorsWanted)
+#endif
 {
-       my_cquantize_ptr cquantize = 0;
+       my_cquantize_ptr cquantize = NULL;
        int i;
+
+#ifndef ORIGINAL_LIB_JPEG
+       /* Allocate the JPEG palette-storage */
        size_t arraysize;
-       if (!im->trueColor || colorsWanted <= 0) {
+       int maxColors = gdMaxColors;
+       if (!im->trueColor) {
                /* Nothing to do! */
                return;
        }
-       
-       if (colorsWanted > gdMaxColors) {
-               colorsWanted = gdMaxColors;
-       }
 
-       im->pixels = gdCalloc (sizeof (unsigned char *), im->sy);
+       /* If we have a transparent color (the alphaless mode of transparency), we
+        * must reserve a palette entry for it at the end of the palette. */
+       if (im->transparent >= 0){
+               maxColors--;
+       }
+       if (colorsWanted > maxColors) {
+               colorsWanted = maxColors;
+       }
+       im->pixels = gdCalloc(sizeof (unsigned char *), im->sy);
+       for (i = 0; (i < im->sy); i++) {
+               im->pixels[i] = gdCalloc(sizeof (unsigned char *), im->sx);
+       }
+#endif
 
-       for (i = 0; i < im->sy; i++) {
-               im->pixels[i] = gdCalloc (sizeof (unsigned char *), im->sx);
+#ifdef ORIGINAL_LIB_JPEG
+       cquantize = (my_cquantize_ptr) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF (my_cquantizer));
+       cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+       cquantize->pub.start_pass = start_pass_2_quant;
+       cquantize->pub.new_color_map = new_color_map_2_quant;
+       /* Make sure jdmaster didn't give me a case I can't handle */
+       if (cinfo->out_color_components != 3) {
+               ERREXIT (cinfo, JERR_NOTIMPL);
        }
-       cquantize = (my_cquantize_ptr) gdCalloc (sizeof (my_cquantizer), 1);
+#else
+       cquantize = (my_cquantize_ptr) gdCalloc(sizeof (my_cquantizer), 1);
+#endif
+       cquantize->fserrors = NULL;     /* flag optional arrays not allocated */
+       cquantize->error_limiter = NULL;
 
        /* Allocate the histogram/inverse colormap storage */
-       cquantize->histogram = (hist4d) gdMalloc (HIST_C0_ELEMS * sizeof (hist3d));
+#ifdef ORIGINAL_LIB_JPEG
+       cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF (hist2d));
+       for (i = 0; i < HIST_C0_ELEMS; i++) {
+               cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C1_ELEMS * HIST_C2_ELEMS * SIZEOF (histcell));
+       }
+       cquantize->needs_zeroed = TRUE; /* histogram is garbage now */
+#else
+       cquantize->histogram = (hist3d) gdMalloc (HIST_C0_ELEMS * sizeof (hist2d));
        for (i = 0; i < HIST_C0_ELEMS; i++) {
-               int j;
-               cquantize->histogram[i] = (hist3d) gdCalloc (HIST_C1_ELEMS, sizeof (hist2d));
-               for (j = 0; j < HIST_C1_ELEMS; j++) {
-                       cquantize->histogram[i][j] = (hist2d) gdCalloc (HIST_C2_ELEMS * HIST_C3_ELEMS, sizeof (histcell));
+               cquantize->histogram[i] = (hist2d) gdMalloc(HIST_C1_ELEMS * HIST_C2_ELEMS * sizeof (histcell));
+       }
+#endif
+
+#ifdef ORIGINAL_LIB_JPEG
+       /* Allocate storage for the completed colormap, if required.
+        * We do this now since it is FAR storage and may affect
+        * the memory manager's space calculations.
+        */
+       if (cinfo->enable_2pass_quant) {
+               /* Make sure color count is acceptable */
+               int desired = cinfo->desired_number_of_colors;
+               /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
+               if (desired < 8) {
+                       ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
+               }
+               /* Make sure colormap indexes can be represented by JSAMPLEs */
+               if (desired > MAXNUMCOLORS) {
+                       ERREXIT1 (cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
                }
+               cquantize->sv_colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3);
+               cquantize->desired = desired;
+       } else {
+               cquantize->sv_colormap = NULL;
+       }
+
+       /* Only F-S dithering or no dithering is supported. */
+       /* If user asks for ordered dither, give him F-S. */
+       if (cinfo->dither_mode != JDITHER_NONE) {
+               cinfo->dither_mode = JDITHER_FS;
        }
 
-       cquantize->fserrors = (FSERRPTR) gdMalloc (4 * sizeof (FSERROR));
+       /* Allocate Floyd-Steinberg workspace if necessary.
+        * This isn't really needed until pass 2, but again it is FAR storage.
+        * Although we will cope with a later change in dither_mode,
+        * we do not promise to honor max_memory_to_use if dither_mode changes.
+        */
+       if (cinfo->dither_mode == JDITHER_FS) {
+               cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF (FSERROR))));
+               /* Might as well create the error-limiting table too. */
+               init_error_limit(cinfo);
+       }
+#else
+
+       cquantize->fserrors = (FSERRPTR) gdMalloc(3 * sizeof (FSERROR));
        init_error_limit (im, cquantize);
-       arraysize = (size_t) ((im->sx + 2) * (4 * sizeof (FSERROR)));
+       arraysize = (size_t) ((im->sx + 2) * (3 * sizeof (FSERROR)));
        gdFree(cquantize->fserrors);
        /* Allocate Floyd-Steinberg workspace. */
-       cquantize->fserrors = gdCalloc (arraysize, 1);
+       cquantize->fserrors = gdCalloc(arraysize, 1);
        cquantize->on_odd_row = FALSE;
 
        /* Do the work! */
-       zeroHistogram (cquantize->histogram);
-       prescan_quantize (im, cquantize);
-       select_colors (im, cquantize, colorsWanted);
-
-       zeroHistogram (cquantize->histogram);
+       zeroHistogram(cquantize->histogram);
+       prescan_quantize(im, cquantize);
+       /* TBB 2.0.5: pass colorsWanted, not 256! */
+       select_colors(im, cquantize, colorsWanted);
+       zeroHistogram(cquantize->histogram);
        if (dither) {
-               pass2_fs_dither (im, cquantize);
+               pass2_fs_dither(im, cquantize);
        } else {
-               pass2_no_dither (im, cquantize);
+               pass2_no_dither(im, cquantize);
        }
+#if 0  /* 2.0.12; we no longer attempt full alpha in palettes */
        if (cquantize->transparentIsPresent) {
                int mt = -1;
                int mtIndex = -1;
-               for (i = 0; i < im->colorsTotal; i++) {
+               for (i = 0; (i < im->colorsTotal); i++) {
                        if (im->alpha[i] > mt) {
                                mtIndex = i;
                                mt = im->alpha[i];
                        }
                }
-               for (i = 0; i < im->colorsTotal; i++) {
+               for (i = 0; (i < im->colorsTotal); i++) {
                        if (im->alpha[i] == mt) {
                                im->alpha[i] = gdAlphaTransparent;
                        }
@@ -1556,37 +1796,55 @@ gdImageTrueColorToPalette (gdImagePtr im, int dither, int colorsWanted)
        if (cquantize->opaqueIsPresent) {
                int mo = 128;
                int moIndex = -1;
-               for (i = 0; i < im->colorsTotal; i++) {
+               for (i = 0; (i < im->colorsTotal); i++) {
                        if (im->alpha[i] < mo) {
                                moIndex = i;
                                mo = im->alpha[i];
                        }
                }
-               for (i = 0; i < im->colorsTotal; i++) {
+               for (i = 0; (i < im->colorsTotal); i++) {
                        if (im->alpha[i] == mo) {
                                im->alpha[i] = gdAlphaOpaque;
                        }
                }
        }
-       
+#endif
+
+       /* If we had a 'transparent' color, increment the color count so it's
+        * officially in the palette and convert the transparent variable to point to
+        * an index rather than a color (Its data already exists and transparent
+        * pixels have already been mapped to it by this point, it is done late as to
+        * avoid color matching / dithering with it). */
+       if (im->transparent >= 0) {
+               im->transparent = im->colorsTotal;
+               im->colorsTotal++;
+       }
+
        /* Success! Get rid of the truecolor image data. */
        im->trueColor = 0;
        /* Junk the truecolor pixels */
        for (i = 0; i < im->sy; i++) {
                gdFree(im->tpixels[i]);
        }
-       gdFree (im->tpixels);
+       gdFree(im->tpixels);
        im->tpixels = 0;
        /* Tediously free stuff. */
 
+       if (im->trueColor) {
+               /* On failure only */
+               for (i = 0; i < im->sy; i++) {
+                       if (im->pixels[i]) {
+                               gdFree (im->pixels[i]);
+                       }
+               }
+               if (im->pixels) {
+                       gdFree (im->pixels);
+               }
+               im->pixels = 0;
+       }
+               
        for (i = 0; i < HIST_C0_ELEMS; i++) {
                if (cquantize->histogram[i]) {
-                       int j;
-                       for (j = 0; j < HIST_C1_ELEMS; j++) {
-                               if (cquantize->histogram[i][j]) {
-                                       gdFree(cquantize->histogram[i][j]);
-                               }
-                       }
                        gdFree(cquantize->histogram[i]);
                }
        }
@@ -1602,13 +1860,13 @@ gdImageTrueColorToPalette (gdImagePtr im, int dither, int colorsWanted)
        if (cquantize) {
                gdFree(cquantize);
        }
+#endif
 }
 
 /* bring the palette colors in im2 to be closer to im1
  *
  */
-int
-gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
+int gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
 {
        unsigned long *buf; /* stores our calculations */
        unsigned long *bp; /* buf ptr */
@@ -1629,7 +1887,7 @@ gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
        buf = (unsigned long *)gdMalloc( sizeof(unsigned long) * 5 * im2->colorsTotal );
        memset( buf, 0, sizeof(unsigned long) * 5 * im2->colorsTotal );
 
-       for( x=0; x<im1->sx; x++ ) {
+       for (x=0; x<im1->sx; x++) {
                for( y=0; y<im1->sy; y++ ) {
                        color = im2->pixels[y][x];
                        rgb = im1->tpixels[y][x];
@@ -1642,7 +1900,7 @@ gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
                }
        }
        bp = buf;
-       for( color=0; color<im2->colorsTotal; color++ ) {
+       for (color=0; color<im2->colorsTotal; color++) {
                count = *(bp++);
                if( count > 0 ) {
                        im2->red[color]         = *(bp++) / count;
@@ -1656,3 +1914,6 @@ gdImageColorMatch (gdImagePtr im1, gdImagePtr im2)
        gdFree(buf);
        return 0;
 }
+
+
+#endif
index 1c32e5623f8c1d31592094dc091f9bf639b497e3..e2219c0cbd7c44e454d7749e05ddce3549ccfd15 100644 (file)
@@ -18,7 +18,7 @@
  * element is replaced in the event of a cache miss after the cache has 
  * reached a given size.
  *
- * John Ellson  (ellson@lucent.com)  Oct 31, 1997
+ * John Ellson  (ellson@graphviz.org)  Oct 31, 1997
  *
  * Test this with:
  *               gcc -o gdcache -g -Wall -DTEST gdcache.c
index 2446d614bdecd763fcdf1253780d48c654401854..45d037475d8856e32d54954c194560a77b9e39dc 100644 (file)
@@ -5,7 +5,7 @@
  * element is replaced in the event of a cache miss after the cache has 
  * reached a given size.
  *
- * John Ellson  (ellson@lucent.com)  Oct 31, 1997
+ * John Ellson  (ellson@graphviz.org)  Oct 31, 1997
  *
  * Test this with:
  *              gcc -o gdcache -g -Wall -DTEST gdcache.c
index f93cd7e23b3df7a410eab1eb2358aa8880bbff7b..f196a980fb26f9e98069cfa8107829faf5ba6586 100644 (file)
@@ -2,7 +2,7 @@
 /********************************************/
 /* gd interface to freetype library         */
 /*                                          */
-/* John Ellson   ellson@lucent.com          */
+/* John Ellson   ellson@graphviz.org        */
 /********************************************/
 
 #include <stdio.h>
@@ -16,6 +16,7 @@
 #include <unistd.h>
 #else
 #include <io.h>
+#define R_OK 04                        /* Needed in Windows */
 #endif
 
 #ifdef WIN32
@@ -83,7 +84,7 @@ gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
 
 /*
  * DEFAULT_FONTPATH and PATHSEPARATOR are host type dependent and
- * are normally set by configure in gvconfig.h.  These are just
+ * are normally set by configure in config.h.  These are just
  * some last resort values that might match some Un*x system
  * if building this version of gd separate from graphviz.
  */
@@ -789,6 +790,7 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
        int render = (im && (im->trueColor || (fg <= 255 && fg >= -255)));
        FT_BitmapGlyph bm;
        int render_mode = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT;
+       int m, mfound;
        /* Now tuneable thanks to Wez Furlong */
        double linespace = LINESPACE;
        /* 2.0.6: put this declaration with the other declarations! */
@@ -847,13 +849,49 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
        if (fg < 0) {
                render_mode |= FT_LOAD_MONOCHROME;
        }
+       /* 2.0.12: allow explicit specification of the preferred map;
+        * but we still fall back if it is not available.
+        */
+       m = gdFTEX_Unicode;
+       if (strex && (strex->flags & gdFTEX_CHARMAP)) {
+               m = strex->charmap;
+       }
+       /* Try all three types of maps, but start with the specified one */
+       mfound = 0;
+       for (i = 0; i < 3; i++) {
+               switch (m) {
+                       case gdFTEX_Unicode:
+                               if (font->have_char_map_unicode) {
+                                       mfound = 1;
+                               }
+                               break;
+                       case gdFTEX_Shift_JIS:
+                               if (font->have_char_map_sjis) {
+                                       mfound = 1;
+                               }
+                               break;
+                       case gdFTEX_Big5:
+                               /* This was the 'else' case, we can't really 'detect' it */
+                               mfound = 1;
+                               break;
+               }
+               if (mfound) {
+                       break;
+               }
+               m++;
+               m %= 3;
+       }
+       if (!mfound) {
+               /* No character set found! */
+               return "No character set found";
+       }
 
 #ifndef JISX0208
        if (!font->have_char_map_sjis) {
                next = string;
        } else
 #endif
-               tmpstr = (char *) gdMalloc (BUFSIZ);
+               tmpstr = (char *) gdMalloc(BUFSIZ);
 
        while (*next) {
                ch = *next;
@@ -879,57 +917,65 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
                          next++;
                          continue;
                }
-
-               if (font->have_char_map_unicode) {
-                       /* use UTF-8 mapping from ASCII */
-                       len = gdTcl_UtfToUniChar (next, &ch);
-                       next += len;
-               } else if (font->have_char_map_sjis) {
-                       unsigned char c;
-                       int jiscode;
-
-                       c = *next;
-                       if (0xA1 <= c && c <= 0xFE) {
-                               next++;
-                               jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
-
-                               ch = (jiscode >> 8) & 0xFF;
-                               jiscode &= 0xFF;
-
-                               if (ch & 1) {
-                                       jiscode += 0x40 - 0x21;
-                               } else {
-                                       jiscode += 0x9E - 0x21;
-                               }
-
-                               if (jiscode >= 0x7F) {
-                                       jiscode++;
+               switch (m) {
+                       case gdFTEX_Unicode:
+                               if (font->have_char_map_unicode) {
+                                       /* use UTF-8 mapping from ASCII */
+                                       len = gdTcl_UtfToUniChar(next, &ch);
+                                       next += len;
                                }
-                               ch = (ch - 0x21) / 2 + 0x81;
-                               if (ch >= 0xA0) {
-                                       ch += 0x40;
+                               break;
+                       case gdFTEX_Shift_JIS: 
+                               if (font->have_char_map_sjis) {
+                                       unsigned char c;
+                                       int jiscode;
+                                       c = *next;
+                                       if (0xA1 <= c && c <= 0xFE) {
+                                               next++;
+                                               jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
+
+                                               ch = (jiscode >> 8) & 0xFF;
+                                               jiscode &= 0xFF;
+
+                                               if (ch & 1) {
+                                                       jiscode += 0x40 - 0x21;
+                                               } else {
+                                                       jiscode += 0x9E - 0x21;
+                                               }
+
+                                               if (jiscode >= 0x7F) {
+                                                       jiscode++;
+                                               }
+                                               ch = (ch - 0x21) / 2 + 0x81;
+                                               if (ch >= 0xA0) {
+                                                       ch += 0x40;
+                                               }
+
+                                               ch = (ch << 8) + jiscode;
+                                       } else {
+                                               ch = c & 0xFF;  /* don't extend sign */
+                                       }
+                                       next++;
                                }
-
-                               ch = (ch << 8) + jiscode;
-                       } else {
-                               ch = c & 0xFF;  /* don't extend sign */
-                       }
-                       next++;
-               } else {
-                       /*
-                        * Big 5 mapping:
-                        * use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
-                        * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
-                        */
-                       ch = (*next) & 0xFF;    /* don't extend sign */
-                       next++;
-                       /* first code of JIS-8 pair */
-                       if (ch >= 161 && *next) { /* don't advance past '\0' */
-                               /* TBB: Fix from Kwok Wah On: & 255 needed */
-                               ch = (ch * 256) + ((*next) & 255);
+                               break;
+                       case gdFTEX_Big5: {
+                               /*
+                                * Big 5 mapping:
+                                * use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
+                                * ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
+                                */
+                               ch = (*next) & 0xFF;    /* don't extend sign */
                                next++;
+                               if (ch >= 161   /* first code of JIS-8 pair */
+                                       && *next) { /* don't advance past '\0' */
+                                       /* TBB: Fix from Kwok Wah On: & 255 needed */
+                                       ch = (ch * 256) + ((*next) & 255);
+                                       next++;
+                               }
                        }
+                       break;
                }
+
                /* set rotation transform */
                FT_Set_Transform(face, &matrix, NULL);
                /* Convert character code to glyph index */
index 30609cde132b4881b8eadfb86b1dc1afe7e91ec4..ad839c8bb3b1ab9b63bf1b6e46808fb9fe464b34 100644 (file)
@@ -362,8 +362,7 @@ do_convert (unsigned char *to, unsigned char *from, const char *code)
   from_len = strlen ((const char *) from) + 1;
   to_len = BUFSIZ;
 
-  if (iconv (cd, (char **) &from, &from_len,
-            (char **) &to, &to_len) == -1)
+  if ((int) iconv(cd, (char **) &from, &from_len, (char **) &to, &to_len) == -1)
     {
 #ifdef HAVE_ERRNO_H
       if (errno == EINVAL)