Blame src/gd_filter.c

Packit ed3af9
/**
Packit ed3af9
 * File: Image Filters
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
Packit ed3af9
#ifdef HAVE_CONFIG_H
Packit ed3af9
#include "config.h"
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#include "gd.h"
Packit ed3af9
#include "gdhelpers.h"
Packit ed3af9
#include "gd_intern.h"
Packit ed3af9
Packit ed3af9
#ifdef _WIN32
Packit ed3af9
# include <windows.h>
Packit ed3af9
#else
Packit ed3af9
# include <unistd.h>
Packit ed3af9
#endif
Packit ed3af9
#include <stdlib.h>
Packit ed3af9
#include <time.h>
Packit ed3af9
#include <math.h>
Packit ed3af9
Packit ed3af9
#undef NDEBUG
Packit ed3af9
/* Comment out this line to enable asserts.
Packit ed3af9
 * TODO: This logic really belongs in cmake and configure.
Packit ed3af9
 */
Packit ed3af9
#define NDEBUG 1
Packit ed3af9
#include <assert.h>
Packit ed3af9
Packit ed3af9
typedef int (BGD_STDCALL *FuncPtr)(gdImagePtr, int, int);
Packit ed3af9
Packit ed3af9
#define GET_PIXEL_FUNCTION(src)(src->trueColor?gdImageGetTrueColorPixel:gdImageGetPixel)
Packit ed3af9
#define MIN(a,b) ((a)<(b)?(a):(b))
Packit ed3af9
#define MAX(a,b) ((a)<(b)?(b):(a))
Packit ed3af9
Packit ed3af9
#ifdef _WIN32
Packit ed3af9
# define GD_SCATTER_SEED() (unsigned int)(time(0) * GetCurrentProcessId())
Packit ed3af9
#else
Packit ed3af9
# define GD_SCATTER_SEED() (unsigned int)(time(0) * getpid())
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdImageScatter
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageScatter(gdImagePtr im, int sub, int plus)
Packit ed3af9
{
Packit ed3af9
	gdScatter s;
Packit ed3af9
Packit ed3af9
	s.sub  = sub;
Packit ed3af9
	s.plus = plus;
Packit ed3af9
	s.num_colors = 0;
Packit ed3af9
	s.seed = GD_SCATTER_SEED();
Packit ed3af9
	return gdImageScatterEx(im, &s);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdImageScatterColor
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageScatterColor(gdImagePtr im, int sub, int plus, int colors[], unsigned int num_colors)
Packit ed3af9
{
Packit ed3af9
	gdScatter s;
Packit ed3af9
Packit ed3af9
	s.sub  = sub;
Packit ed3af9
	s.plus = plus;
Packit ed3af9
	s.colors = colors;
Packit ed3af9
	s.num_colors = num_colors;
Packit ed3af9
	s.seed = GD_SCATTER_SEED();
Packit ed3af9
	return gdImageScatterEx(im, &s);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdImageScatterEx
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageScatterEx(gdImagePtr im, gdScatterPtr scatter)
Packit ed3af9
{
Packit ed3af9
	register int x, y;
Packit ed3af9
	int dest_x, dest_y;
Packit ed3af9
	int pxl, new_pxl;
Packit ed3af9
	unsigned int n;
Packit ed3af9
	int sub = scatter->sub, plus = scatter->plus;
Packit ed3af9
Packit ed3af9
	if (plus == 0 && sub == 0) {
Packit ed3af9
		return 1;
Packit ed3af9
	} else if (sub >= plus) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	(void)srand(scatter->seed);
Packit ed3af9
Packit ed3af9
	if (scatter->num_colors) {
Packit ed3af9
		for (y = 0; y < im->sy; y++) {
Packit ed3af9
			for (x = 0; x < im->sx; x++) {
Packit ed3af9
				dest_x = (int) (x + ((rand() % (plus - sub)) + sub));
Packit ed3af9
				dest_y = (int) (y + ((rand() % (plus - sub)) + sub));
Packit ed3af9
Packit ed3af9
				if (!gdImageBoundsSafe(im, dest_x, dest_y)) {
Packit ed3af9
					continue;
Packit ed3af9
				}
Packit ed3af9
Packit ed3af9
				pxl = gdImageGetPixel(im, x, y);
Packit ed3af9
				new_pxl = gdImageGetPixel(im, dest_x, dest_y);
Packit ed3af9
Packit ed3af9
				for (n = 0; n < scatter->num_colors; n++) {
Packit ed3af9
					if (pxl == scatter->colors[n]) {
Packit ed3af9
						gdImageSetPixel(im, dest_x, dest_y, pxl);
Packit ed3af9
						gdImageSetPixel(im, x, y, new_pxl);
Packit ed3af9
					}
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	} else {
Packit ed3af9
		for (y = 0; y < im->sy; y++) {
Packit ed3af9
			for (x = 0; x < im->sx; x++) {
Packit ed3af9
				dest_x = (int) (x + ((rand() % (plus - sub)) + sub));
Packit ed3af9
				dest_y = (int) (y + ((rand() % (plus - sub)) + sub));
Packit ed3af9
Packit ed3af9
				if (!gdImageBoundsSafe(im, dest_x, dest_y)) {
Packit ed3af9
					continue;
Packit ed3af9
				}
Packit ed3af9
Packit ed3af9
				pxl = gdImageGetPixel(im, x, y);
Packit ed3af9
				new_pxl = gdImageGetPixel(im, dest_x, dest_y);
Packit ed3af9
Packit ed3af9
				gdImageSetPixel(im, dest_x, dest_y, pxl);
Packit ed3af9
				gdImageSetPixel(im, x, y, new_pxl);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdImagePixelate
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImagePixelate(gdImagePtr im, int block_size, const unsigned int mode)
Packit ed3af9
{
Packit ed3af9
	int x, y;
Packit ed3af9
Packit ed3af9
	if (block_size <= 0) {
Packit ed3af9
		return 0;
Packit ed3af9
	} else if (block_size == 1) {
Packit ed3af9
		return 1;
Packit ed3af9
	}
Packit ed3af9
	switch (mode) {
Packit ed3af9
	case GD_PIXELATE_UPPERLEFT:
Packit ed3af9
		for (y = 0; y < im->sy; y += block_size) {
Packit ed3af9
			for (x = 0; x < im->sx; x += block_size) {
Packit ed3af9
				if (gdImageBoundsSafe(im, x, y)) {
Packit ed3af9
					int c = gdImageGetPixel(im, x, y);
Packit ed3af9
					gdImageFilledRectangle(im, x, y, x + block_size - 1, y + block_size - 1, c);
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		break;
Packit ed3af9
	case GD_PIXELATE_AVERAGE:
Packit ed3af9
		for (y = 0; y < im->sy; y += block_size) {
Packit ed3af9
			for (x = 0; x < im->sx; x += block_size) {
Packit ed3af9
				int a, r, g, b, c;
Packit ed3af9
				int total;
Packit ed3af9
				int cx, cy;
Packit ed3af9
Packit ed3af9
				a = r = g = b = c = total = 0;
Packit ed3af9
				/* sampling */
Packit ed3af9
				for (cy = 0; cy < block_size; cy++) {
Packit ed3af9
					for (cx = 0; cx < block_size; cx++) {
Packit ed3af9
						if (!gdImageBoundsSafe(im, x + cx, y + cy)) {
Packit ed3af9
							continue;
Packit ed3af9
						}
Packit ed3af9
						c = gdImageGetPixel(im, x + cx, y + cy);
Packit ed3af9
						a += gdImageAlpha(im, c);
Packit ed3af9
						r += gdImageRed(im, c);
Packit ed3af9
						g += gdImageGreen(im, c);
Packit ed3af9
						b += gdImageBlue(im, c);
Packit ed3af9
						total++;
Packit ed3af9
					}
Packit ed3af9
				}
Packit ed3af9
				/* drawing */
Packit ed3af9
				if (total > 0) {
Packit ed3af9
					c = gdImageColorResolveAlpha(im, r / total, g / total, b / total, a / total);
Packit ed3af9
					gdImageFilledRectangle(im, x, y, x + block_size - 1, y + block_size - 1, c);
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		break;
Packit ed3af9
	default:
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageNegate
Packit ed3af9
 *
Packit ed3af9
 * Invert an image
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src - The image.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageNegate(gdImagePtr src)
Packit ed3af9
{
Packit ed3af9
	int x, y;
Packit ed3af9
	int r,g,b,a;
Packit ed3af9
	int new_pxl, pxl;
Packit ed3af9
	FuncPtr f;
Packit ed3af9
Packit ed3af9
	if (src==NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	f = GET_PIXEL_FUNCTION(src);
Packit ed3af9
Packit ed3af9
	for (y=0; y<src->sy; ++y) {
Packit ed3af9
		for (x=0; x<src->sx; ++x) {
Packit ed3af9
			pxl = f (src, x, y);
Packit ed3af9
			r = gdImageRed(src, pxl);
Packit ed3af9
			g = gdImageGreen(src, pxl);
Packit ed3af9
			b = gdImageBlue(src, pxl);
Packit ed3af9
			a = gdImageAlpha(src, pxl);
Packit ed3af9
Packit ed3af9
			new_pxl = gdImageColorAllocateAlpha(src, 255-r, 255-g, 255-b, a);
Packit ed3af9
			if (new_pxl == -1) {
Packit ed3af9
				new_pxl = gdImageColorClosestAlpha(src, 255-r, 255-g, 255-b, a);
Packit ed3af9
			}
Packit ed3af9
			gdImageSetPixel (src, x, y, new_pxl);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageGrayScale
Packit ed3af9
 *
Packit ed3af9
 * Convert an image to grayscale
Packit ed3af9
 *
Packit ed3af9
 * The red, green and blue components of each pixel are replaced by their
Packit ed3af9
 * weighted sum using the same coefficients as the REC.601 luma (Y')
Packit ed3af9
 * calculation. The alpha components are retained.
Packit ed3af9
 *
Packit ed3af9
 * For palette images the result may differ due to palette limitations.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src - The image.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageGrayScale(gdImagePtr src)
Packit ed3af9
{
Packit ed3af9
	int x, y;
Packit ed3af9
	int r,g,b,a;
Packit ed3af9
	int new_pxl, pxl;
Packit ed3af9
	FuncPtr f;
Packit ed3af9
	int alpha_blending;
Packit ed3af9
Packit ed3af9
	if (src==NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	alpha_blending = src->alphaBlendingFlag;
Packit ed3af9
	gdImageAlphaBlending(src, gdEffectReplace);
Packit ed3af9
Packit ed3af9
	f = GET_PIXEL_FUNCTION(src);
Packit ed3af9
Packit ed3af9
	for (y=0; y<src->sy; ++y) {
Packit ed3af9
		for (x=0; x<src->sx; ++x) {
Packit ed3af9
			pxl = f (src, x, y);
Packit ed3af9
			r = gdImageRed(src, pxl);
Packit ed3af9
			g = gdImageGreen(src, pxl);
Packit ed3af9
			b = gdImageBlue(src, pxl);
Packit ed3af9
			a = gdImageAlpha(src, pxl);
Packit ed3af9
			r = g = b = (int) (.299 * r + .587 * g + .114 * b);
Packit ed3af9
Packit ed3af9
			new_pxl = gdImageColorAllocateAlpha(src, r, g, b, a);
Packit ed3af9
			if (new_pxl == -1) {
Packit ed3af9
				new_pxl = gdImageColorClosestAlpha(src, r, g, b, a);
Packit ed3af9
			}
Packit ed3af9
			gdImageSetPixel (src, x, y, new_pxl);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	gdImageAlphaBlending(src, alpha_blending);
Packit ed3af9
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageBrightness
Packit ed3af9
 *
Packit ed3af9
 * Change the brightness of an image
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src        - The image.
Packit ed3af9
 *   brightness - The value to add to the color channels of all pixels.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageContrast>
Packit ed3af9
 *   - <gdImageColor>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageBrightness(gdImagePtr src, int brightness)
Packit ed3af9
{
Packit ed3af9
	int x, y;
Packit ed3af9
	int r,g,b,a;
Packit ed3af9
	int new_pxl, pxl;
Packit ed3af9
	FuncPtr f;
Packit ed3af9
Packit ed3af9
	if (src==NULL || (brightness < -255 || brightness > 255)) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (brightness==0) {
Packit ed3af9
		return 1;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	f = GET_PIXEL_FUNCTION(src);
Packit ed3af9
Packit ed3af9
	for (y=0; y<src->sy; ++y) {
Packit ed3af9
		for (x=0; x<src->sx; ++x) {
Packit ed3af9
			pxl = f (src, x, y);
Packit ed3af9
Packit ed3af9
			r = gdImageRed(src, pxl);
Packit ed3af9
			g = gdImageGreen(src, pxl);
Packit ed3af9
			b = gdImageBlue(src, pxl);
Packit ed3af9
			a = gdImageAlpha(src, pxl);
Packit ed3af9
Packit ed3af9
			r = r + brightness;
Packit ed3af9
			g = g + brightness;
Packit ed3af9
			b = b + brightness;
Packit ed3af9
Packit ed3af9
			r = (r > 255)? 255 : ((r < 0)? 0:r);
Packit ed3af9
			g = (g > 255)? 255 : ((g < 0)? 0:g);
Packit ed3af9
			b = (b > 255)? 255 : ((b < 0)? 0:b);
Packit ed3af9
Packit ed3af9
			new_pxl = gdImageColorAllocateAlpha(src, (int)r, (int)g, (int)b, a);
Packit ed3af9
			if (new_pxl == -1) {
Packit ed3af9
				new_pxl = gdImageColorClosestAlpha(src, (int)r, (int)g, (int)b, a);
Packit ed3af9
			}
Packit ed3af9
			gdImageSetPixel (src, x, y, new_pxl);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageContrast
Packit ed3af9
 *
Packit ed3af9
 * Change the contrast of an image
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src      - The image.
Packit ed3af9
 *   contrast - The contrast adjustment value. Negative values increase, postive
Packit ed3af9
 *              values decrease the contrast. The larger the absolute value, the
Packit ed3af9
 *              stronger the effect.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageBrightness>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageContrast(gdImagePtr src, double contrast)
Packit ed3af9
{
Packit ed3af9
	int x, y;
Packit ed3af9
	int r,g,b,a;
Packit ed3af9
	double rf,gf,bf;
Packit ed3af9
	int new_pxl, pxl;
Packit ed3af9
Packit ed3af9
	FuncPtr f;
Packit ed3af9
Packit ed3af9
	if (src==NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	f = GET_PIXEL_FUNCTION(src);
Packit ed3af9
Packit ed3af9
	contrast = (double)(100.0-contrast)/100.0;
Packit ed3af9
	contrast = contrast*contrast;
Packit ed3af9
Packit ed3af9
	for (y=0; y<src->sy; ++y) {
Packit ed3af9
		for (x=0; x<src->sx; ++x) {
Packit ed3af9
			pxl = f(src, x, y);
Packit ed3af9
Packit ed3af9
			r = gdImageRed(src, pxl);
Packit ed3af9
			g = gdImageGreen(src, pxl);
Packit ed3af9
			b = gdImageBlue(src, pxl);
Packit ed3af9
			a = gdImageAlpha(src, pxl);
Packit ed3af9
Packit ed3af9
			rf = (double)r/255.0;
Packit ed3af9
			rf = rf-0.5;
Packit ed3af9
			rf = rf*contrast;
Packit ed3af9
			rf = rf+0.5;
Packit ed3af9
			rf = rf*255.0;
Packit ed3af9
Packit ed3af9
			bf = (double)b/255.0;
Packit ed3af9
			bf = bf-0.5;
Packit ed3af9
			bf = bf*contrast;
Packit ed3af9
			bf = bf+0.5;
Packit ed3af9
			bf = bf*255.0;
Packit ed3af9
Packit ed3af9
			gf = (double)g/255.0;
Packit ed3af9
			gf = gf-0.5;
Packit ed3af9
			gf = gf*contrast;
Packit ed3af9
			gf = gf+0.5;
Packit ed3af9
			gf = gf*255.0;
Packit ed3af9
Packit ed3af9
			rf = (rf > 255.0)? 255.0 : ((rf < 0.0)? 0.0:rf);
Packit ed3af9
			gf = (gf > 255.0)? 255.0 : ((gf < 0.0)? 0.0:gf);
Packit ed3af9
			bf = (bf > 255.0)? 255.0 : ((bf < 0.0)? 0.0:bf);
Packit ed3af9
Packit ed3af9
			new_pxl = gdImageColorAllocateAlpha(src, (int)rf, (int)gf, (int)bf, a);
Packit ed3af9
			if (new_pxl == -1) {
Packit ed3af9
				new_pxl = gdImageColorClosestAlpha(src, (int)rf, (int)gf, (int)bf, a);
Packit ed3af9
			}
Packit ed3af9
			gdImageSetPixel (src, x, y, new_pxl);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageColor
Packit ed3af9
 *
Packit ed3af9
 * Change channel values of an image
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src   - The image.
Packit ed3af9
 *   red   - The value to add to the red channel of all pixels.
Packit ed3af9
 *   green - The value to add to the green channel of all pixels.
Packit ed3af9
 *   blue  - The value to add to the blue channel of all pixels.
Packit ed3af9
 *   alpha - The value to add to the alpha channel of all pixels.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageBrightness>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageColor(gdImagePtr src, const int red, const int green, const int blue, const int alpha)
Packit ed3af9
{
Packit ed3af9
	int x, y;
Packit ed3af9
	int new_pxl, pxl;
Packit ed3af9
	FuncPtr f;
Packit ed3af9
Packit ed3af9
	if (src == NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	f = GET_PIXEL_FUNCTION(src);
Packit ed3af9
Packit ed3af9
	for (y=0; y<src->sy; ++y) {
Packit ed3af9
		for (x=0; x<src->sx; ++x) {
Packit ed3af9
			int r,g,b,a;
Packit ed3af9
Packit ed3af9
			pxl = f(src, x, y);
Packit ed3af9
			r = gdImageRed(src, pxl);
Packit ed3af9
			g = gdImageGreen(src, pxl);
Packit ed3af9
			b = gdImageBlue(src, pxl);
Packit ed3af9
			a = gdImageAlpha(src, pxl);
Packit ed3af9
Packit ed3af9
			r = r + red;
Packit ed3af9
			g = g + green;
Packit ed3af9
			b = b + blue;
Packit ed3af9
			a = a + alpha;
Packit ed3af9
Packit ed3af9
			r = (r > 255)? 255 : ((r < 0)? 0 : r);
Packit ed3af9
			g = (g > 255)? 255 : ((g < 0)? 0 : g);
Packit ed3af9
			b = (b > 255)? 255 : ((b < 0)? 0 : b);
Packit ed3af9
			a = (a > 127)? 127 : ((a < 0)? 0 : a);
Packit ed3af9
Packit ed3af9
			new_pxl = gdImageColorAllocateAlpha(src, r, g, b, a);
Packit ed3af9
			if (new_pxl == -1) {
Packit ed3af9
				new_pxl = gdImageColorClosestAlpha(src, r, g, b, a);
Packit ed3af9
			}
Packit ed3af9
			gdImageSetPixel (src, x, y, new_pxl);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageConvolution
Packit ed3af9
 *
Packit ed3af9
 * Apply a convolution matrix to an image
Packit ed3af9
 *
Packit ed3af9
 * Depending on the matrix a wide range of effects can be accomplished, e.g.
Packit ed3af9
 * blurring, sharpening, embossing and edge detection.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src        - The image.
Packit ed3af9
 *   filter     - The 3x3 convolution matrix.
Packit ed3af9
 *   filter_div - The value to divide the convoluted channel values by.
Packit ed3af9
 *   offset     - The value to add to the convoluted channel values.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageEdgeDetectQuick>
Packit ed3af9
 *   - <gdImageGaussianBlur>
Packit ed3af9
 *   - <gdImageEmboss>
Packit ed3af9
 *   - <gdImageMeanRemoval>
Packit ed3af9
 *   - <gdImageSmooth>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageConvolution(gdImagePtr src, float filter[3][3], float filter_div, float offset)
Packit ed3af9
{
Packit ed3af9
	int         x, y, i, j, new_a;
Packit ed3af9
	float       new_r, new_g, new_b;
Packit ed3af9
	int         new_pxl, pxl=0;
Packit ed3af9
	gdImagePtr  srcback;
Packit ed3af9
	FuncPtr f;
Packit ed3af9
Packit ed3af9
	if (src==NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* We need the orinal image with each safe neoghb. pixel */
Packit ed3af9
	srcback = gdImageCreateTrueColor (src->sx, src->sy);
Packit ed3af9
	if (srcback==NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	gdImageSaveAlpha(srcback, 1);
Packit ed3af9
	new_pxl = gdImageColorAllocateAlpha(srcback, 0, 0, 0, 127);
Packit ed3af9
	gdImageFill(srcback, 0, 0, new_pxl);
Packit ed3af9
Packit ed3af9
	gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);
Packit ed3af9
Packit ed3af9
	f = GET_PIXEL_FUNCTION(src);
Packit ed3af9
Packit ed3af9
	for ( y=0; y<src->sy; y++) {
Packit ed3af9
		for(x=0; x<src->sx; x++) {
Packit ed3af9
			new_r = new_g = new_b = 0;
Packit ed3af9
			new_a = gdImageAlpha(srcback, pxl);
Packit ed3af9
Packit ed3af9
			for (j=0; j<3; j++) {
Packit ed3af9
				int yv = MIN(MAX(y - 1 + j, 0), src->sy - 1);
Packit ed3af9
				for (i=0; i<3; i++) {
Packit ed3af9
				        pxl = f(srcback, MIN(MAX(x - 1 + i, 0), src->sx - 1), yv);
Packit ed3af9
					new_r += (float)gdImageRed(srcback, pxl) * filter[j][i];
Packit ed3af9
					new_g += (float)gdImageGreen(srcback, pxl) * filter[j][i];
Packit ed3af9
					new_b += (float)gdImageBlue(srcback, pxl) * filter[j][i];
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			new_r = (new_r/filter_div)+offset;
Packit ed3af9
			new_g = (new_g/filter_div)+offset;
Packit ed3af9
			new_b = (new_b/filter_div)+offset;
Packit ed3af9
Packit ed3af9
			new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
Packit ed3af9
			new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
Packit ed3af9
			new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
Packit ed3af9
Packit ed3af9
			new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
Packit ed3af9
			if (new_pxl == -1) {
Packit ed3af9
				new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
Packit ed3af9
			}
Packit ed3af9
			gdImageSetPixel (src, x, y, new_pxl);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	gdImageDestroy(srcback);
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdImageSelectiveBlur
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageSelectiveBlur( gdImagePtr src)
Packit ed3af9
{
Packit ed3af9
	int         x, y, i, j;
Packit ed3af9
	float       new_r, new_g, new_b;
Packit ed3af9
	int         new_pxl, cpxl, pxl, new_a=0;
Packit ed3af9
	float flt_r [3][3];
Packit ed3af9
	float flt_g [3][3];
Packit ed3af9
	float flt_b [3][3];
Packit ed3af9
	float flt_r_sum, flt_g_sum, flt_b_sum;
Packit ed3af9
Packit ed3af9
	gdImagePtr srcback;
Packit ed3af9
	FuncPtr f;
Packit ed3af9
Packit ed3af9
	if (src==NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* We need the orinal image with each safe neoghb. pixel */
Packit ed3af9
	srcback = gdImageCreateTrueColor (src->sx, src->sy);
Packit ed3af9
	if (srcback==NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
	gdImageCopy(srcback, src,0,0,0,0,src->sx,src->sy);
Packit ed3af9
Packit ed3af9
	f = GET_PIXEL_FUNCTION(src);
Packit ed3af9
Packit ed3af9
	for(y = 0; y<src->sy; y++) {
Packit ed3af9
		for (x=0; x<src->sx; x++) {
Packit ed3af9
		      flt_r_sum = flt_g_sum = flt_b_sum = 0.0;
Packit ed3af9
			cpxl = f(src, x, y);
Packit ed3af9
Packit ed3af9
			for (j=0; j<3; j++) {
Packit ed3af9
				for (i=0; i<3; i++) {
Packit ed3af9
					if ((j == 1) && (i == 1)) {
Packit ed3af9
						flt_r[1][1] = flt_g[1][1] = flt_b[1][1] = 0.5;
Packit ed3af9
					} else {
Packit ed3af9
						pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
Packit ed3af9
						new_a = gdImageAlpha(srcback, pxl);
Packit ed3af9
Packit ed3af9
						new_r = ((float)gdImageRed(srcback, cpxl)) - ((float)gdImageRed (srcback, pxl));
Packit ed3af9
Packit ed3af9
						if (new_r < 0.0f) {
Packit ed3af9
							new_r = -new_r;
Packit ed3af9
						}
Packit ed3af9
						if (new_r != 0) {
Packit ed3af9
							flt_r[j][i] = 1.0f/new_r;
Packit ed3af9
						} else {
Packit ed3af9
							flt_r[j][i] = 1.0f;
Packit ed3af9
						}
Packit ed3af9
Packit ed3af9
						new_g = ((float)gdImageGreen(srcback, cpxl)) - ((float)gdImageGreen(srcback, pxl));
Packit ed3af9
Packit ed3af9
						if (new_g < 0.0f) {
Packit ed3af9
							new_g = -new_g;
Packit ed3af9
						}
Packit ed3af9
						if (new_g != 0) {
Packit ed3af9
							flt_g[j][i] = 1.0f/new_g;
Packit ed3af9
						} else {
Packit ed3af9
							flt_g[j][i] = 1.0f;
Packit ed3af9
						}
Packit ed3af9
Packit ed3af9
						new_b = ((float)gdImageBlue(srcback, cpxl)) - ((float)gdImageBlue(srcback, pxl));
Packit ed3af9
Packit ed3af9
						if (new_b < 0.0f) {
Packit ed3af9
							new_b = -new_b;
Packit ed3af9
						}
Packit ed3af9
						if (new_b != 0) {
Packit ed3af9
							flt_b[j][i] = 1.0f/new_b;
Packit ed3af9
						} else {
Packit ed3af9
							flt_b[j][i] = 1.0f;
Packit ed3af9
						}
Packit ed3af9
					}
Packit ed3af9
Packit ed3af9
					flt_r_sum += flt_r[j][i];
Packit ed3af9
					flt_g_sum += flt_g[j][i];
Packit ed3af9
					flt_b_sum += flt_b [j][i];
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			for (j=0; j<3; j++) {
Packit ed3af9
				for (i=0; i<3; i++) {
Packit ed3af9
					if (flt_r_sum != 0.0) {
Packit ed3af9
						flt_r[j][i] /= flt_r_sum;
Packit ed3af9
					}
Packit ed3af9
					if (flt_g_sum != 0.0) {
Packit ed3af9
						flt_g[j][i] /= flt_g_sum;
Packit ed3af9
					}
Packit ed3af9
					if (flt_b_sum != 0.0) {
Packit ed3af9
						flt_b [j][i] /= flt_b_sum;
Packit ed3af9
					}
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			new_r = new_g = new_b = 0.0;
Packit ed3af9
Packit ed3af9
			for (j=0; j<3; j++) {
Packit ed3af9
				for (i=0; i<3; i++) {
Packit ed3af9
					pxl = f(src, x-(3>>1)+i, y-(3>>1)+j);
Packit ed3af9
					new_r += (float)gdImageRed(srcback, pxl) * flt_r[j][i];
Packit ed3af9
					new_g += (float)gdImageGreen(srcback, pxl) * flt_g[j][i];
Packit ed3af9
					new_b += (float)gdImageBlue(srcback, pxl) * flt_b[j][i];
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			new_r = (new_r > 255.0f)? 255.0f : ((new_r < 0.0f)? 0.0f:new_r);
Packit ed3af9
			new_g = (new_g > 255.0f)? 255.0f : ((new_g < 0.0f)? 0.0f:new_g);
Packit ed3af9
			new_b = (new_b > 255.0f)? 255.0f : ((new_b < 0.0f)? 0.0f:new_b);
Packit ed3af9
			new_pxl = gdImageColorAllocateAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
Packit ed3af9
			if (new_pxl == -1) {
Packit ed3af9
				new_pxl = gdImageColorClosestAlpha(src, (int)new_r, (int)new_g, (int)new_b, new_a);
Packit ed3af9
			}
Packit ed3af9
			gdImageSetPixel (src, x, y, new_pxl);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	gdImageDestroy(srcback);
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageEdgeDetectQuick
Packit ed3af9
 *
Packit ed3af9
 * Edge detection of an image
Packit ed3af9
 *
Packit ed3af9
 * (see edge_detect_quick.jpg)
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src - The image.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageMeanRemoval>
Packit ed3af9
 *   - <gdImageConvolution>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageEdgeDetectQuick(gdImagePtr src)
Packit ed3af9
{
Packit ed3af9
	float filter[3][3] =	{{-1.0,0.0,-1.0},
Packit ed3af9
				{0.0,4.0,0.0},
Packit ed3af9
				{-1.0,0.0,-1.0}};
Packit ed3af9
Packit ed3af9
	return gdImageConvolution(src, filter, 1, 127);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageGaussianBlur
Packit ed3af9
Packit ed3af9
    <gdImageGaussianBlur> performs a Gaussian blur of radius 1 on the
Packit ed3af9
    image.  The image is modified in place.
Packit ed3af9
Packit ed3af9
    *NOTE:* You will almost certain want to use
Packit ed3af9
    <gdImageCopyGaussianBlurred> instead, as it allows you to change
Packit ed3af9
    your kernel size and sigma value.  Future versions of this
Packit ed3af9
    function may fall back to calling it instead of
Packit ed3af9
    <gdImageConvolution>, causing subtle changes so be warned.
Packit ed3af9
Packit ed3af9
  Parameters:
Packit ed3af9
    im  - The image to blur
Packit ed3af9
Packit ed3af9
  Returns:
Packit ed3af9
    GD_TRUE (1) on success, GD_FALSE (0) on failure.
Packit ed3af9
Packit ed3af9
*/
Packit ed3af9
Packit ed3af9
BGD_DECLARE(int) gdImageGaussianBlur(gdImagePtr im)
Packit ed3af9
{
Packit ed3af9
	float filter[3][3] = {
Packit ed3af9
        {1.0, 2.0, 1.0},
Packit ed3af9
        {2.0, 4.0, 2.0},
Packit ed3af9
        {1.0, 2.0, 1.0}
Packit ed3af9
    };
Packit ed3af9
Packit ed3af9
	return gdImageConvolution(im, filter, 16, 0);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageEmboss
Packit ed3af9
 *
Packit ed3af9
 * Emboss an image
Packit ed3af9
 *
Packit ed3af9
 * (see emboss.jpg)
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   im - The image.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageConvolution>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageEmboss(gdImagePtr im)
Packit ed3af9
{
Packit ed3af9
/*
Packit ed3af9
	float filter[3][3] =	{{1.0,1.0,1.0},
Packit ed3af9
				{0.0,0.0,0.0},
Packit ed3af9
				{-1.0,-1.0,-1.0}};
Packit ed3af9
*/
Packit ed3af9
	float filter[3][3] =	{{ 1.5, 0.0, 0.0},
Packit ed3af9
				 { 0.0, 0.0, 0.0},
Packit ed3af9
				 { 0.0, 0.0,-1.5}};
Packit ed3af9
Packit ed3af9
	return gdImageConvolution(im, filter, 1, 127);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageMeanRemoval
Packit ed3af9
 *
Packit ed3af9
 * Mean removal of an image
Packit ed3af9
 *
Packit ed3af9
 * (see mean_removal.jpg)
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   im - The image.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageEdgeDetectQuick>
Packit ed3af9
 *   - <gdImageConvolution>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageMeanRemoval(gdImagePtr im)
Packit ed3af9
{
Packit ed3af9
	float filter[3][3] =	{{-1.0,-1.0,-1.0},
Packit ed3af9
				{-1.0,9.0,-1.0},
Packit ed3af9
				{-1.0,-1.0,-1.0}};
Packit ed3af9
Packit ed3af9
	return gdImageConvolution(im, filter, 1, 0);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageSmooth
Packit ed3af9
 *
Packit ed3af9
 * Smooth an image
Packit ed3af9
 *
Packit ed3af9
 * (see smooth.jpg)
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   im     - The image.
Packit ed3af9
 *   weight - The strength of the smoothing.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageConvolution>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageSmooth(gdImagePtr im, float weight)
Packit ed3af9
{
Packit ed3af9
	float filter[3][3] =	{{1.0,1.0,1.0},
Packit ed3af9
				{1.0,0.0,1.0},
Packit ed3af9
				{1.0,1.0,1.0}};
Packit ed3af9
Packit ed3af9
	filter[1][1] = weight;
Packit ed3af9
Packit ed3af9
	return gdImageConvolution(im, filter, weight+8, 0);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
/* ======================== Gaussian Blur Code ======================== */
Packit ed3af9
Packit ed3af9
/* Return an array of coefficients for 'radius' and 'sigma' (sigma >=
Packit ed3af9
 * 0 means compute it).  Result length is 2*radius+1. */
Packit ed3af9
static double *
Packit ed3af9
gaussian_coeffs(int radius, double sigmaArg) {
Packit ed3af9
    const double sigma = (sigmaArg <= 0.0) ? (2.0/3.0)*radius : sigmaArg;
Packit ed3af9
    const double s = 2.0 * sigma * sigma;
Packit ed3af9
    double *result;
Packit ed3af9
    double sum = 0;
Packit ed3af9
    int x, n, count;
Packit ed3af9
Packit ed3af9
    count = 2*radius + 1;
Packit ed3af9
Packit ed3af9
    result = gdMalloc(sizeof(double) * count);
Packit ed3af9
    if (!result) {
Packit ed3af9
        return NULL;
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
    for (x = -radius; x <= radius; x++) {
Packit ed3af9
        double coeff = exp(-(x*x)/s);
Packit ed3af9
Packit ed3af9
        sum += coeff;
Packit ed3af9
        result[x + radius] = coeff;
Packit ed3af9
    }/* for */
Packit ed3af9
Packit ed3af9
    for (n = 0; n < count; n++) {
Packit ed3af9
        result[n] /= sum;
Packit ed3af9
    }/* for */
Packit ed3af9
Packit ed3af9
    return result;
Packit ed3af9
}/* gaussian_coeffs*/
Packit ed3af9
Packit ed3af9
Packit ed3af9
Packit ed3af9
static inline int
Packit ed3af9
reflect(int max, int x)
Packit ed3af9
{
Packit ed3af9
    assert(x > -max && x < 2*max);
Packit ed3af9
Packit ed3af9
    if(x < 0) return -x;
Packit ed3af9
    if(x >= max) return max - (x - max) - 1;
Packit ed3af9
    return x;
Packit ed3af9
}/* reflect*/
Packit ed3af9
Packit ed3af9
Packit ed3af9
Packit ed3af9
static inline void
Packit ed3af9
applyCoeffsLine(gdImagePtr src, gdImagePtr dst, int line, int linelen,
Packit ed3af9
                double *coeffs, int radius, gdAxis axis)
Packit ed3af9
{
Packit ed3af9
    int ndx;
Packit ed3af9
Packit ed3af9
    for (ndx = 0; ndx < linelen; ndx++) {
Packit ed3af9
        double r = 0, g = 0, b = 0, a = 0;
Packit ed3af9
        int cndx;
Packit ed3af9
        int *dest = (axis == HORIZONTAL) ?
Packit ed3af9
            &dst->tpixels[line][ndx] :
Packit ed3af9
            &dst->tpixels[ndx][line];
Packit ed3af9
Packit ed3af9
        for (cndx = -radius; cndx <= radius; cndx++) {
Packit ed3af9
            const double coeff = coeffs[cndx + radius];
Packit ed3af9
            const int rndx = reflect(linelen, ndx + cndx);
Packit ed3af9
Packit ed3af9
            const int srcpx = (axis == HORIZONTAL) ?
Packit ed3af9
                src->tpixels[line][rndx] :
Packit ed3af9
                src->tpixels[rndx][line];
Packit ed3af9
                
Packit ed3af9
            r += coeff * (double)gdTrueColorGetRed(srcpx);
Packit ed3af9
            g += coeff * (double)gdTrueColorGetGreen(srcpx);
Packit ed3af9
            b += coeff * (double)gdTrueColorGetBlue(srcpx);
Packit ed3af9
            a += coeff * (double)gdTrueColorGetAlpha(srcpx);
Packit ed3af9
        }/* for */
Packit ed3af9
Packit ed3af9
		*dest = gdTrueColorAlpha(uchar_clamp(r, 0xFF), uchar_clamp(g, 0xFF),
Packit ed3af9
                                 uchar_clamp(b, 0xFF), uchar_clamp(a, 0x7F));
Packit ed3af9
    }/* for */
Packit ed3af9
}/* applyCoeffsLine*/
Packit ed3af9
Packit ed3af9
Packit ed3af9
static void
Packit ed3af9
applyCoeffs(gdImagePtr src, gdImagePtr dst, double *coeffs, int radius, 
Packit ed3af9
            gdAxis axis)
Packit ed3af9
{
Packit ed3af9
    int line, numlines, linelen;
Packit ed3af9
Packit ed3af9
    if (axis == HORIZONTAL) {
Packit ed3af9
        numlines = src->sy;
Packit ed3af9
        linelen = src->sx;
Packit ed3af9
    } else {
Packit ed3af9
        numlines = src->sx;
Packit ed3af9
        linelen = src->sy;
Packit ed3af9
    }/* if .. else*/
Packit ed3af9
Packit ed3af9
    for (line = 0; line < numlines; line++) {
Packit ed3af9
        applyCoeffsLine(src, dst, line, linelen, coeffs, radius, axis);
Packit ed3af9
    }/* for */
Packit ed3af9
}/* applyCoeffs*/
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCopyGaussianBlurred
Packit ed3af9
Packit ed3af9
    Return a copy of the source image _src_ blurred according to the
Packit ed3af9
    parameters using the Gaussian Blur algorithm.
Packit ed3af9
Packit ed3af9
    _radius_ is a radius, not a diameter so a radius of 2 (for
Packit ed3af9
    example) will blur across a region 5 pixels across (2 to the
Packit ed3af9
    center, 1 for the center itself and another 2 to the other edge).
Packit ed3af9
    
Packit ed3af9
    _sigma_ represents the "fatness" of the curve (lower == fatter).
Packit ed3af9
    If _sigma_ is less than or equal to 0,
Packit ed3af9
    <gdImageCopyGaussianBlurred> ignores it and instead computes an
Packit ed3af9
    "optimal" value.  Be warned that future versions of this function
Packit ed3af9
    may compute sigma differently.
Packit ed3af9
Packit ed3af9
    The resulting image is always truecolor.
Packit ed3af9
Packit ed3af9
  More Details:
Packit ed3af9
Packit ed3af9
    A Gaussian Blur is generated by replacing each pixel's color
Packit ed3af9
    values with the average of the surrounding pixels' colors.  This
Packit ed3af9
    region is a circle whose radius is given by argument _radius_.
Packit ed3af9
    Thus, a larger radius will yield a blurrier image.
Packit ed3af9
Packit ed3af9
    This average is not a simple mean of the values.  Instead, values
Packit ed3af9
    are weighted using the Gaussian function (roughly a bell curve
Packit ed3af9
    centered around the destination pixel) giving it much more
Packit ed3af9
    influence on the result than its neighbours.  Thus, a fatter curve
Packit ed3af9
    will give the center pixel more weight and make the image less
Packit ed3af9
    blurry; lower _sigma_ values will yield flatter curves.
Packit ed3af9
Packit ed3af9
    Currently, <gdImageCopyGaussianBlurred> computes the default sigma
Packit ed3af9
    as
Packit ed3af9
Packit ed3af9
        (2/3)*radius
Packit ed3af9
Packit ed3af9
    Note, however that we reserve the right to change this if we find
Packit ed3af9
    a better ratio.  If you absolutely need the current sigma value,
Packit ed3af9
    you should set it yourself.
Packit ed3af9
Packit ed3af9
  Parameters:
Packit ed3af9
Packit ed3af9
    src     - the source image
Packit ed3af9
    radius  - the blur radius (*not* diameter--range is 2*radius + 1)
Packit ed3af9
    sigma   - the sigma value or a value <= 0.0 to use the computed default
Packit ed3af9
Packit ed3af9
  Returns:
Packit ed3af9
Packit ed3af9
    The new image or NULL if an error occurred.  The result is always
Packit ed3af9
    truecolor.
Packit ed3af9
Packit ed3af9
  Example:
Packit ed3af9
    (start code)
Packit ed3af9
Packit ed3af9
    FILE *in;
Packit ed3af9
    gdImagePtr result, src;
Packit ed3af9
     
Packit ed3af9
    in = fopen("foo.png", "rb");
Packit ed3af9
    src = gdImageCreateFromPng(in);
Packit ed3af9
    
Packit ed3af9
    result = gdImageCopyGaussianBlurred(im, src->sx / 10, -1.0);
Packit ed3af9
Packit ed3af9
    (end code)
Packit ed3af9
*/
Packit ed3af9
Packit ed3af9
/* TODO: Look into turning this into a generic seperable filter
Packit ed3af9
 * function with Gaussian Blur being one special case.  (At the
Packit ed3af9
 * moment, I can't find any other useful separable filter so for not,
Packit ed3af9
 * it's just blur.) */
Packit ed3af9
BGD_DECLARE(gdImagePtr)
Packit ed3af9
gdImageCopyGaussianBlurred(gdImagePtr src, int radius, double sigma)
Packit ed3af9
{
Packit ed3af9
    gdImagePtr tmp = NULL, result = NULL;
Packit ed3af9
    double *coeffs;
Packit ed3af9
    int freeSrc = 0;
Packit ed3af9
Packit ed3af9
    if (radius < 1) {
Packit ed3af9
        return NULL;
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
    /* Compute the coefficients. */
Packit ed3af9
    coeffs = gaussian_coeffs(radius, sigma);
Packit ed3af9
    if (!coeffs) {
Packit ed3af9
        return NULL;
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
    /* If the image is not truecolor, we first make a truecolor
Packit ed3af9
     * scratch copy. */
Packit ed3af9
	if (!src->trueColor) {
Packit ed3af9
        int tcstat;
Packit ed3af9
Packit ed3af9
        src = gdImageClone(src);
Packit ed3af9
        if (!src) {
Packit ed3af9
			gdFree(coeffs);
Packit ed3af9
			return NULL;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
        tcstat = gdImagePaletteToTrueColor(src);
Packit ed3af9
        if (!tcstat) {
Packit ed3af9
            gdImageDestroy(src);
Packit ed3af9
			gdFree(coeffs);
Packit ed3af9
            return NULL;
Packit ed3af9
        }/* if */
Packit ed3af9
		
Packit ed3af9
        freeSrc = 1;
Packit ed3af9
	}/* if */
Packit ed3af9
Packit ed3af9
    /* Apply the filter horizontally. */
Packit ed3af9
    tmp = gdImageCreateTrueColor(src->sx, src->sy);
Packit ed3af9
    if (!tmp) {
Packit ed3af9
		gdFree(coeffs);
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
    applyCoeffs(src, tmp, coeffs, radius, HORIZONTAL);
Packit ed3af9
Packit ed3af9
    /* Apply the filter vertically. */
Packit ed3af9
    result = gdImageCreateTrueColor(src->sx, src->sy);
Packit ed3af9
    if (result) {
Packit ed3af9
        applyCoeffs(tmp, result, coeffs, radius, VERTICAL);
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
    gdImageDestroy(tmp);
Packit ed3af9
    gdFree(coeffs);
Packit ed3af9
Packit ed3af9
    if (freeSrc) gdImageDestroy(src);
Packit ed3af9
Packit ed3af9
    return result;
Packit ed3af9
}/* gdImageCopyGaussianBlurred*/
Packit ed3af9