Blame src/gdfx.c

Packit Service df60bb
#ifdef HAVE_CONFIG_H
Packit Service df60bb
#include "config.h"
Packit Service df60bb
#endif /* HAVE_CONFIG_H */
Packit Service df60bb
Packit Service df60bb
#include "gd.h"
Packit Service df60bb
#include "gd_errors.h"
Packit Service df60bb
#include <math.h>
Packit Service df60bb
Packit Service df60bb
/* In tests this is sufficient to prevent obvious artifacts */
Packit Service df60bb
#define MAG 4
Packit Service df60bb
Packit Service df60bb
#define PI 3.141592
Packit Service df60bb
#define DEG2RAD(x) ((x)*PI/180.)
Packit Service df60bb
Packit Service df60bb
#define MAX(x,y) ((x) > (y) ? (x) : (y))
Packit Service df60bb
#define MIN(x,y) ((x) < (y) ? (x) : (y))
Packit Service df60bb
Packit Service df60bb
#define MAX4(x,y,z,w) \
Packit Service df60bb
	((MAX((x),(y))) > (MAX((z),(w))) ? (MAX((x),(y))) : (MAX((z),(w))))
Packit Service df60bb
#define MIN4(x,y,z,w) \
Packit Service df60bb
	((MIN((x),(y))) < (MIN((z),(w))) ? (MIN((x),(y))) : (MIN((z),(w))))
Packit Service df60bb
Packit Service df60bb
#define MAXX(x) MAX4(x[0],x[2],x[4],x[6])
Packit Service df60bb
#define MINX(x) MIN4(x[0],x[2],x[4],x[6])
Packit Service df60bb
#define MAXY(x) MAX4(x[1],x[3],x[5],x[7])
Packit Service df60bb
#define MINY(x) MIN4(x[1],x[3],x[5],x[7])
Packit Service df60bb
Packit Service df60bb
/**
Packit Service df60bb
 * Function: gdImageStringFTCircle
Packit Service df60bb
 *
Packit Service df60bb
 * Draw text curved along the top and bottom of a circular area of an image.
Packit Service df60bb
 *
Packit Service df60bb
 * Parameters:
Packit Service df60bb
 *  im          - The image to draw onto.
Packit Service df60bb
 *  cx          - The x-coordinate of the center of the circular area.
Packit Service df60bb
 *  cy          - The y-coordinate of the center of the circular area.
Packit Service df60bb
 *  radius      - The radius of the circular area.
Packit Service df60bb
 *  textRadius  - The height of each character; if textRadius is 1/2 of radius,
Packit Service df60bb
 *	              characters extend halfway from the edge to the center.
Packit Service df60bb
 *  fillPortion - The percentage of the 180 degrees of the circular area
Packit Service df60bb
 *                assigned to each section of text, that is actually occupied
Packit Service df60bb
 *                by text. The value has to be in range 0.0 to 1.0, with useful
Packit Service df60bb
 *                values from about 0.4 to 0.9; 0.9 looks better than 1.0 which
Packit Service df60bb
 *                is rather crowded.
Packit Service df60bb
 *  font        - The fontlist that is passed to <gdImageStringFT>.
Packit Service df60bb
 *  points      - The point size, which functions as a hint. Although the size
Packit Service df60bb
 *                of the text is determined by radius, textRadius and
Packit Service df60bb
 *                fillPortion, a point size that 'hints' appropriately should be
Packit Service df60bb
 *                passed. If it's known that the text will be large, a large
Packit Service df60bb
 *                point size such as 24.0 should be passed to get the best
Packit Service df60bb
 *                results.
Packit Service df60bb
 *  top         - The text to draw clockwise at the top of the circular area.
Packit Service df60bb
 *  bottom      - The text to draw counterclockwise at the bottom of the
Packit Service df60bb
 *                circular area.
Packit Service df60bb
 *  fgcolor     - The font color.
Packit Service df60bb
 *
Packit Service df60bb
 * Returns:
Packit Service df60bb
 *  NULL on success, or an error string on failure.
Packit Service df60bb
 */
Packit Service df60bb
BGD_DECLARE(char*)
Packit Service df60bb
gdImageStringFTCircle (gdImagePtr im,
Packit Service df60bb
                       int cx,
Packit Service df60bb
                       int cy,
Packit Service df60bb
                       double radius,
Packit Service df60bb
                       double textRadius,
Packit Service df60bb
                       double fillPortion,
Packit Service df60bb
                       char *font,
Packit Service df60bb
                       double points, char *top, char *bottom, int fgcolor)
Packit Service df60bb
{
Packit Service df60bb
	char *err;
Packit Service df60bb
	int w;
Packit Service df60bb
	int brect[8];
Packit Service df60bb
	int sx1, sx2, sy1, sy2, sx, sy;
Packit Service df60bb
	int x, y;
Packit Service df60bb
	int fr, fg, fb, fa;
Packit Service df60bb
	int ox, oy;
Packit Service df60bb
	double prop;
Packit Service df60bb
	gdImagePtr im1;
Packit Service df60bb
	gdImagePtr im2;
Packit Service df60bb
	gdImagePtr im3;
Packit Service df60bb
	/* obtain brect so that we can size the image */
Packit Service df60bb
	err = gdImageStringFT ((gdImagePtr) NULL,
Packit Service df60bb
	                       &brect[0], 0, font, points * MAG, 0, 0, 0, bottom);
Packit Service df60bb
	if (err) {
Packit Service df60bb
		return err;
Packit Service df60bb
	}
Packit Service df60bb
	sx1 = MAXX (brect) - MINX (brect) + 6;
Packit Service df60bb
	sy1 = MAXY (brect) - MINY (brect) + 6;
Packit Service df60bb
	err = gdImageStringFT ((gdImagePtr) NULL,
Packit Service df60bb
	                       &brect[0], 0, font, points * MAG, 0, 0, 0, top);
Packit Service df60bb
	if (err) {
Packit Service df60bb
		return err;
Packit Service df60bb
	}
Packit Service df60bb
	sx2 = MAXX (brect) - MINX (brect) + 6;
Packit Service df60bb
	sy2 = MAXY (brect) - MINY (brect) + 6;
Packit Service df60bb
	/* Pad by 4 pixels to allow for slight errors
Packit Service df60bb
	   observed in the bounding box returned by freetype */
Packit Service df60bb
	if (sx1 > sx2) {
Packit Service df60bb
		sx = sx1 * 2 + 4;
Packit Service df60bb
	} else {
Packit Service df60bb
		sx = sx2 * 2 + 4;
Packit Service df60bb
	}
Packit Service df60bb
	if (sy1 > sy2) {
Packit Service df60bb
		sy = sy1;
Packit Service df60bb
	} else {
Packit Service df60bb
		sy = sy2;
Packit Service df60bb
	}
Packit Service df60bb
	im1 = gdImageCreateTrueColor (sx, sy);
Packit Service df60bb
	if (!im1) {
Packit Service df60bb
		return "could not create first image";
Packit Service df60bb
	}
Packit Service df60bb
	err = gdImageStringFT (im1, 0, gdTrueColor (255, 255, 255),
Packit Service df60bb
	                       font, points * MAG,
Packit Service df60bb
	                       0, ((sx / 2) - sx1) / 2, points * MAG, bottom);
Packit Service df60bb
	if (err) {
Packit Service df60bb
		gdImageDestroy (im1);
Packit Service df60bb
		return err;
Packit Service df60bb
	}
Packit Service df60bb
	/* We don't know the descent, which would be needed to do this
Packit Service df60bb
	   with the angle parameter. Instead, implement a simple
Packit Service df60bb
	   flip operation ourselves. */
Packit Service df60bb
	err = gdImageStringFT (im1, 0, gdTrueColor (255, 255, 255),
Packit Service df60bb
	                       font, points * MAG,
Packit Service df60bb
	                       0, sx / 2 + ((sx / 2) - sx2) / 2, points * MAG, top);
Packit Service df60bb
	if (err) {
Packit Service df60bb
		gdImageDestroy (im1);
Packit Service df60bb
		return err;
Packit Service df60bb
	}
Packit Service df60bb
	/* Flip in place is tricky, be careful not to double-swap things */
Packit Service df60bb
	if (sy & 1) {
Packit Service df60bb
		for (y = 0; (y <= (sy / 2)); y++) {
Packit Service df60bb
			int xlimit = sx - 2;
Packit Service df60bb
			if (y == (sy / 2)) {
Packit Service df60bb
				/* If there is a "middle" row, be careful
Packit Service df60bb
				   not to swap twice! */
Packit Service df60bb
				xlimit -= (sx / 4);
Packit Service df60bb
			}
Packit Service df60bb
			for (x = (sx / 2) + 2; (x < xlimit); x++) {
Packit Service df60bb
				int t;
Packit Service df60bb
				int ox = sx - x + (sx / 2) - 1;
Packit Service df60bb
				int oy = sy - y - 1;
Packit Service df60bb
				t = im1->tpixels[oy][ox];
Packit Service df60bb
				im1->tpixels[oy][ox] = im1->tpixels[y][x];
Packit Service df60bb
				im1->tpixels[y][x] = t;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	} else {
Packit Service df60bb
		for (y = 0; (y < (sy / 2)); y++) {
Packit Service df60bb
			int xlimit = sx - 2;
Packit Service df60bb
			for (x = (sx / 2) + 2; (x < xlimit); x++) {
Packit Service df60bb
				int t;
Packit Service df60bb
				int ox = sx - x + (sx / 2) - 1;
Packit Service df60bb
				int oy = sy - y - 1;
Packit Service df60bb
				t = im1->tpixels[oy][ox];
Packit Service df60bb
				im1->tpixels[oy][ox] = im1->tpixels[y][x];
Packit Service df60bb
				im1->tpixels[y][x] = t;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
#if STEP_PNGS
Packit Service df60bb
	{
Packit Service df60bb
		FILE *out = fopen ("gdfx1.png", "wb");
Packit Service df60bb
		gdImagePng (im1, out);
Packit Service df60bb
		fclose (out);
Packit Service df60bb
	}
Packit Service df60bb
#endif /* STEP_PNGS */
Packit Service df60bb
	/* Resample taller; the exact proportions of the text depend on the
Packit Service df60bb
	   ratio of textRadius to radius, and the value of fillPortion */
Packit Service df60bb
	if (sx > sy * 10) {
Packit Service df60bb
		w = sx;
Packit Service df60bb
	} else {
Packit Service df60bb
		w = sy * 10;
Packit Service df60bb
	}
Packit Service df60bb
	im2 = gdImageCreateTrueColor (w, w);
Packit Service df60bb
	if (!im2) {
Packit Service df60bb
		gdImageDestroy (im1);
Packit Service df60bb
		return "could not create resampled image";
Packit Service df60bb
	}
Packit Service df60bb
	prop = textRadius / radius;
Packit Service df60bb
	gdImageCopyResampled (im2, im1,
Packit Service df60bb
	                      gdImageSX (im2) * (1.0 - fillPortion) / 4,
Packit Service df60bb
	                      sy * 10 * (1.0 - prop),
Packit Service df60bb
	                      0, 0,
Packit Service df60bb
	                      gdImageSX (im2) * fillPortion / 2, sy * 10 * prop,
Packit Service df60bb
	                      gdImageSX (im1) / 2, gdImageSY (im1));
Packit Service df60bb
	gdImageCopyResampled (im2, im1,
Packit Service df60bb
	                      (gdImageSX (im2) / 2) +
Packit Service df60bb
	                      gdImageSX (im2) * (1.0 - fillPortion) / 4,
Packit Service df60bb
	                      sy * 10 * (1.0 - prop),
Packit Service df60bb
	                      gdImageSX (im1) / 2, 0,
Packit Service df60bb
	                      gdImageSX (im2) * fillPortion / 2, sy * 10 * prop,
Packit Service df60bb
	                      gdImageSX (im1) / 2, gdImageSY (im1));
Packit Service df60bb
#if STEP_PNGS
Packit Service df60bb
	{
Packit Service df60bb
		FILE *out = fopen ("gdfx2.png", "wb");
Packit Service df60bb
		gdImagePng (im2, out);
Packit Service df60bb
		fclose (out);
Packit Service df60bb
	}
Packit Service df60bb
#endif /* STEP_PNGS */
Packit Service df60bb
Packit Service df60bb
	gdImageDestroy (im1);
Packit Service df60bb
Packit Service df60bb
	/* Ready to produce a circle */
Packit Service df60bb
	im3 = gdImageSquareToCircle (im2, radius);
Packit Service df60bb
	if (im3 == NULL) {
Packit Service df60bb
		gdImageDestroy(im2);
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
	gdImageDestroy (im2);
Packit Service df60bb
	/* Now blend im3 with the destination. Cheat a little. The
Packit Service df60bb
	   source (im3) is white-on-black, so we can use the
Packit Service df60bb
	   red component as a basis for alpha as long as we're
Packit Service df60bb
	   careful to shift off the extra bit and invert
Packit Service df60bb
	   (alpha ranges from 0 to 127 where 0 is OPAQUE).
Packit Service df60bb
	   Also be careful to allow for an alpha component
Packit Service df60bb
	   in the fgcolor parameter itself (gug!) */
Packit Service df60bb
	fr = gdTrueColorGetRed (fgcolor);
Packit Service df60bb
	fg = gdTrueColorGetGreen (fgcolor);
Packit Service df60bb
	fb = gdTrueColorGetBlue (fgcolor);
Packit Service df60bb
	fa = gdTrueColorGetAlpha (fgcolor);
Packit Service df60bb
	ox = cx - (im3->sx / 2);
Packit Service df60bb
	oy = cy - (im3->sy / 2);
Packit Service df60bb
	for (y = 0; (y < im3->sy); y++) {
Packit Service df60bb
		for (x = 0; (x < im3->sx); x++) {
Packit Service df60bb
			int a = gdTrueColorGetRed (im3->tpixels[y][x]) >> 1;
Packit Service df60bb
			a *= (127 - fa);
Packit Service df60bb
			a /= 127;
Packit Service df60bb
			a = 127 - a;
Packit Service df60bb
			gdImageSetPixel (im, x + ox, y + oy,
Packit Service df60bb
			                 gdTrueColorAlpha (fr, fg, fb, a));
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	gdImageDestroy (im3);
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
#if GDFX_MAIN
Packit Service df60bb
Packit Service df60bb
int
Packit Service df60bb
main (int argc, char *argv[])
Packit Service df60bb
{
Packit Service df60bb
	FILE *in;
Packit Service df60bb
	FILE *out;
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	int radius;
Packit Service df60bb
	/* Create an image of text on a circle, with an
Packit Service df60bb
	   alpha channel so that we can copy it onto a
Packit Service df60bb
	   background */
Packit Service df60bb
	in = fopen ("eleanor.jpg", "rb");
Packit Service df60bb
	if (!in) {
Packit Service df60bb
		im = gdImageCreateTrueColor (300, 300);
Packit Service df60bb
	} else {
Packit Service df60bb
		im = gdImageCreateFromJpeg (in);
Packit Service df60bb
		fclose (in);
Packit Service df60bb
	}
Packit Service df60bb
	if (gdImageSX (im) < gdImageSY (im)) {
Packit Service df60bb
		radius = gdImageSX (im) / 2;
Packit Service df60bb
	} else {
Packit Service df60bb
		radius = gdImageSY (im) / 2;
Packit Service df60bb
	}
Packit Service df60bb
	gdImageStringFTCircle (im,
Packit Service df60bb
	                       gdImageSX (im) / 2,
Packit Service df60bb
	                       gdImageSY (im) / 2,
Packit Service df60bb
	                       radius,
Packit Service df60bb
	                       radius / 2,
Packit Service df60bb
	                       0.8,
Packit Service df60bb
	                       "arial",
Packit Service df60bb
	                       24,
Packit Service df60bb
	                       "top text",
Packit Service df60bb
	                       "bottom text", gdTrueColorAlpha (240, 240, 255, 32));
Packit Service df60bb
	out = fopen ("gdfx.png", "wb");
Packit Service df60bb
	if (!out) {
Packit Service df60bb
		gd_error("Can't create gdfx.png\n");
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
	gdImagePng (im, out);
Packit Service df60bb
	fclose (out);
Packit Service df60bb
	gdImageDestroy (im);
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
#endif /* GDFX_MAIN */
Packit Service df60bb
Packit Service df60bb
/* Note: don't change these */
Packit Service df60bb
#define SUPER 2
Packit Service df60bb
#define SUPERBITS1 1
Packit Service df60bb
#define SUPERBITS2 2
Packit Service df60bb
Packit Service df60bb
/**
Packit Service df60bb
 * Function: gdImageSquareToCircle
Packit Service df60bb
 *
Packit Service df60bb
 * Apply polar coordinate transformation to an image.
Packit Service df60bb
 *
Packit Service df60bb
 * The X axis of the original will be remapped to theta (angle) and the Y axis
Packit Service df60bb
 * of the original will be remapped to rho (distance from center).
Packit Service df60bb
 *
Packit Service df60bb
 * Parameters:
Packit Service df60bb
 *  im     - The image, which must be square, i.e. width == height.
Packit Service df60bb
 *  radius - The radius of the new image, i.e. width == height == radius * 2.
Packit Service df60bb
 *
Packit Service df60bb
 * Returns:
Packit Service df60bb
 *  The transformed image, or NULL on failure.
Packit Service df60bb
 */
Packit Service df60bb
BGD_DECLARE(gdImagePtr)
Packit Service df60bb
gdImageSquareToCircle (gdImagePtr im, int radius)
Packit Service df60bb
{
Packit Service df60bb
	int x, y;
Packit Service df60bb
	double c;
Packit Service df60bb
	gdImagePtr im2;
Packit Service df60bb
	if (im->sx != im->sy) {
Packit Service df60bb
		/* Source image must be square */
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
	im2 = gdImageCreateTrueColor (radius * 2, radius * 2);
Packit Service df60bb
	if (!im2) {
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
	/* Supersampling for a nicer result */
Packit Service df60bb
	c = (im2->sx / 2) * SUPER;
Packit Service df60bb
	for (y = 0; (y < im2->sy * SUPER); y++) {
Packit Service df60bb
		for (x = 0; (x < im2->sx * SUPER); x++) {
Packit Service df60bb
			double rho = sqrt ((x - c) * (x - c) + (y - c) * (y - c));
Packit Service df60bb
			int pix;
Packit Service df60bb
			int cpix;
Packit Service df60bb
			double theta;
Packit Service df60bb
			double ox;
Packit Service df60bb
			double oy;
Packit Service df60bb
			int red, green, blue, alpha;
Packit Service df60bb
			if (rho > c) {
Packit Service df60bb
				continue;
Packit Service df60bb
			}
Packit Service df60bb
			theta = atan2 (x - c, y - c) + PI / 2;
Packit Service df60bb
			if (theta < 0) {
Packit Service df60bb
				theta += 2 * PI;
Packit Service df60bb
			}
Packit Service df60bb
			/* Undo supersampling */
Packit Service df60bb
			oy = (rho * im->sx) / (im2->sx * SUPER / 2);
Packit Service df60bb
			ox = theta * im->sx / (3.141592653 * 2);
Packit Service df60bb
			pix = gdImageGetPixel (im, ox, oy);
Packit Service df60bb
			cpix = im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1];
Packit Service df60bb
			red =
Packit Service df60bb
			    (gdImageRed (im, pix) >> SUPERBITS2) + gdTrueColorGetRed (cpix);
Packit Service df60bb
			green =
Packit Service df60bb
			    (gdImageGreen (im, pix) >> SUPERBITS2) +
Packit Service df60bb
			    gdTrueColorGetGreen (cpix);
Packit Service df60bb
			blue =
Packit Service df60bb
			    (gdImageBlue (im, pix) >> SUPERBITS2) + gdTrueColorGetBlue (cpix);
Packit Service df60bb
			alpha =
Packit Service df60bb
			    (gdImageAlpha (im, pix) >> SUPERBITS2) +
Packit Service df60bb
			    gdTrueColorGetAlpha (cpix);
Packit Service df60bb
			im2->tpixels[y >> SUPERBITS1][x >> SUPERBITS1] =
Packit Service df60bb
			    gdTrueColorAlpha (red, green, blue, alpha);
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	/* Restore full dynamic range, 0-63 yields 0-252. Replication of
Packit Service df60bb
	   first 2 bits in last 2 bits has the desired effect. Note
Packit Service df60bb
	   slightly different arithmetic for alpha which is 7-bit.
Packit Service df60bb
	   NOTE: only correct for SUPER == 2 */
Packit Service df60bb
	for (y = 0; (y < im2->sy); y++) {
Packit Service df60bb
		for (x = 0; (x < im2->sx); x++) {
Packit Service df60bb
			/* Copy first 2 bits to last 2 bits, matching the
Packit Service df60bb
			   dynamic range of the original cheaply */
Packit Service df60bb
			int cpix = im2->tpixels[y][x];
Packit Service df60bb
Packit Service df60bb
			im2->tpixels[y][x] = gdTrueColorAlpha ((gdTrueColorGetRed (cpix) &
Packit Service df60bb
			                                        0xFC) +
Packit Service df60bb
			                                       ((gdTrueColorGetRed (cpix) &
Packit Service df60bb
			                                               0xC0) >> 6),
Packit Service df60bb
			                                       (gdTrueColorGetGreen (cpix) &
Packit Service df60bb
			                                        0xFC) +
Packit Service df60bb
			                                       ((gdTrueColorGetGreen (cpix)
Packit Service df60bb
			                                               & 0xC0) >> 6),
Packit Service df60bb
			                                       (gdTrueColorGetBlue (cpix) &
Packit Service df60bb
			                                        0xFC) +
Packit Service df60bb
			                                       ((gdTrueColorGetBlue (cpix) &
Packit Service df60bb
			                                               0xC0) >> 6),
Packit Service df60bb
			                                       (gdTrueColorGetAlpha (cpix) &
Packit Service df60bb
			                                        0x7C) +
Packit Service df60bb
			                                       ((gdTrueColorGetAlpha (cpix)
Packit Service df60bb
			                                               & 0x60) >> 6));
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	return im2;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* 2.0.16: Called by gdImageSharpen to avoid excessive code repetition
Packit Service df60bb
    Added on 2003-11-19 by
Packit Service df60bb
    Paul Troughton (paul<dot>troughton<at>ieee<dot>org)
Packit Service df60bb
    Given filter coefficents and colours of three adjacent pixels,
Packit Service df60bb
returns new colour for centre pixel
Packit Service df60bb
*/
Packit Service df60bb
Packit Service df60bb
int
Packit Service df60bb
gdImageSubSharpen (int pc, int c, int nc, float inner_coeff, float
Packit Service df60bb
                   outer_coeff)
Packit Service df60bb
{
Packit Service df60bb
	float red, green, blue, alpha;
Packit Service df60bb
Packit Service df60bb
	red = inner_coeff * gdTrueColorGetRed (c) + outer_coeff *
Packit Service df60bb
	      (gdTrueColorGetRed (pc) + gdTrueColorGetRed (nc));
Packit Service df60bb
	green = inner_coeff * gdTrueColorGetGreen (c) + outer_coeff *
Packit Service df60bb
	        (gdTrueColorGetGreen (pc) + gdTrueColorGetGreen (nc));
Packit Service df60bb
	blue = inner_coeff * gdTrueColorGetBlue (c) + outer_coeff *
Packit Service df60bb
	       (gdTrueColorGetBlue (pc) + gdTrueColorGetBlue (nc));
Packit Service df60bb
	alpha = gdTrueColorGetAlpha (c);
Packit Service df60bb
Packit Service df60bb
	/* Clamping, as can overshoot bounds in either direction */
Packit Service df60bb
	if (red > 255.0f) {
Packit Service df60bb
		red = 255.0f;
Packit Service df60bb
	}
Packit Service df60bb
	if (green > 255.0f) {
Packit Service df60bb
		green = 255.0f;
Packit Service df60bb
	}
Packit Service df60bb
	if (blue > 255.0f) {
Packit Service df60bb
		blue = 255.0f;
Packit Service df60bb
	}
Packit Service df60bb
	if (red < 0.0f) {
Packit Service df60bb
		red = 0.0f;
Packit Service df60bb
	}
Packit Service df60bb
	if (green < 0.0f) {
Packit Service df60bb
		green = 0.0f;
Packit Service df60bb
	}
Packit Service df60bb
	if (blue < 0.0f) {
Packit Service df60bb
		blue = 0.0f;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/**
Packit Service df60bb
 * Function: gdImageSharpen
Packit Service df60bb
 *
Packit Service df60bb
 * Sharpen an image.
Packit Service df60bb
 *
Packit Service df60bb
 * Uses a simple 3x3 convolution kernel and makes use of separability.
Packit Service df60bb
 * It's faster, but less flexible, than full-blown unsharp masking.
Packit Service df60bb
 * Silently does nothing to non-truecolor images and for pct<0, as it's not a useful blurring function.
Packit Service df60bb
 *
Packit Service df60bb
 * Parameters:
Packit Service df60bb
 *  pct - The sharpening percentage, which can be greater than 100.
Packit Service df60bb
 *
Packit Service df60bb
 * Author:
Packit Service df60bb
 *  Paul Troughton (paul<dot>troughton<at>ieee<dot>org)
Packit Service df60bb
 */
Packit Service df60bb
BGD_DECLARE(void)
Packit Service df60bb
gdImageSharpen (gdImagePtr im, int pct)
Packit Service df60bb
{
Packit Service df60bb
	int x, y;
Packit Service df60bb
	int sx, sy;
Packit Service df60bb
	float inner_coeff, outer_coeff;
Packit Service df60bb
Packit Service df60bb
	sx = im->sx;
Packit Service df60bb
	sy = im->sy;
Packit Service df60bb
Packit Service df60bb
	/* Must sum to 1 to avoid overall change in brightness.
Packit Service df60bb
	 * Scaling chosen so that pct=100 gives 1-D filter [-1 6 -1]/4,
Packit Service df60bb
	 * resulting in a 2-D filter [1 -6 1; -6 36 -6; 1 -6 1]/16,
Packit Service df60bb
	 * which gives noticeable, but not excessive, sharpening
Packit Service df60bb
	 */
Packit Service df60bb
Packit Service df60bb
	outer_coeff = -pct / 400.0;
Packit Service df60bb
	inner_coeff = 1 - 2 * outer_coeff;
Packit Service df60bb
Packit Service df60bb
	/* Don't try to do anything with non-truecolor images, as
Packit Service df60bb
	   pointless,
Packit Service df60bb
	   * nor for pct<=0, as small kernel size leads to nasty
Packit Service df60bb
	   artefacts when blurring
Packit Service df60bb
	 */
Packit Service df60bb
	if ((im->trueColor) && (pct > 0)) {
Packit Service df60bb
Packit Service df60bb
		/* First pass, 1-D convolution column-wise */
Packit Service df60bb
		for (x = 0; x < sx; x++) {
Packit Service df60bb
Packit Service df60bb
			/* pc is colour of previous pixel; c of the
Packit Service df60bb
			   current pixel and nc of the next */
Packit Service df60bb
			int pc, c, nc;
Packit Service df60bb
Packit Service df60bb
			/* Replicate edge pixel at image boundary */
Packit Service df60bb
			pc = gdImageGetPixel (im, x, 0);
Packit Service df60bb
Packit Service df60bb
			/* Stop looping before last pixel to avoid
Packit Service df60bb
			   conditional within loop */
Packit Service df60bb
			for (y = 0; y < sy - 1; y++) {
Packit Service df60bb
Packit Service df60bb
				c = gdImageGetPixel (im, x, y);
Packit Service df60bb
Packit Service df60bb
				nc = gdImageGetTrueColorPixel (im, x, y + 1);
Packit Service df60bb
Packit Service df60bb
				/* Update centre pixel to new colour */
Packit Service df60bb
				gdImageSetPixel (im, x, y,
Packit Service df60bb
				                 gdImageSubSharpen (pc, c, nc, inner_coeff,
Packit Service df60bb
				                                    outer_coeff));
Packit Service df60bb
Packit Service df60bb
				/* Save original colour of current
Packit Service df60bb
				   pixel for next time round */
Packit Service df60bb
				pc = c;
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			/* Deal with last pixel, replicating current
Packit Service df60bb
			   pixel at image boundary */
Packit Service df60bb
			c = gdImageGetPixel (im, x, y);
Packit Service df60bb
			gdImageSetPixel (im, x, y, gdImageSubSharpen
Packit Service df60bb
			                 (pc, c, c, inner_coeff, outer_coeff));
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		/* Second pass, 1-D convolution row-wise */
Packit Service df60bb
		for (y = 0; y < sy; y++) {
Packit Service df60bb
			int pc, c;
Packit Service df60bb
			pc = gdImageGetPixel (im, 0, y);
Packit Service df60bb
			for (x = 0; x < sx - 1; x++) {
Packit Service df60bb
				int c, nc;
Packit Service df60bb
				c = gdImageGetPixel (im, x, y);
Packit Service df60bb
				nc = gdImageGetTrueColorPixel (im, x + 1, y);
Packit Service df60bb
				gdImageSetPixel (im, x, y,
Packit Service df60bb
				                 gdImageSubSharpen (pc, c, nc, inner_coeff,
Packit Service df60bb
				                                    outer_coeff));
Packit Service df60bb
				pc = c;
Packit Service df60bb
			}
Packit Service df60bb
			c = gdImageGetPixel (im, x, y);
Packit Service df60bb
			gdImageSetPixel (im, x, y, gdImageSubSharpen
Packit Service df60bb
			                 (pc, c, c, inner_coeff, outer_coeff));
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
}
Packit Service df60bb