Back to index

tetex-bin  3.0
Defines | Functions
gdfx.c File Reference
#include "gd.h"
#include <math.h>

Go to the source code of this file.

Defines

#define MAG   4
#define PI   3.141592
#define DEG2RAD(x)   ((x)*PI/180.)
#define MAX(x, y)   ((x) > (y) ? (x) : (y))
#define MIN(x, y)   ((x) < (y) ? (x) : (y))
#define MAX4(x, y, z, w)   ((MAX((x),(y))) > (MAX((z),(w))) ? (MAX((x),(y))) : (MAX((z),(w))))
#define MIN4(x, y, z, w)   ((MIN((x),(y))) < (MIN((z),(w))) ? (MIN((x),(y))) : (MIN((z),(w))))
#define MAXX(x)   MAX4(x[0],x[2],x[4],x[6])
#define MINX(x)   MIN4(x[0],x[2],x[4],x[6])
#define MAXY(x)   MAX4(x[1],x[3],x[5],x[7])
#define MINY(x)   MIN4(x[1],x[3],x[5],x[7])
#define SUPER   2
#define SUPERBITS1   1
#define SUPERBITS2   2

Functions

 gdImageStringFTCircle (gdImagePtr im, int cx, int cy, double radius, double textRadius, double fillPortion, char *font, double points, char *top, char *bottom, int fgcolor)
 gdImageSquareToCircle (gdImagePtr im, int radius)
int gdImageSubSharpen (int pc, int c, int nc, float inner_coeff, float outer_coeff)
 gdImageSharpen (gdImagePtr im, int pct)

Define Documentation

#define DEG2RAD (   x)    ((x)*PI/180.)

Definition at line 8 of file gdfx.c.

#define MAG   4

Definition at line 5 of file gdfx.c.

#define MAX (   x,
  y 
)    ((x) > (y) ? (x) : (y))

Definition at line 10 of file gdfx.c.

#define MAX4 (   x,
  y,
  z,
  w 
)    ((MAX((x),(y))) > (MAX((z),(w))) ? (MAX((x),(y))) : (MAX((z),(w))))

Definition at line 13 of file gdfx.c.

#define MAXX (   x)    MAX4(x[0],x[2],x[4],x[6])

Definition at line 18 of file gdfx.c.

#define MAXY (   x)    MAX4(x[1],x[3],x[5],x[7])

Definition at line 20 of file gdfx.c.

#define MIN (   x,
  y 
)    ((x) < (y) ? (x) : (y))

Definition at line 11 of file gdfx.c.

#define MIN4 (   x,
  y,
  z,
  w 
)    ((MIN((x),(y))) < (MIN((z),(w))) ? (MIN((x),(y))) : (MIN((z),(w))))

Definition at line 15 of file gdfx.c.

#define MINX (   x)    MIN4(x[0],x[2],x[4],x[6])

Definition at line 19 of file gdfx.c.

#define MINY (   x)    MIN4(x[1],x[3],x[5],x[7])

Definition at line 21 of file gdfx.c.

#define PI   3.141592

Definition at line 7 of file gdfx.c.

#define SUPER   2

Definition at line 274 of file gdfx.c.

#define SUPERBITS1   1

Definition at line 275 of file gdfx.c.

#define SUPERBITS2   2

Definition at line 276 of file gdfx.c.


Function Documentation

gdImageSharpen ( gdImagePtr  im,
int  pct 
)

Definition at line 426 of file gdfx.c.

{
  int x, y;
  int sx, sy;
  float inner_coeff, outer_coeff;

  sx = im->sx;
  sy = im->sy;

  /* Must sum to 1 to avoid overall change in brightness.
   * Scaling chosen so that pct=100 gives 1-D filter [-1 6 -1]/4,
   * resulting in a 2-D filter [1 -6 1; -6 36 -6; 1 -6 1]/16,
   * which gives noticeable, but not excessive, sharpening
   */

  outer_coeff = -pct / 400.0;
  inner_coeff = 1 - 2 * outer_coeff;

  /* Don't try to do anything with non-truecolor images, as 
     pointless,
     * nor for pct<=0, as small kernel size leads to nasty 
     artefacts when blurring
   */
  if ((im->trueColor) && (pct > 0))
    {

      /* First pass, 1-D convolution column-wise */
      for (x = 0; x < sx; x++)
       {

         /* pc is colour of previous pixel; c of the 
            current pixel and nc of the next */
         int pc, c, nc;

         /* Replicate edge pixel at image boundary */
         pc = gdImageGetPixel (im, x, 0);

         /* Stop looping before last pixel to avoid 
            conditional within loop */
         for (y = 0; y < sy - 1; y++)
           {

             c = gdImageGetPixel (im, x, y);

             nc = gdImageGetTrueColorPixel (im, x, y + 1);

             /* Update centre pixel to new colour */
             gdImageSetPixel (im, x, y,
                            gdImageSubSharpen (pc, c, nc, inner_coeff,
                                            outer_coeff));

             /* Save original colour of current 
                pixel for next time round */
             pc = c;
           }

         /* Deal with last pixel, replicating current 
            pixel at image boundary */
         c = gdImageGetPixel (im, x, y);
         gdImageSetPixel (im, x, y, gdImageSubSharpen
                        (pc, c, c, inner_coeff, outer_coeff));
       }

      /* Second pass, 1-D convolution row-wise */
      for (y = 0; y < sy; y++)
       {
         int pc, c;
         pc = gdImageGetPixel (im, 0, y);
         for (x = 0; x < sx - 1; x++)
           {
             int c, nc;
             c = gdImageGetPixel (im, x, y);
             nc = gdImageGetTrueColorPixel (im, x + 1, y);
             gdImageSetPixel (im, x, y,
                            gdImageSubSharpen (pc, c, nc, inner_coeff,
                                            outer_coeff));
             pc = c;
           }
         c = gdImageGetPixel (im, x, y);
         gdImageSetPixel (im, x, y, gdImageSubSharpen
                        (pc, c, c, inner_coeff, outer_coeff));
       }
    }
}

Here is the call graph for this function:

gdImageSquareToCircle ( gdImagePtr  im,
int  radius 
)

Definition at line 279 of file gdfx.c.

{
  int x, y;
  double c;
  gdImagePtr im2;
  if (im->sx != im->sy)
    {
      /* Source image must be square */
      return 0;
    }
  im2 = gdImageCreateTrueColor (radius * 2, radius * 2);
  /* Supersampling for a nicer result */
  c = (im2->sx / 2) * SUPER;
  for (y = 0; (y < im2->sy * SUPER); y++)
    {
      for (x = 0; (x < im2->sx * SUPER); x++)
       {
         double rho = sqrt ((x - c) * (x - c) + (y - c) * (y - c));
         int pix;
         int cpix;
         double theta;
         double ox;
         double oy;
         int red, green, blue, alpha;
         if (rho > c)
           {
             continue;
           }
         theta = atan2 (x - c, y - c) + PI / 2;
         if (theta < 0)
           {
             theta += 2 * PI;
           }
         /* Undo supersampling */
         oy = (rho * im->sx) / (im2->sx * SUPER / 2);
         ox = theta * im->sx / (3.141592653 * 2);
         pix = gdImageGetPixel (im, ox, oy);
         cpix = im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1];
         red =
           (gdImageRed (im, pix) >> SUPERBITS2) + gdTrueColorGetRed (cpix);
         green =
           (gdImageGreen (im, pix) >> SUPERBITS2) +
           gdTrueColorGetGreen (cpix);
         blue =
           (gdImageBlue (im, pix) >> SUPERBITS2) + gdTrueColorGetBlue (cpix);
         alpha =
           (gdImageAlpha (im, pix) >> SUPERBITS2) +
           gdTrueColorGetAlpha (cpix);
         im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1] =
           gdTrueColorAlpha (red, green, blue, alpha);
       }
    }
  /* Restore full dynamic range, 0-63 yields 0-252. Replication of
     first 2 bits in last 2 bits has the desired effect. Note
     slightly different arithmetic for alpha which is 7-bit. 
     NOTE: only correct for SUPER == 2 */
  for (y = 0; (y < im2->sy); y++)
    {
      for (x = 0; (x < im2->sx); x++)
       {
         /* Copy first 2 bits to last 2 bits, matching the
            dynamic range of the original cheaply */
         int cpix = im2->tpixels[y][x];

         im2->tpixels[y][x] = gdTrueColorAlpha ((gdTrueColorGetRed (cpix) &
                                            0xFC) +
                                           ((gdTrueColorGetRed (cpix) &
                                             0xC0) >> 6),
                                           (gdTrueColorGetGreen (cpix) &
                                            0xFC) +
                                           ((gdTrueColorGetGreen (cpix)
                                             & 0xC0) >> 6),
                                           (gdTrueColorGetBlue (cpix) &
                                            0xFC) +
                                           ((gdTrueColorGetBlue (cpix) &
                                             0xC0) >> 6),
                                           (gdTrueColorGetAlpha (cpix) &
                                            0x7C) +
                                           ((gdTrueColorGetAlpha (cpix)
                                             & 0x60) >> 6));
       }
    }
  return im2;
}

Here is the caller graph for this function:

gdImageStringFTCircle ( gdImagePtr  im,
int  cx,
int  cy,
double  radius,
double  textRadius,
double  fillPortion,
char *  font,
double  points,
char *  top,
char *  bottom,
int  fgcolor 
)

Definition at line 24 of file gdfx.c.

{
  char *err;
  int w;
  int brect[8];
  int sx1, sx2, sy1, sy2, sx, sy;
  int x, y;
  int fr, fg, fb, fa;
  int ox, oy;
  double prop;
  gdImagePtr im1;
  gdImagePtr im2;
  gdImagePtr im3;
  /* obtain brect so that we can size the image */
  err = gdImageStringFT ((gdImagePtr) NULL,
                      &brect[0], 0, font, points * MAG, 0, 0, 0, bottom);
  if (err)
    {
      return err;
    }
  sx1 = MAXX (brect) - MINX (brect) + 6;
  sy1 = MAXY (brect) - MINY (brect) + 6;
  err = gdImageStringFT ((gdImagePtr) NULL,
                      &brect[0], 0, font, points * MAG, 0, 0, 0, top);
  if (err)
    {
      return err;
    }
  sx2 = MAXX (brect) - MINX (brect) + 6;
  sy2 = MAXY (brect) - MINY (brect) + 6;
  /* Pad by 4 pixels to allow for slight errors
     observed in the bounding box returned by freetype */
  if (sx1 > sx2)
    {
      sx = sx1 * 2 + 4;
    }
  else
    {
      sx = sx2 * 2 + 4;
    }
  if (sy1 > sy2)
    {
      sy = sy1;
    }
  else
    {
      sy = sy2;
    }
  im1 = gdImageCreateTrueColor (sx, sy);
  if (!im1)
    {
      return "could not create first image";
    }
  err = gdImageStringFT (im1, 0, gdTrueColor (255, 255, 255),
                      font, points * MAG,
                      0, ((sx / 2) - sx1) / 2, points * MAG, bottom);
  if (err)
    {
      gdImageDestroy (im1);
      return err;
    }
  /* We don't know the descent, which would be needed to do this
     with the angle parameter. Instead, implement a simple
     flip operation ourselves. */
  err = gdImageStringFT (im1, 0, gdTrueColor (255, 255, 255),
                      font, points * MAG,
                      0, sx / 2 + ((sx / 2) - sx2) / 2, points * MAG, top);
  if (err)
    {
      gdImageDestroy (im1);
      return err;
    }
  /* Flip in place is tricky, be careful not to double-swap things */
  if (sy & 1)
    {
      for (y = 0; (y <= (sy / 2)); y++)
       {
         int xlimit = sx - 2;
         if (y == (sy / 2))
           {
             /* If there is a "middle" row, be careful
                not to swap twice! */
             xlimit -= (sx / 4);
           }
         for (x = (sx / 2) + 2; (x < xlimit); x++)
           {
             int t;
             int ox = sx - x + (sx / 2) - 1;
             int oy = sy - y - 1;
             t = im1->tpixels[oy][ox];
             im1->tpixels[oy][ox] = im1->tpixels[y][x];
             im1->tpixels[y][x] = t;
           }
       }
    }
  else
    {
      for (y = 0; (y < (sy / 2)); y++)
       {
         int xlimit = sx - 2;
         for (x = (sx / 2) + 2; (x < xlimit); x++)
           {
             int t;
             int ox = sx - x + (sx / 2) - 1;
             int oy = sy - y - 1;
             t = im1->tpixels[oy][ox];
             im1->tpixels[oy][ox] = im1->tpixels[y][x];
             im1->tpixels[y][x] = t;
           }
       }
    }
#if STEP_PNGS
  {
    FILE *out = fopen ("gdfx1.png", "wb");
    gdImagePng (im1, out);
    fclose (out);
  }
#endif /* STEP_PNGS */
  /* Resample taller; the exact proportions of the text depend on the
     ratio of textRadius to radius, and the value of fillPortion */
  if (sx > sy * 10)
    {
      w = sx;
    }
  else
    {
      w = sy * 10;
    }
  im2 = gdImageCreateTrueColor (w, w);
  if (!im2)
    {
      gdImageDestroy (im1);
      return "could not create resampled image";
    }
  prop = textRadius / radius;
  gdImageCopyResampled (im2, im1,
                     gdImageSX (im2) * (1.0 - fillPortion) / 4,
                     sy * 10 * (1.0 - prop),
                     0, 0,
                     gdImageSX (im2) * fillPortion / 2, sy * 10 * prop,
                     gdImageSX (im1) / 2, gdImageSY (im1));
  gdImageCopyResampled (im2, im1,
                     (gdImageSX (im2) / 2) +
                     gdImageSX (im2) * (1.0 - fillPortion) / 4,
                     sy * 10 * (1.0 - prop),
                     gdImageSX (im1) / 2, 0,
                     gdImageSX (im2) * fillPortion / 2, sy * 10 * prop,
                     gdImageSX (im1) / 2, gdImageSY (im1));
#if STEP_PNGS
  {
    FILE *out = fopen ("gdfx2.png", "wb");
    gdImagePng (im2, out);
    fclose (out);
  }
#endif /* STEP_PNGS */
  /* Ready to produce a circle */
  im3 = gdImageSquareToCircle (im2, radius);
  gdImageDestroy (im1);
  gdImageDestroy (im2);
  /* Now blend im3 with the destination. Cheat a little. The
     source (im3) is white-on-black, so we can use the
     red component as a basis for alpha as long as we're
     careful to shift off the extra bit and invert
     (alpha ranges from 0 to 127 where 0 is OPAQUE). 
     Also be careful to allow for an alpha component
     in the fgcolor parameter itself (gug!) */
  fr = gdTrueColorGetRed (fgcolor);
  fg = gdTrueColorGetGreen (fgcolor);
  fb = gdTrueColorGetBlue (fgcolor);
  fa = gdTrueColorGetAlpha (fgcolor);
  ox = cx - (im3->sx / 2);
  oy = cy - (im3->sy / 2);
  for (y = 0; (y < im3->sy); y++)
    {
      for (x = 0; (x < im3->sx); x++)
       {
         int a = gdTrueColorGetRed (im3->tpixels[y][x]) >> 1;
         a *= (127 - fa);
         a /= 127;
         a = 127 - a;
         gdImageSetPixel (im, x + ox, y + oy,
                        gdTrueColorAlpha (fr, fg, fb, a));
       }
    }
  gdImageDestroy (im3);
  return 0;
}

Here is the call graph for this function:

int gdImageSubSharpen ( int  pc,
int  c,
int  nc,
float  inner_coeff,
float  outer_coeff 
)

Definition at line 372 of file gdfx.c.

{
  float red, green, blue, alpha;

  red = inner_coeff * gdTrueColorGetRed (c) + outer_coeff *
    (gdTrueColorGetRed (pc) + gdTrueColorGetRed (nc));
  green = inner_coeff * gdTrueColorGetGreen (c) + outer_coeff *
    (gdTrueColorGetGreen (pc) + gdTrueColorGetGreen (nc));
  blue = inner_coeff * gdTrueColorGetBlue (c) + outer_coeff *
    (gdTrueColorGetBlue (pc) + gdTrueColorGetBlue (nc));
  alpha = gdTrueColorGetAlpha (c);

  /* Clamping, as can overshoot bounds in either direction */
  if (red > 255.0f)
    {
      red = 255.0f;
    }
  if (green > 255.0f)
    {
      green = 255.0f;
    }
  if (blue > 255.0f)
    {
      blue = 255.0f;
    }
  if (red < 0.0f)
    {
      red = 0.0f;
    }
  if (green < 0.0f)
    {
      green = 0.0f;
    }
  if (blue < 0.0f)
    {
      blue = 0.0f;
    }

  return gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha);
}

Here is the caller graph for this function: