Blame src/gd_interpolation.c

Packit ed3af9
/*
Packit ed3af9
 * The two pass scaling function is based on:
Packit ed3af9
 * Filtered Image Rescaling
Packit ed3af9
 * Based on Gems III
Packit ed3af9
 *  - Schumacher general filtered image rescaling
Packit ed3af9
 * (pp. 414-424)
Packit ed3af9
 * by Dale Schumacher
Packit ed3af9
 *
Packit ed3af9
 * 	Additional changes by Ray Gardener, Daylon Graphics Ltd.
Packit ed3af9
 * 	December 4, 1999
Packit ed3af9
 *
Packit ed3af9
 * 	Ported to libgd by Pierre Joye. Support for multiple channels
Packit ed3af9
 * 	added (argb for now).
Packit ed3af9
 *
Packit ed3af9
 * 	Initial sources code is avaibable in the Gems Source Code Packages:
Packit ed3af9
 * 	http://www.acm.org/pubs/tog/GraphicsGems/GGemsIII.tar.gz
Packit ed3af9
 *
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Summary:
Packit ed3af9
Packit ed3af9
		- Horizontal filter contributions are calculated on the fly,
Packit ed3af9
		  as each column is mapped from src to dst image. This lets
Packit ed3af9
		  us omit having to allocate a temporary full horizontal stretch
Packit ed3af9
		  of the src image.
Packit ed3af9
Packit ed3af9
		- If none of the src pixels within a sampling region differ,
Packit ed3af9
		  then the output pixel is forced to equal (any of) the source pixel.
Packit ed3af9
		  This ensures that filters do not corrupt areas of constant color.
Packit ed3af9
Packit ed3af9
		- Filter weight contribution results, after summing, are
Packit ed3af9
		  rounded to the nearest pixel color value instead of
Packit ed3af9
		  being casted to ILubyte (usually an int or char). Otherwise,
Packit ed3af9
		  artifacting occurs.
Packit ed3af9
Packit ed3af9
*/
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Additional functions are available for simple rotation or up/downscaling.
Packit ed3af9
	downscaling using the fixed point implementations are usually much faster
Packit ed3af9
	than the existing gdImageCopyResampled while having a similar or better
Packit ed3af9
	quality.
Packit ed3af9
	
Packit ed3af9
	For image rotations, the optimized versions have a lazy antialiasing for 
Packit ed3af9
	the edges of the images. For a much better antialiased result, the affine
Packit ed3af9
	function is recommended.
Packit ed3af9
*/
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
TODO:
Packit ed3af9
 - Optimize pixel accesses and loops once we have continuous buffer
Packit ed3af9
 - Add scale support for a portion only of an image (equivalent of copyresized/resampled)
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#ifdef HAVE_CONFIG_H
Packit ed3af9
#include "config.h"
Packit ed3af9
#endif /* HAVE_CONFIG_H */
Packit ed3af9
Packit ed3af9
#include <stdio.h>
Packit ed3af9
#include <stdlib.h>
Packit ed3af9
#include <string.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
#include "gd.h"
Packit ed3af9
#include "gdhelpers.h"
Packit ed3af9
#include "gd_intern.h"
Packit ed3af9
Packit ed3af9
#ifdef _MSC_VER
Packit ed3af9
# pragma optimize("t", on)
Packit ed3af9
# include <emmintrin.h>
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static gdImagePtr gdImageScaleBilinear(gdImagePtr im, 
Packit ed3af9
                                       const unsigned int new_width,
Packit ed3af9
                                       const unsigned int new_height);
Packit ed3af9
static gdImagePtr gdImageScaleBicubicFixed(gdImagePtr src,
Packit ed3af9
                                           const unsigned int width,
Packit ed3af9
                                           const unsigned int height);
Packit ed3af9
static gdImagePtr gdImageScaleNearestNeighbour(gdImagePtr im,
Packit ed3af9
                                               const unsigned int width,
Packit ed3af9
                                               const unsigned int height);
Packit ed3af9
static gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src,
Packit ed3af9
                                                const float degrees,
Packit ed3af9
                                                const int bgColor);
Packit ed3af9
static gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees,
Packit ed3af9
                                       const int bgColor);
Packit ed3af9
Packit ed3af9
Packit ed3af9
#define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
Packit ed3af9
Packit ed3af9
/* only used here, let do a generic fixed point integers later if required by other
Packit ed3af9
   part of GD */
Packit ed3af9
typedef long gdFixed;
Packit ed3af9
/* Integer to fixed point */
Packit ed3af9
#define gd_itofx(x) ((x) << 8)
Packit ed3af9
Packit ed3af9
/* Float to fixed point */
Packit ed3af9
#define gd_ftofx(x) (long)((x) * 256)
Packit ed3af9
Packit ed3af9
/*  Double to fixed point */
Packit ed3af9
#define gd_dtofx(x) (long)((x) * 256)
Packit ed3af9
Packit ed3af9
/* Fixed point to integer */
Packit ed3af9
#define gd_fxtoi(x) ((x) >> 8)
Packit ed3af9
Packit ed3af9
/* Fixed point to float */
Packit ed3af9
# define gd_fxtof(x) ((float)(x) / 256)
Packit ed3af9
Packit ed3af9
/* Fixed point to double */
Packit ed3af9
#define gd_fxtod(x) ((double)(x) / 256)
Packit ed3af9
Packit ed3af9
/* Multiply a fixed by a fixed */
Packit ed3af9
#define gd_mulfx(x,y) (((x) * (y)) >> 8)
Packit ed3af9
Packit ed3af9
/* Divide a fixed by a fixed */
Packit ed3af9
#define gd_divfx(x,y) (((x) << 8) / (y))
Packit ed3af9
Packit ed3af9
typedef struct
Packit ed3af9
{
Packit ed3af9
	double *Weights;  /* Normalized weights of neighboring pixels */
Packit ed3af9
	int Left,Right;   /* Bounds of source pixels window */
Packit ed3af9
} ContributionType;  /* Contirbution information for a single pixel */
Packit ed3af9
Packit ed3af9
typedef struct
Packit ed3af9
{
Packit ed3af9
	ContributionType *ContribRow; /* Row (or column) of contribution weights */
Packit ed3af9
	unsigned int WindowSize,      /* Filter window size (of affecting source pixels) */
Packit ed3af9
		     LineLength;      /* Length of line (no. or rows / cols) */
Packit ed3af9
} LineContribType;
Packit ed3af9
Packit ed3af9
/* Each core filter has its own radius */
Packit ed3af9
#define DEFAULT_FILTER_LINEAR               1.0f
Packit ed3af9
#define DEFAULT_FILTER_BICUBIC				3.0f
Packit ed3af9
#define DEFAULT_FILTER_BOX					0.5f
Packit ed3af9
#define DEFAULT_FILTER_GENERALIZED_CUBIC	0.5f
Packit ed3af9
#define DEFAULT_FILTER_RADIUS				1.0f
Packit ed3af9
#define DEFAULT_LANCZOS8_RADIUS				8.0f
Packit ed3af9
#define DEFAULT_LANCZOS3_RADIUS				3.0f
Packit ed3af9
#define DEFAULT_HERMITE_RADIUS				1.0f
Packit ed3af9
#define DEFAULT_BOX_RADIUS					0.5f
Packit ed3af9
#define DEFAULT_TRIANGLE_RADIUS				1.0f
Packit ed3af9
#define DEFAULT_BELL_RADIUS					1.5f
Packit ed3af9
#define DEFAULT_CUBICSPLINE_RADIUS			2.0f
Packit ed3af9
#define DEFAULT_MITCHELL_RADIUS				2.0f
Packit ed3af9
#define DEFAULT_COSINE_RADIUS				1.0f
Packit ed3af9
#define DEFAULT_CATMULLROM_RADIUS			2.0f
Packit ed3af9
#define DEFAULT_QUADRATIC_RADIUS			1.5f
Packit ed3af9
#define DEFAULT_QUADRATICBSPLINE_RADIUS		1.5f
Packit ed3af9
#define DEFAULT_CUBICCONVOLUTION_RADIUS		3.0f
Packit ed3af9
#define DEFAULT_GAUSSIAN_RADIUS				1.0f
Packit ed3af9
#define DEFAULT_HANNING_RADIUS				1.0f
Packit ed3af9
#define DEFAULT_HAMMING_RADIUS				1.0f
Packit ed3af9
#define DEFAULT_SINC_RADIUS					1.0f
Packit ed3af9
#define DEFAULT_WELSH_RADIUS				1.0f
Packit ed3af9
Packit ed3af9
static double KernelBessel_J1(const double x)
Packit ed3af9
{
Packit ed3af9
	double p, q;
Packit ed3af9
Packit ed3af9
	register long i;
Packit ed3af9
Packit ed3af9
	static const double
Packit ed3af9
	Pone[] =
Packit ed3af9
	{
Packit ed3af9
		0.581199354001606143928050809e+21,
Packit ed3af9
		-0.6672106568924916298020941484e+20,
Packit ed3af9
		0.2316433580634002297931815435e+19,
Packit ed3af9
		-0.3588817569910106050743641413e+17,
Packit ed3af9
		0.2908795263834775409737601689e+15,
Packit ed3af9
		-0.1322983480332126453125473247e+13,
Packit ed3af9
		0.3413234182301700539091292655e+10,
Packit ed3af9
		-0.4695753530642995859767162166e+7,
Packit ed3af9
		0.270112271089232341485679099e+4
Packit ed3af9
	},
Packit ed3af9
	Qone[] =
Packit ed3af9
	{
Packit ed3af9
		0.11623987080032122878585294e+22,
Packit ed3af9
		0.1185770712190320999837113348e+20,
Packit ed3af9
		0.6092061398917521746105196863e+17,
Packit ed3af9
		0.2081661221307607351240184229e+15,
Packit ed3af9
		0.5243710262167649715406728642e+12,
Packit ed3af9
		0.1013863514358673989967045588e+10,
Packit ed3af9
		0.1501793594998585505921097578e+7,
Packit ed3af9
		0.1606931573481487801970916749e+4,
Packit ed3af9
		0.1e+1
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	p = Pone[8];
Packit ed3af9
	q = Qone[8];
Packit ed3af9
	for (i=7; i >= 0; i--)
Packit ed3af9
	{
Packit ed3af9
		p = p*x*x+Pone[i];
Packit ed3af9
		q = q*x*x+Qone[i];
Packit ed3af9
	}
Packit ed3af9
	return (double)(p/q);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double KernelBessel_P1(const double x)
Packit ed3af9
{
Packit ed3af9
	double p, q;
Packit ed3af9
Packit ed3af9
	register long i;
Packit ed3af9
Packit ed3af9
	static const double
Packit ed3af9
	Pone[] =
Packit ed3af9
	{
Packit ed3af9
		0.352246649133679798341724373e+5,
Packit ed3af9
		0.62758845247161281269005675e+5,
Packit ed3af9
		0.313539631109159574238669888e+5,
Packit ed3af9
		0.49854832060594338434500455e+4,
Packit ed3af9
		0.2111529182853962382105718e+3,
Packit ed3af9
		0.12571716929145341558495e+1
Packit ed3af9
	},
Packit ed3af9
	Qone[] =
Packit ed3af9
	{
Packit ed3af9
		0.352246649133679798068390431e+5,
Packit ed3af9
		0.626943469593560511888833731e+5,
Packit ed3af9
		0.312404063819041039923015703e+5,
Packit ed3af9
		0.4930396490181088979386097e+4,
Packit ed3af9
		0.2030775189134759322293574e+3,
Packit ed3af9
		0.1e+1
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	p = Pone[5];
Packit ed3af9
	q = Qone[5];
Packit ed3af9
	for (i=4; i >= 0; i--)
Packit ed3af9
	{
Packit ed3af9
		p = p*(8.0/x)*(8.0/x)+Pone[i];
Packit ed3af9
		q = q*(8.0/x)*(8.0/x)+Qone[i];
Packit ed3af9
	}
Packit ed3af9
	return (double)(p/q);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double KernelBessel_Q1(const double x)
Packit ed3af9
{
Packit ed3af9
	double p, q;
Packit ed3af9
Packit ed3af9
	register long i;
Packit ed3af9
Packit ed3af9
	static const double
Packit ed3af9
	Pone[] =
Packit ed3af9
	{
Packit ed3af9
		0.3511751914303552822533318e+3,
Packit ed3af9
		0.7210391804904475039280863e+3,
Packit ed3af9
		0.4259873011654442389886993e+3,
Packit ed3af9
		0.831898957673850827325226e+2,
Packit ed3af9
		0.45681716295512267064405e+1,
Packit ed3af9
		0.3532840052740123642735e-1
Packit ed3af9
	},
Packit ed3af9
	Qone[] =
Packit ed3af9
	{
Packit ed3af9
		0.74917374171809127714519505e+4,
Packit ed3af9
		0.154141773392650970499848051e+5,
Packit ed3af9
		0.91522317015169922705904727e+4,
Packit ed3af9
		0.18111867005523513506724158e+4,
Packit ed3af9
		0.1038187585462133728776636e+3,
Packit ed3af9
		0.1e+1
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	p = Pone[5];
Packit ed3af9
	q = Qone[5];
Packit ed3af9
	for (i=4; i >= 0; i--)
Packit ed3af9
	{
Packit ed3af9
		p = p*(8.0/x)*(8.0/x)+Pone[i];
Packit ed3af9
		q = q*(8.0/x)*(8.0/x)+Qone[i];
Packit ed3af9
	}
Packit ed3af9
	return (double)(p/q);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double KernelBessel_Order1(double x)
Packit ed3af9
{
Packit ed3af9
	double p, q;
Packit ed3af9
	
Packit ed3af9
	if (x == 0.0)
Packit ed3af9
		return (0.0f);
Packit ed3af9
	p = x;
Packit ed3af9
	if (x < 0.0)
Packit ed3af9
		x=(-x);
Packit ed3af9
	if (x < 8.0)
Packit ed3af9
		return (p*KernelBessel_J1(x));
Packit ed3af9
	q = (double)sqrt(2.0f/(M_PI*x))*(double)(KernelBessel_P1(x)*(1.0f/sqrt(2.0f)*(sin(x)-cos(x)))-8.0f/x*KernelBessel_Q1(x)*
Packit ed3af9
		(-1.0f/sqrt(2.0f)*(sin(x)+cos(x))));
Packit ed3af9
	if (p < 0.0f)
Packit ed3af9
		q = (-q);
Packit ed3af9
	return (q);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double filter_bessel(const double x)
Packit ed3af9
{
Packit ed3af9
	if (x == 0.0f)
Packit ed3af9
		return (double)(M_PI/4.0f);
Packit ed3af9
	return (KernelBessel_Order1((double)M_PI*x)/(2.0f*x));
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
static double filter_blackman(const double x)
Packit ed3af9
{
Packit ed3af9
	return (0.42f+0.5f*(double)cos(M_PI*x)+0.08f*(double)cos(2.0f*M_PI*x));
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
double filter_linear(const double x) {
Packit ed3af9
	double ax = fabs(x);
Packit ed3af9
	if (ax < 1.0f) {
Packit ed3af9
		return (1.0f - ax);
Packit ed3af9
	}
Packit ed3af9
	return 0.0f;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Bicubic interpolation kernel (a=-1):
Packit ed3af9
  \verbatim
Packit ed3af9
          /
Packit ed3af9
         | 1-2|t|**2+|t|**3          , if |t| < 1
Packit ed3af9
  h(t) = | 4-8|t|+5|t|**2-|t|**3     , if 1<=|t|<2
Packit ed3af9
         | 0                         , otherwise
Packit ed3af9
          \
Packit ed3af9
  \endverbatim
Packit ed3af9
 * ***bd*** 2.2004
Packit ed3af9
 */
Packit ed3af9
static double filter_bicubic(const double t)
Packit ed3af9
{
Packit ed3af9
	const double abs_t = (double)fabs(t);
Packit ed3af9
	const double abs_t_sq = abs_t * abs_t;
Packit ed3af9
	if (abs_t<1) return 1-2*abs_t_sq+abs_t_sq*abs_t;
Packit ed3af9
	if (abs_t<2) return 4 - 8*abs_t +5*abs_t_sq - abs_t_sq*abs_t;
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Generalized cubic kernel (for a=-1 it is the same as BicubicKernel):
Packit ed3af9
  \verbatim
Packit ed3af9
          /
Packit ed3af9
         | (a+2)|t|**3 - (a+3)|t|**2 + 1     , |t| <= 1
Packit ed3af9
  h(t) = | a|t|**3 - 5a|t|**2 + 8a|t| - 4a   , 1 < |t| <= 2
Packit ed3af9
         | 0                                 , otherwise
Packit ed3af9
          \
Packit ed3af9
  \endverbatim
Packit ed3af9
 * Often used values for a are -1 and -1/2.
Packit ed3af9
 */
Packit ed3af9
static double filter_generalized_cubic(const double t)
Packit ed3af9
{
Packit ed3af9
	const double a = -DEFAULT_FILTER_GENERALIZED_CUBIC;
Packit ed3af9
	double abs_t = (double)fabs(t);
Packit ed3af9
	double abs_t_sq = abs_t * abs_t;
Packit ed3af9
	if (abs_t < 1) return (a + 2) * abs_t_sq * abs_t - (a + 3) * abs_t_sq + 1;
Packit ed3af9
	if (abs_t < 2) return a * abs_t_sq * abs_t - 5 * a * abs_t_sq + 8 * a * abs_t - 4 * a;
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
/* CubicSpline filter, default radius 2 */
Packit ed3af9
static double filter_cubic_spline(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
Packit ed3af9
	if (x < 1.0 ) {
Packit ed3af9
		const double x2 = x*x;
Packit ed3af9
Packit ed3af9
		return (0.5 * x2 * x - x2 + 2.0 / 3.0);
Packit ed3af9
	}
Packit ed3af9
	if (x < 2.0) {
Packit ed3af9
		return (pow(2.0 - x, 3.0)/6.0);
Packit ed3af9
	}
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
/* CubicConvolution filter, default radius 3 */
Packit ed3af9
static double filter_cubic_convolution(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
	const double x2 = x1 * x1;
Packit ed3af9
	const double x2_x = x2 * x;
Packit ed3af9
Packit ed3af9
	if (x <= 1.0) return ((4.0 / 3.0)* x2_x - (7.0 / 3.0) * x2 + 1.0);
Packit ed3af9
	if (x <= 2.0) return (- (7.0 / 12.0) * x2_x + 3 * x2 - (59.0 / 12.0) * x + 2.5);
Packit ed3af9
	if (x <= 3.0) return ( (1.0/12.0) * x2_x - (2.0 / 3.0) * x2 + 1.75 * x - 1.5);
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static double filter_box(double x) {
Packit ed3af9
	if (x < - DEFAULT_FILTER_BOX)
Packit ed3af9
		return 0.0f;
Packit ed3af9
	if (x < DEFAULT_FILTER_BOX)
Packit ed3af9
		return 1.0f;
Packit ed3af9
	return 0.0f;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double filter_catmullrom(const double x)
Packit ed3af9
{
Packit ed3af9
	if (x < -2.0)
Packit ed3af9
		return(0.0f);
Packit ed3af9
	if (x < -1.0)
Packit ed3af9
		return(0.5f*(4.0f+x*(8.0f+x*(5.0f+x))));
Packit ed3af9
	if (x < 0.0)
Packit ed3af9
		return(0.5f*(2.0f+x*x*(-5.0f-3.0f*x)));
Packit ed3af9
	if (x < 1.0)
Packit ed3af9
		return(0.5f*(2.0f+x*x*(-5.0f+3.0f*x)));
Packit ed3af9
	if (x < 2.0)
Packit ed3af9
		return(0.5f*(4.0f+x*(-8.0f+x*(5.0f-x))));
Packit ed3af9
	return(0.0f);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
static double filter_filter(double t)
Packit ed3af9
{
Packit ed3af9
	/* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */
Packit ed3af9
	if(t < 0.0) t = -t;
Packit ed3af9
	if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
Packit ed3af9
	return(0.0);
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
/* Lanczos8 filter, default radius 8 */
Packit ed3af9
static double filter_lanczos8(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
#define R DEFAULT_LANCZOS8_RADIUS
Packit ed3af9
Packit ed3af9
	if ( x == 0.0) return 1;
Packit ed3af9
Packit ed3af9
	if ( x < R) {
Packit ed3af9
		return R * sin(x*M_PI) * sin(x * M_PI/ R) / (x * M_PI * x * M_PI);
Packit ed3af9
	}
Packit ed3af9
	return 0.0;
Packit ed3af9
#undef R
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
/* Lanczos3 filter, default radius 3 */
Packit ed3af9
static double filter_lanczos3(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
#define R DEFAULT_LANCZOS3_RADIUS
Packit ed3af9
Packit ed3af9
	if ( x == 0.0) return 1;
Packit ed3af9
Packit ed3af9
	if ( x < R)
Packit ed3af9
	{
Packit ed3af9
		return R * sin(x*M_PI) * sin(x * M_PI / R) / (x * M_PI * x * M_PI);
Packit ed3af9
	}
Packit ed3af9
	return 0.0;
Packit ed3af9
#undef R
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/* Hermite filter, default radius 1 */
Packit ed3af9
static double filter_hermite(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
Packit ed3af9
	if (x < 1.0) return ((2.0 * x - 3) * x * x + 1.0 );
Packit ed3af9
Packit ed3af9
	return 0.0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* Trangle filter, default radius 1 */
Packit ed3af9
static double filter_triangle(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
	if (x < 1.0) return (1.0 - x);
Packit ed3af9
	return 0.0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* Bell filter, default radius 1.5 */
Packit ed3af9
static double filter_bell(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
Packit ed3af9
	if (x < 0.5) return (0.75 - x*x);
Packit ed3af9
	if (x < 1.5) return (0.5 * pow(x - 1.5, 2.0));
Packit ed3af9
	return 0.0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* Mitchell filter, default radius 2.0 */
Packit ed3af9
static double filter_mitchell(const double x)
Packit ed3af9
{
Packit ed3af9
#define KM_B (1.0f/3.0f)
Packit ed3af9
#define KM_C (1.0f/3.0f)
Packit ed3af9
#define KM_P0 ((  6.0f - 2.0f * KM_B ) / 6.0f)
Packit ed3af9
#define KM_P2 ((-18.0f + 12.0f * KM_B + 6.0f * KM_C) / 6.0f)
Packit ed3af9
#define KM_P3 (( 12.0f - 9.0f  * KM_B - 6.0f * KM_C) / 6.0f)
Packit ed3af9
#define KM_Q0 ((  8.0f * KM_B + 24.0f * KM_C) / 6.0f)
Packit ed3af9
#define KM_Q1 ((-12.0f * KM_B - 48.0f * KM_C) / 6.0f)
Packit ed3af9
#define KM_Q2 ((  6.0f * KM_B + 30.0f * KM_C) / 6.0f)
Packit ed3af9
#define KM_Q3 (( -1.0f * KM_B -  6.0f * KM_C) / 6.0f)
Packit ed3af9
Packit ed3af9
	if (x < -2.0)
Packit ed3af9
		return(0.0f);
Packit ed3af9
	if (x < -1.0)
Packit ed3af9
		return(KM_Q0-x*(KM_Q1-x*(KM_Q2-x*KM_Q3)));
Packit ed3af9
	if (x < 0.0f)
Packit ed3af9
		return(KM_P0+x*x*(KM_P2-x*KM_P3));
Packit ed3af9
	if (x < 1.0f)
Packit ed3af9
		return(KM_P0+x*x*(KM_P2+x*KM_P3));
Packit ed3af9
	if (x < 2.0f)
Packit ed3af9
		return(KM_Q0+x*(KM_Q1+x*(KM_Q2+x*KM_Q3)));
Packit ed3af9
	return(0.0f);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
/* Cosine filter, default radius 1 */
Packit ed3af9
static double filter_cosine(const double x)
Packit ed3af9
{
Packit ed3af9
	if ((x >= -1.0) && (x <= 1.0)) return ((cos(x * M_PI) + 1.0)/2.0);
Packit ed3af9
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
/* Quadratic filter, default radius 1.5 */
Packit ed3af9
static double filter_quadratic(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
Packit ed3af9
	if (x <= 0.5) return (- 2.0 * x * x + 1);
Packit ed3af9
	if (x <= 1.5) return (x * x - 2.5* x + 1.5);
Packit ed3af9
	return 0.0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double filter_bspline(const double x)
Packit ed3af9
{
Packit ed3af9
	if (x>2.0f) {
Packit ed3af9
		return 0.0f;
Packit ed3af9
	} else {
Packit ed3af9
		double a, b, c, d;
Packit ed3af9
		/* Was calculated anyway cause the "if((x-1.0f) < 0)" */
Packit ed3af9
		const double xm1 = x - 1.0f;
Packit ed3af9
		const double xp1 = x + 1.0f;
Packit ed3af9
		const double xp2 = x + 2.0f;
Packit ed3af9
Packit ed3af9
		if ((xp2) <= 0.0f) a = 0.0f; else a = xp2*xp2*xp2;
Packit ed3af9
		if ((xp1) <= 0.0f) b = 0.0f; else b = xp1*xp1*xp1;
Packit ed3af9
		if (x <= 0) c = 0.0f; else c = x*x*x;
Packit ed3af9
		if ((xm1) <= 0.0f) d = 0.0f; else d = xm1*xm1*xm1;
Packit ed3af9
Packit ed3af9
		return (0.16666666666666666667f * (a - (4.0f * b) + (6.0f * c) - (4.0f * d)));
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
/* QuadraticBSpline filter, default radius 1.5 */
Packit ed3af9
static double filter_quadratic_bspline(const double x1)
Packit ed3af9
{
Packit ed3af9
	const double x = x1 < 0.0 ? -x1 : x1;
Packit ed3af9
Packit ed3af9
	if (x <= 0.5) return (- x * x + 0.75);
Packit ed3af9
	if (x <= 1.5) return (0.5 * x * x - 1.5 * x + 1.125);
Packit ed3af9
	return 0.0;
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static double filter_gaussian(const double x)
Packit ed3af9
{
Packit ed3af9
	/* return(exp((double) (-2.0 * x * x)) * sqrt(2.0 / M_PI)); */
Packit ed3af9
	return (double)(exp(-2.0f * x * x) * 0.79788456080287f);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double filter_hanning(const double x)
Packit ed3af9
{
Packit ed3af9
	/* A Cosine windowing function */
Packit ed3af9
	return(0.5 + 0.5 * cos(M_PI * x));
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double filter_hamming(const double x)
Packit ed3af9
{
Packit ed3af9
	/* should be
Packit ed3af9
	(0.54+0.46*cos(M_PI*(double) x));
Packit ed3af9
	but this approximation is sufficient */
Packit ed3af9
	if (x < -1.0f)
Packit ed3af9
		return 0.0f;
Packit ed3af9
	if (x < 0.0f)
Packit ed3af9
		return 0.92f*(-2.0f*x-3.0f)*x*x+1.0f;
Packit ed3af9
	if (x < 1.0f)
Packit ed3af9
		return 0.92f*(2.0f*x-3.0f)*x*x+1.0f;
Packit ed3af9
	return 0.0f;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double filter_power(const double x)
Packit ed3af9
{
Packit ed3af9
	const double a = 2.0f;
Packit ed3af9
	if (fabs(x)>1) return 0.0f;
Packit ed3af9
	return (1.0f - (double)fabs(pow(x,a)));
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static double filter_sinc(const double x)
Packit ed3af9
{
Packit ed3af9
	/* X-scaled Sinc(x) function. */
Packit ed3af9
	if (x == 0.0) return(1.0);
Packit ed3af9
	return (sin(M_PI * (double) x) / (M_PI * (double) x));
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
static double filter_welsh(const double x)
Packit ed3af9
{
Packit ed3af9
	/* Welsh parabolic windowing filter */
Packit ed3af9
	if (x <  1.0)
Packit ed3af9
		return(1 - x*x);
Packit ed3af9
	return(0.0);
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#if defined(_MSC_VER) && !defined(inline)
Packit ed3af9
# define inline __inline
Packit ed3af9
#endif 
Packit ed3af9
Packit ed3af9
/* keep it for future usage for affine copy over an existing image, targetting fix for 2.2.2 */
Packit ed3af9
#ifdef FUNCTION_NOT_USED_YET
Packit ed3af9
/* Copied from upstream's libgd */
Packit ed3af9
static inline int _color_blend (const int dst, const int src)
Packit ed3af9
{
Packit ed3af9
	const int src_alpha = gdTrueColorGetAlpha(src);
Packit ed3af9
Packit ed3af9
	if( src_alpha == gdAlphaOpaque ) {
Packit ed3af9
		return src;
Packit ed3af9
	} else {
Packit ed3af9
		const int dst_alpha = gdTrueColorGetAlpha(dst);
Packit ed3af9
Packit ed3af9
		if( src_alpha == gdAlphaTransparent ) return dst;
Packit ed3af9
		if( dst_alpha == gdAlphaTransparent ) {
Packit ed3af9
			return src;
Packit ed3af9
		} else {
Packit ed3af9
			register int alpha, red, green, blue;
Packit ed3af9
			const int src_weight = gdAlphaTransparent - src_alpha;
Packit ed3af9
			const int dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
Packit ed3af9
			const int tot_weight = src_weight + dst_weight;
Packit ed3af9
Packit ed3af9
			alpha = src_alpha * dst_alpha / gdAlphaMax;
Packit ed3af9
Packit ed3af9
			red = (gdTrueColorGetRed(src) * src_weight
Packit ed3af9
				   + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
Packit ed3af9
			green = (gdTrueColorGetGreen(src) * src_weight
Packit ed3af9
				   + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
Packit ed3af9
			blue = (gdTrueColorGetBlue(src) * src_weight
Packit ed3af9
				   + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
Packit ed3af9
Packit ed3af9
			return ((alpha << 24) + (red << 16) + (green << 8) + blue);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static inline int _setEdgePixel(const gdImagePtr src, unsigned int x, unsigned int y, gdFixed coverage, const int bgColor) 
Packit ed3af9
{
Packit ed3af9
	const gdFixed f_127 = gd_itofx(127);
Packit ed3af9
	register int c = src->tpixels[y][x];
Packit ed3af9
	c = c | (( (int) (gd_fxtof(gd_mulfx(coverage, f_127)) + 50.5f)) << 24);
Packit ed3af9
	return _color_blend(bgColor, c);
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static inline int getPixelOverflowTC(gdImagePtr im, const int x, const int y, const int bgColor)
Packit ed3af9
{
Packit ed3af9
	if (gdImageBoundsSafe(im, x, y)) {
Packit ed3af9
		const int c = im->tpixels[y][x];
Packit ed3af9
		if (c == im->transparent) {
Packit ed3af9
			return bgColor == -1 ? gdTrueColorAlpha(0, 0, 0, 127) : bgColor;
Packit ed3af9
		}
Packit ed3af9
		return c;
Packit ed3af9
	} else {
Packit ed3af9
		return bgColor;
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#define colorIndex2RGBA(c) gdTrueColorAlpha(im->red[(c)], im->green[(c)], im->blue[(c)], im->alpha[(c)])
Packit ed3af9
#define colorIndex2RGBcustomA(c, a) gdTrueColorAlpha(im->red[(c)], im->green[(c)], im->blue[(c)], im->alpha[(a)])
Packit ed3af9
static inline int getPixelOverflowPalette(gdImagePtr im, const int x, const int y, const int bgColor)
Packit ed3af9
{
Packit ed3af9
	if (gdImageBoundsSafe(im, x, y)) {
Packit ed3af9
		const int c = im->pixels[y][x];
Packit ed3af9
		if (c == im->transparent) {
Packit ed3af9
			return bgColor == -1 ? gdTrueColorAlpha(0, 0, 0, 127) : bgColor;
Packit ed3af9
		}
Packit ed3af9
		return colorIndex2RGBA(c);
Packit ed3af9
	} else {
Packit ed3af9
		return bgColor;
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int getPixelInterpolateWeight(gdImagePtr im, const double x, const double y, const int bgColor)
Packit ed3af9
{
Packit ed3af9
	/* Closest pixel <= (xf,yf) */
Packit ed3af9
	int sx = (int)(x);
Packit ed3af9
	int sy = (int)(y);
Packit ed3af9
	const double xf = x - (double)sx;
Packit ed3af9
	const double yf = y - (double)sy;
Packit ed3af9
	const double nxf = (double) 1.0 - xf;
Packit ed3af9
	const double nyf = (double) 1.0 - yf;
Packit ed3af9
	const double m1 = xf * yf;
Packit ed3af9
	const double m2 = nxf * yf;
Packit ed3af9
	const double m3 = xf * nyf;
Packit ed3af9
	const double m4 = nxf * nyf;
Packit ed3af9
Packit ed3af9
	/* get color values of neighbouring pixels */
Packit ed3af9
	const int c1 = im->trueColor == 1 ? getPixelOverflowTC(im, sx, sy, bgColor)         : getPixelOverflowPalette(im, sx, sy, bgColor);
Packit ed3af9
	const int c2 = im->trueColor == 1 ? getPixelOverflowTC(im, sx - 1, sy, bgColor)     : getPixelOverflowPalette(im, sx - 1, sy, bgColor);
Packit ed3af9
	const int c3 = im->trueColor == 1 ? getPixelOverflowTC(im, sx, sy - 1, bgColor)     : getPixelOverflowPalette(im, sx, sy - 1, bgColor);
Packit ed3af9
	const int c4 = im->trueColor == 1 ? getPixelOverflowTC(im, sx - 1, sy - 1, bgColor) : getPixelOverflowPalette(im, sx, sy - 1, bgColor);
Packit ed3af9
	int r, g, b, a;
Packit ed3af9
Packit ed3af9
	if (x < 0) sx--;
Packit ed3af9
	if (y < 0) sy--;
Packit ed3af9
Packit ed3af9
	/* component-wise summing-up of color values */
Packit ed3af9
	if (im->trueColor) {
Packit ed3af9
		r = (int)(m1*gdTrueColorGetRed(c1)   + m2*gdTrueColorGetRed(c2)   + m3*gdTrueColorGetRed(c3)   + m4*gdTrueColorGetRed(c4));
Packit ed3af9
		g = (int)(m1*gdTrueColorGetGreen(c1) + m2*gdTrueColorGetGreen(c2) + m3*gdTrueColorGetGreen(c3) + m4*gdTrueColorGetGreen(c4));
Packit ed3af9
		b = (int)(m1*gdTrueColorGetBlue(c1)  + m2*gdTrueColorGetBlue(c2)  + m3*gdTrueColorGetBlue(c3)  + m4*gdTrueColorGetBlue(c4));
Packit ed3af9
		a = (int)(m1*gdTrueColorGetAlpha(c1) + m2*gdTrueColorGetAlpha(c2) + m3*gdTrueColorGetAlpha(c3) + m4*gdTrueColorGetAlpha(c4));
Packit ed3af9
	} else {
Packit ed3af9
		r = (int)(m1*im->red[(c1)]   + m2*im->red[(c2)]   + m3*im->red[(c3)]   + m4*im->red[(c4)]);
Packit ed3af9
		g = (int)(m1*im->green[(c1)] + m2*im->green[(c2)] + m3*im->green[(c3)] + m4*im->green[(c4)]);
Packit ed3af9
		b = (int)(m1*im->blue[(c1)]  + m2*im->blue[(c2)]  + m3*im->blue[(c3)]  + m4*im->blue[(c4)]);
Packit ed3af9
		a = (int)(m1*im->alpha[(c1)] + m2*im->alpha[(c2)] + m3*im->alpha[(c3)] + m4*im->alpha[(c4)]);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	r = CLAMP(r, 0, 255);
Packit ed3af9
	g = CLAMP(g, 0, 255);
Packit ed3af9
	b = CLAMP(b, 0, 255);
Packit ed3af9
	a = CLAMP(a, 0, gdAlphaMax);
Packit ed3af9
	return gdTrueColorAlpha(r, g, b, a);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * InternalFunction: getPixelInterpolated
Packit ed3af9
 *  Returns the interpolated color value using the default interpolation
Packit ed3af9
 *  method. The returned color is always in the ARGB format (truecolor).
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 * 	im - Image to set the default interpolation method
Packit ed3af9
 *  y - X value of the ideal position
Packit ed3af9
 *  y - Y value of the ideal position
Packit ed3af9
 *  method - Interpolation method <gdInterpolationMethod>
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *  GD_TRUE if the affine is rectilinear or GD_FALSE
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *  <gdSetInterpolationMethod>
Packit ed3af9
 */
Packit ed3af9
int getPixelInterpolated(gdImagePtr im, const double x, const double y, const int bgColor)
Packit ed3af9
{
Packit ed3af9
	const int xi=(int)(x);
Packit ed3af9
	const int yi=(int)(y);
Packit ed3af9
	int yii;
Packit ed3af9
	int i;
Packit ed3af9
	double kernel, kernel_cache_y;
Packit ed3af9
	double kernel_x[12], kernel_y[4];
Packit ed3af9
	double new_r = 0.0f, new_g = 0.0f, new_b = 0.0f, new_a = 0.0f;
Packit ed3af9
Packit ed3af9
	/* These methods use special implementations */
Packit ed3af9
	if (im->interpolation_id == GD_NEAREST_NEIGHBOUR) {
Packit ed3af9
		return -1;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (im->interpolation_id == GD_WEIGHTED4) {
Packit ed3af9
		return getPixelInterpolateWeight(im, x, y, bgColor);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (im->interpolation_id == GD_NEAREST_NEIGHBOUR) {
Packit ed3af9
		if (im->trueColor == 1) {
Packit ed3af9
			return getPixelOverflowTC(im, xi, yi, bgColor);
Packit ed3af9
		} else {
Packit ed3af9
			return getPixelOverflowPalette(im, xi, yi, bgColor);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	if (im->interpolation) {
Packit ed3af9
		for (i=0; i<4; i++) {
Packit ed3af9
			kernel_x[i] = (double) im->interpolation((double)(xi+i-1-x));
Packit ed3af9
			kernel_y[i] = (double) im->interpolation((double)(yi+i-1-y));
Packit ed3af9
		}
Packit ed3af9
	} else {
Packit ed3af9
		return -1;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/*
Packit ed3af9
	 * TODO: use the known fast rgba multiplication implementation once
Packit ed3af9
	 * the new formats are in place
Packit ed3af9
	 */
Packit ed3af9
	for (yii = yi-1; yii < yi+3; yii++) {
Packit ed3af9
		int xii;
Packit ed3af9
		kernel_cache_y = kernel_y[yii-(yi-1)];
Packit ed3af9
		if (im->trueColor) {
Packit ed3af9
			for (xii=xi-1; xii
Packit ed3af9
				const int rgbs = getPixelOverflowTC(im, xii, yii, bgColor);
Packit ed3af9
Packit ed3af9
				kernel = kernel_cache_y * kernel_x[xii-(xi-1)];
Packit ed3af9
				new_r += kernel * gdTrueColorGetRed(rgbs);
Packit ed3af9
				new_g += kernel * gdTrueColorGetGreen(rgbs);
Packit ed3af9
				new_b += kernel * gdTrueColorGetBlue(rgbs);
Packit ed3af9
				new_a += kernel * gdTrueColorGetAlpha(rgbs);
Packit ed3af9
			}
Packit ed3af9
		} else {
Packit ed3af9
			for (xii=xi-1; xii
Packit ed3af9
				const int rgbs = getPixelOverflowPalette(im, xii, yii, bgColor);
Packit ed3af9
Packit ed3af9
				kernel = kernel_cache_y * kernel_x[xii-(xi-1)];
Packit ed3af9
				new_r += kernel * gdTrueColorGetRed(rgbs);
Packit ed3af9
				new_g += kernel * gdTrueColorGetGreen(rgbs);
Packit ed3af9
				new_b += kernel * gdTrueColorGetBlue(rgbs);
Packit ed3af9
				new_a += kernel * gdTrueColorGetAlpha(rgbs);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	new_r = CLAMP(new_r, 0, 255);
Packit ed3af9
	new_g = CLAMP(new_g, 0, 255);
Packit ed3af9
	new_b = CLAMP(new_b, 0, 255);
Packit ed3af9
	new_a = CLAMP(new_a, 0, gdAlphaMax);
Packit ed3af9
Packit ed3af9
	return gdTrueColorAlpha(((int)new_r), ((int)new_g), ((int)new_b), ((int)new_a));
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static inline LineContribType * _gdContributionsAlloc(unsigned int line_length, unsigned int windows_size)
Packit ed3af9
{
Packit ed3af9
	unsigned int u = 0;
Packit ed3af9
	LineContribType *res;
Packit ed3af9
	size_t weights_size;
Packit ed3af9
Packit ed3af9
	if (overflow2(windows_size, sizeof(double))) {
Packit ed3af9
		return NULL;
Packit ed3af9
	} else {
Packit ed3af9
		weights_size = windows_size * sizeof(double);
Packit ed3af9
	}
Packit ed3af9
	res = (LineContribType *) gdMalloc(sizeof(LineContribType));
Packit ed3af9
	if (!res) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
	res->WindowSize = windows_size;
Packit ed3af9
	res->LineLength = line_length;
Packit ed3af9
	if (overflow2(line_length, sizeof(ContributionType))) {
Packit ed3af9
		gdFree(res);
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
	res->ContribRow = (ContributionType *) gdMalloc(line_length * sizeof(ContributionType));
Packit ed3af9
	if (res->ContribRow == NULL) {
Packit ed3af9
		gdFree(res);
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
	for (u = 0 ; u < line_length ; u++) {
Packit ed3af9
		res->ContribRow[u].Weights = (double *) gdMalloc(weights_size);
Packit ed3af9
		if (res->ContribRow[u].Weights == NULL) {
Packit ed3af9
			unsigned int i;
Packit ed3af9
Packit ed3af9
			for (i=0;i
Packit ed3af9
				gdFree(res->ContribRow[i].Weights);
Packit ed3af9
			}
Packit ed3af9
			gdFree(res->ContribRow);
Packit ed3af9
			gdFree(res);
Packit ed3af9
			return NULL;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return res;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static inline void _gdContributionsFree(LineContribType * p)
Packit ed3af9
{
Packit ed3af9
	unsigned int u;
Packit ed3af9
	for (u = 0; u < p->LineLength; u++)  {
Packit ed3af9
		gdFree(p->ContribRow[u].Weights);
Packit ed3af9
	}
Packit ed3af9
	gdFree(p->ContribRow);
Packit ed3af9
	gdFree(p);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static inline LineContribType *_gdContributionsCalc(unsigned int line_size, unsigned int src_size, double scale_d,  const interpolation_method pFilter)
Packit ed3af9
{
Packit ed3af9
	double width_d;
Packit ed3af9
	double scale_f_d = 1.0;
Packit ed3af9
	const double filter_width_d = DEFAULT_BOX_RADIUS;
Packit ed3af9
	int windows_size;
Packit ed3af9
	unsigned int u;
Packit ed3af9
	LineContribType *res;
Packit ed3af9
Packit ed3af9
	if (scale_d < 1.0) {
Packit ed3af9
		width_d = filter_width_d / scale_d;
Packit ed3af9
		scale_f_d = scale_d;
Packit ed3af9
	}  else {
Packit ed3af9
		width_d= filter_width_d;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	windows_size = 2 * (int)ceil(width_d) + 1;
Packit ed3af9
	res = _gdContributionsAlloc(line_size, windows_size);
Packit ed3af9
	if (res == NULL) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
	for (u = 0; u < line_size; u++) {
Packit ed3af9
		const double dCenter = (double)u / scale_d;
Packit ed3af9
		/* get the significant edge points affecting the pixel */
Packit ed3af9
		register int iLeft = MAX(0, (int)floor (dCenter - width_d));
Packit ed3af9
		int iRight = MIN((int)ceil(dCenter + width_d), (int)src_size - 1);
Packit ed3af9
		double dTotalWeight = 0.0;
Packit ed3af9
		int iSrc;
Packit ed3af9
Packit ed3af9
		/* Cut edge points to fit in filter window in case of spill-off */
Packit ed3af9
		if (iRight - iLeft + 1 > windows_size)  {
Packit ed3af9
			if (iLeft < ((int)src_size - 1 / 2))  {
Packit ed3af9
				iLeft++;
Packit ed3af9
			} else {
Packit ed3af9
				iRight--;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		res->ContribRow[u].Left = iLeft;
Packit ed3af9
		res->ContribRow[u].Right = iRight;
Packit ed3af9
Packit ed3af9
		for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
Packit ed3af9
			dTotalWeight += (res->ContribRow[u].Weights[iSrc-iLeft] =  scale_f_d * (*pFilter)(scale_f_d * (dCenter - (double)iSrc)));
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (dTotalWeight < 0.0) {
Packit ed3af9
			_gdContributionsFree(res);
Packit ed3af9
			return NULL;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (dTotalWeight > 0.0) {
Packit ed3af9
			for (iSrc = iLeft; iSrc <= iRight; iSrc++) {
Packit ed3af9
				res->ContribRow[u].Weights[iSrc-iLeft] /= dTotalWeight;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	return res;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
static inline void
Packit ed3af9
_gdScaleOneAxis(gdImagePtr pSrc, gdImagePtr dst,
Packit ed3af9
				unsigned int dst_len, unsigned int row, LineContribType *contrib,
Packit ed3af9
				gdAxis axis)
Packit ed3af9
{
Packit ed3af9
	unsigned int ndx;
Packit ed3af9
Packit ed3af9
	for (ndx = 0; ndx < dst_len; ndx++) {
Packit ed3af9
		double r = 0, g = 0, b = 0, a = 0;
Packit ed3af9
		const int left = contrib->ContribRow[ndx].Left;
Packit ed3af9
		const int right = contrib->ContribRow[ndx].Right;
Packit ed3af9
		int *dest = (axis == HORIZONTAL) ? 
Packit ed3af9
			&dst->tpixels[row][ndx] : 
Packit ed3af9
			&dst->tpixels[ndx][row];
Packit ed3af9
Packit ed3af9
		int i;
Packit ed3af9
Packit ed3af9
		/* Accumulate each channel */
Packit ed3af9
		for (i = left; i <= right; i++) {
Packit ed3af9
			const int left_channel = i - left;
Packit ed3af9
			const int srcpx = (axis == HORIZONTAL) ?
Packit ed3af9
				pSrc->tpixels[row][i] : 
Packit ed3af9
				pSrc->tpixels[i][row];
Packit ed3af9
Packit ed3af9
			r += contrib->ContribRow[ndx].Weights[left_channel]
Packit ed3af9
				* (double)(gdTrueColorGetRed(srcpx));
Packit ed3af9
			g += contrib->ContribRow[ndx].Weights[left_channel]
Packit ed3af9
				* (double)(gdTrueColorGetGreen(srcpx));
Packit ed3af9
			b += contrib->ContribRow[ndx].Weights[left_channel]
Packit ed3af9
				* (double)(gdTrueColorGetBlue(srcpx));
Packit ed3af9
			a += contrib->ContribRow[ndx].Weights[left_channel]
Packit ed3af9
				* (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),
Packit ed3af9
                                 uchar_clamp(a, 0x7F)); /* alpha is 0..127 */
Packit ed3af9
	}/* for */
Packit ed3af9
}/* _gdScaleOneAxis*/
Packit ed3af9
Packit ed3af9
Packit ed3af9
static inline int
Packit ed3af9
_gdScalePass(const gdImagePtr pSrc, const unsigned int src_len,
Packit ed3af9
             const gdImagePtr pDst, const unsigned int dst_len,
Packit ed3af9
             const unsigned int num_lines,
Packit ed3af9
             const gdAxis axis)
Packit ed3af9
{
Packit ed3af9
	unsigned int line_ndx;
Packit ed3af9
	LineContribType * contrib;
Packit ed3af9
Packit ed3af9
    /* Same dim, just copy it. */
Packit ed3af9
    assert(dst_len != src_len); // TODO: caller should handle this.
Packit ed3af9
Packit ed3af9
	contrib = _gdContributionsCalc(dst_len, src_len,
Packit ed3af9
                                   (double)dst_len / (double)src_len,
Packit ed3af9
                                   pSrc->interpolation);
Packit ed3af9
	if (contrib == NULL) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* Scale each line */
Packit ed3af9
    for (line_ndx = 0; line_ndx < num_lines; line_ndx++) {
Packit ed3af9
        _gdScaleOneAxis(pSrc, pDst, dst_len, line_ndx, contrib, axis);
Packit ed3af9
	}
Packit ed3af9
	_gdContributionsFree (contrib);
Packit ed3af9
    return 1;
Packit ed3af9
}/* _gdScalePass*/
Packit ed3af9
Packit ed3af9
Packit ed3af9
static gdImagePtr
Packit ed3af9
gdImageScaleTwoPass(const gdImagePtr src, const unsigned int new_width,
Packit ed3af9
                    const unsigned int new_height)
Packit ed3af9
{
Packit ed3af9
    const unsigned int src_width = src->sx;
Packit ed3af9
    const unsigned int src_height = src->sy;
Packit ed3af9
	gdImagePtr tmp_im = NULL;
Packit ed3af9
	gdImagePtr dst = NULL;
Packit ed3af9
	int scale_pass_res;
Packit ed3af9
Packit ed3af9
	assert(src != NULL);
Packit ed3af9
Packit ed3af9
    /* First, handle the trivial case. */
Packit ed3af9
    if (src_width == new_width && src_height == new_height) {
Packit ed3af9
        return gdImageClone(src);
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
	/* Convert to truecolor if it isn't; this code requires it. */
Packit ed3af9
	if (!src->trueColor) {
Packit ed3af9
		gdImagePaletteToTrueColor(src);
Packit ed3af9
	}/* if */
Packit ed3af9
Packit ed3af9
    /* Scale horizontally unless sizes are the same. */
Packit ed3af9
    if (src_width == new_width) {
Packit ed3af9
        tmp_im = src;
Packit ed3af9
    } else {
Packit ed3af9
        tmp_im = gdImageCreateTrueColor(new_width, src_height);
Packit ed3af9
        if (tmp_im == NULL) {
Packit ed3af9
            return NULL;
Packit ed3af9
        }
Packit ed3af9
        gdImageSetInterpolationMethod(tmp_im, src->interpolation_id);
Packit ed3af9
Packit ed3af9
		scale_pass_res = _gdScalePass(src, src_width, tmp_im, new_width, src_height, HORIZONTAL);
Packit ed3af9
		if (scale_pass_res != 1) {
Packit ed3af9
			gdImageDestroy(tmp_im);
Packit ed3af9
			return NULL;
Packit ed3af9
		}
Packit ed3af9
    }/* if .. else*/
Packit ed3af9
Packit ed3af9
    /* If vertical sizes match, we're done. */
Packit ed3af9
    if (src_height == new_height) {
Packit ed3af9
        assert(tmp_im != src);
Packit ed3af9
        return tmp_im;
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
    /* Otherwise, we need to scale vertically. */
Packit ed3af9
	dst = gdImageCreateTrueColor(new_width, new_height);
Packit ed3af9
	if (dst != NULL) {
Packit ed3af9
        gdImageSetInterpolationMethod(dst, src->interpolation_id);
Packit ed3af9
        scale_pass_res = _gdScalePass(tmp_im, src_height, dst, new_height, new_width, VERTICAL);
Packit ed3af9
		if (scale_pass_res != 1) {
Packit ed3af9
			gdImageDestroy(dst);
Packit ed3af9
			if (src != tmp_im) {
Packit ed3af9
				gdImageDestroy(tmp_im);
Packit ed3af9
			}
Packit ed3af9
			return NULL;
Packit ed3af9
	   }
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
Packit ed3af9
	if (src != tmp_im) {
Packit ed3af9
        gdImageDestroy(tmp_im);
Packit ed3af9
    }/* if */
Packit ed3af9
Packit ed3af9
	return dst;
Packit ed3af9
}/* gdImageScaleTwoPass*/
Packit ed3af9
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	BilinearFixed, BicubicFixed and nearest implementations are
Packit ed3af9
	rewamped versions of the implementation in CBitmapEx
Packit ed3af9
Packit ed3af9
	http://www.codeproject.com/Articles/29121/CBitmapEx-Free-C-Bitmap-Manipulation-Class
Packit ed3af9
Packit ed3af9
	Integer only implementation, good to have for common usages like
Packit ed3af9
	pre scale very large images before using another interpolation
Packit ed3af9
	methods for the last step.
Packit ed3af9
*/
Packit ed3af9
static gdImagePtr
Packit ed3af9
gdImageScaleNearestNeighbour(gdImagePtr im, const unsigned int width, const unsigned int height)
Packit ed3af9
{
Packit ed3af9
	const unsigned long new_width = MAX(1, width);
Packit ed3af9
	const unsigned long new_height = MAX(1, height);
Packit ed3af9
	const float dx = (float)im->sx / (float)new_width;
Packit ed3af9
	const float dy = (float)im->sy / (float)new_height;
Packit ed3af9
	const gdFixed f_dx = gd_ftofx(dx);
Packit ed3af9
	const gdFixed f_dy = gd_ftofx(dy);
Packit ed3af9
Packit ed3af9
	gdImagePtr dst_img;
Packit ed3af9
	unsigned long  dst_offset_x;
Packit ed3af9
	unsigned long  dst_offset_y = 0;
Packit ed3af9
	unsigned int i;
Packit ed3af9
Packit ed3af9
	dst_img = gdImageCreateTrueColor(new_width, new_height);
Packit ed3af9
Packit ed3af9
	if (dst_img == NULL) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	for (i=0; i
Packit ed3af9
		unsigned int j;
Packit ed3af9
		dst_offset_x = 0;
Packit ed3af9
		if (im->trueColor) {
Packit ed3af9
			for (j=0; j
Packit ed3af9
				const gdFixed f_i = gd_itofx(i);
Packit ed3af9
				const gdFixed f_j = gd_itofx(j);
Packit ed3af9
				const gdFixed f_a = gd_mulfx(f_i, f_dy);
Packit ed3af9
				const gdFixed f_b = gd_mulfx(f_j, f_dx);
Packit ed3af9
				const long m = gd_fxtoi(f_a);
Packit ed3af9
				const long n = gd_fxtoi(f_b);
Packit ed3af9
Packit ed3af9
				dst_img->tpixels[dst_offset_y][dst_offset_x++] = im->tpixels[m][n];
Packit ed3af9
			}
Packit ed3af9
		} else {
Packit ed3af9
			for (j=0; j
Packit ed3af9
				const gdFixed f_i = gd_itofx(i);
Packit ed3af9
				const gdFixed f_j = gd_itofx(j);
Packit ed3af9
				const gdFixed f_a = gd_mulfx(f_i, f_dy);
Packit ed3af9
				const gdFixed f_b = gd_mulfx(f_j, f_dx);
Packit ed3af9
				const long m = gd_fxtoi(f_a);
Packit ed3af9
				const long n = gd_fxtoi(f_b);
Packit ed3af9
Packit ed3af9
				dst_img->tpixels[dst_offset_y][dst_offset_x++] = colorIndex2RGBA(im->pixels[m][n]);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		dst_offset_y++;
Packit ed3af9
	}
Packit ed3af9
	return dst_img;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#if 0
Packit ed3af9
static inline int getPixelOverflowColorTC(gdImagePtr im, const int x, const int y, const int color)
Packit ed3af9
{
Packit ed3af9
	if (gdImageBoundsSafe(im, x, y)) {
Packit ed3af9
		const int c = im->tpixels[y][x];
Packit ed3af9
		if (c == im->transparent) {
Packit ed3af9
			return gdTrueColorAlpha(0, 0, 0, 127);
Packit ed3af9
		}
Packit ed3af9
		return c;
Packit ed3af9
	} else {
Packit ed3af9
		register int border = 0;
Packit ed3af9
		if (y < im->cy1) {
Packit ed3af9
			border = im->tpixels[0][im->cx1];
Packit ed3af9
			goto processborder;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (y < im->cy1) {
Packit ed3af9
			border = im->tpixels[0][im->cx1];
Packit ed3af9
			goto processborder;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (y > im->cy2) {
Packit ed3af9
			if (x >= im->cx1 && x <= im->cx1) {
Packit ed3af9
				border = im->tpixels[im->cy2][x];
Packit ed3af9
				goto processborder;
Packit ed3af9
			} else {
Packit ed3af9
				return gdTrueColorAlpha(0, 0, 0, 127);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		/* y is bound safe at this point */
Packit ed3af9
		if (x < im->cx1) {
Packit ed3af9
			border = im->tpixels[y][im->cx1];
Packit ed3af9
			goto processborder;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (x > im->cx2) {
Packit ed3af9
			border = im->tpixels[y][im->cx2];
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
processborder:
Packit ed3af9
		if (border == im->transparent) {
Packit ed3af9
			return gdTrueColorAlpha(0, 0, 0, 127);
Packit ed3af9
		} else{
Packit ed3af9
			return gdTrueColorAlpha(gdTrueColorGetRed(border), gdTrueColorGetGreen(border), gdTrueColorGetBlue(border), 127);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
static gdImagePtr gdImageScaleBilinearPalette(gdImagePtr im, const unsigned int new_width, const unsigned int new_height)
Packit ed3af9
{
Packit ed3af9
	long _width = MAX(1, new_width);
Packit ed3af9
	long _height = MAX(1, new_height);
Packit ed3af9
	float dx = (float)gdImageSX(im) / (float)_width;
Packit ed3af9
	float dy = (float)gdImageSY(im) / (float)_height;
Packit ed3af9
	gdFixed f_dx = gd_ftofx(dx);
Packit ed3af9
	gdFixed f_dy = gd_ftofx(dy);
Packit ed3af9
	gdFixed f_1 = gd_itofx(1);
Packit ed3af9
Packit ed3af9
	int dst_offset_h;
Packit ed3af9
	int dst_offset_v = 0;
Packit ed3af9
	long i;
Packit ed3af9
	gdImagePtr new_img;
Packit ed3af9
	const int transparent = im->transparent;
Packit ed3af9
Packit ed3af9
	new_img = gdImageCreateTrueColor(new_width, new_height);
Packit ed3af9
	if (new_img == NULL) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (transparent < 0) {
Packit ed3af9
		/* uninitialized */
Packit ed3af9
		new_img->transparent = -1;
Packit ed3af9
	} else {
Packit ed3af9
		new_img->transparent = gdTrueColorAlpha(im->red[transparent], im->green[transparent], im->blue[transparent], im->alpha[transparent]);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	for (i=0; i < _height; i++) {
Packit ed3af9
		long j;
Packit ed3af9
		const gdFixed f_i = gd_itofx(i);
Packit ed3af9
		const gdFixed f_a = gd_mulfx(f_i, f_dy);
Packit ed3af9
		register long m = gd_fxtoi(f_a);
Packit ed3af9
Packit ed3af9
		dst_offset_h = 0;
Packit ed3af9
Packit ed3af9
		for (j=0; j < _width; j++) {
Packit ed3af9
			/* Update bitmap */
Packit ed3af9
			gdFixed f_j = gd_itofx(j);
Packit ed3af9
			gdFixed f_b = gd_mulfx(f_j, f_dx);
Packit ed3af9
Packit ed3af9
			const long n = gd_fxtoi(f_b);
Packit ed3af9
			gdFixed f_f = f_a - gd_itofx(m);
Packit ed3af9
			gdFixed f_g = f_b - gd_itofx(n);
Packit ed3af9
Packit ed3af9
			const gdFixed f_w1 = gd_mulfx(f_1-f_f, f_1-f_g);
Packit ed3af9
			const gdFixed f_w2 = gd_mulfx(f_1-f_f, f_g);
Packit ed3af9
			const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g);
Packit ed3af9
			const gdFixed f_w4 = gd_mulfx(f_f, f_g);
Packit ed3af9
			unsigned int pixel1;
Packit ed3af9
			unsigned int pixel2;
Packit ed3af9
			unsigned int pixel3;
Packit ed3af9
			unsigned int pixel4;
Packit ed3af9
			register gdFixed f_r1, f_r2, f_r3, f_r4,
Packit ed3af9
					f_g1, f_g2, f_g3, f_g4,
Packit ed3af9
					f_b1, f_b2, f_b3, f_b4,
Packit ed3af9
					f_a1, f_a2, f_a3, f_a4;
Packit ed3af9
Packit ed3af9
			/* 0 for bgColor; (n,m) is supposed to be valid anyway */
Packit ed3af9
			pixel1 = getPixelOverflowPalette(im, n, m, 0);
Packit ed3af9
			pixel2 = getPixelOverflowPalette(im, n + 1, m, pixel1);
Packit ed3af9
			pixel3 = getPixelOverflowPalette(im, n, m + 1, pixel1);
Packit ed3af9
			pixel4 = getPixelOverflowPalette(im, n + 1, m + 1, pixel1);
Packit ed3af9
Packit ed3af9
			f_r1 = gd_itofx(gdTrueColorGetRed(pixel1));
Packit ed3af9
			f_r2 = gd_itofx(gdTrueColorGetRed(pixel2));
Packit ed3af9
			f_r3 = gd_itofx(gdTrueColorGetRed(pixel3));
Packit ed3af9
			f_r4 = gd_itofx(gdTrueColorGetRed(pixel4));
Packit ed3af9
			f_g1 = gd_itofx(gdTrueColorGetGreen(pixel1));
Packit ed3af9
			f_g2 = gd_itofx(gdTrueColorGetGreen(pixel2));
Packit ed3af9
			f_g3 = gd_itofx(gdTrueColorGetGreen(pixel3));
Packit ed3af9
			f_g4 = gd_itofx(gdTrueColorGetGreen(pixel4));
Packit ed3af9
			f_b1 = gd_itofx(gdTrueColorGetBlue(pixel1));
Packit ed3af9
			f_b2 = gd_itofx(gdTrueColorGetBlue(pixel2));
Packit ed3af9
			f_b3 = gd_itofx(gdTrueColorGetBlue(pixel3));
Packit ed3af9
			f_b4 = gd_itofx(gdTrueColorGetBlue(pixel4));
Packit ed3af9
			f_a1 = gd_itofx(gdTrueColorGetAlpha(pixel1));
Packit ed3af9
			f_a2 = gd_itofx(gdTrueColorGetAlpha(pixel2));
Packit ed3af9
			f_a3 = gd_itofx(gdTrueColorGetAlpha(pixel3));
Packit ed3af9
			f_a4 = gd_itofx(gdTrueColorGetAlpha(pixel4));
Packit ed3af9
Packit ed3af9
			{
Packit ed3af9
				const unsigned char red = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_r1) + gd_mulfx(f_w2, f_r2) + gd_mulfx(f_w3, f_r3) + gd_mulfx(f_w4, f_r4));
Packit ed3af9
				const unsigned char green = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_g1) + gd_mulfx(f_w2, f_g2) + gd_mulfx(f_w3, f_g3) + gd_mulfx(f_w4, f_g4));
Packit ed3af9
				const unsigned char blue = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_b1) + gd_mulfx(f_w2, f_b2) + gd_mulfx(f_w3, f_b3) + gd_mulfx(f_w4, f_b4));
Packit ed3af9
				const unsigned char alpha = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_a1) + gd_mulfx(f_w2, f_a2) + gd_mulfx(f_w3, f_a3) + gd_mulfx(f_w4, f_a4));
Packit ed3af9
Packit ed3af9
				new_img->tpixels[dst_offset_v][dst_offset_h] = gdTrueColorAlpha(red, green, blue, alpha);
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			dst_offset_h++;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		dst_offset_v++;
Packit ed3af9
	}
Packit ed3af9
	return new_img;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static gdImagePtr gdImageScaleBilinearTC(gdImagePtr im, const unsigned int new_width, const unsigned int new_height)
Packit ed3af9
{
Packit ed3af9
	long dst_w = MAX(1, new_width);
Packit ed3af9
	long dst_h = MAX(1, new_height);
Packit ed3af9
	float dx = (float)gdImageSX(im) / (float)dst_w;
Packit ed3af9
	float dy = (float)gdImageSY(im) / (float)dst_h;
Packit ed3af9
	gdFixed f_dx = gd_ftofx(dx);
Packit ed3af9
	gdFixed f_dy = gd_ftofx(dy);
Packit ed3af9
	gdFixed f_1 = gd_itofx(1);
Packit ed3af9
Packit ed3af9
	int dst_offset_h;
Packit ed3af9
	int dst_offset_v = 0;
Packit ed3af9
	long i;
Packit ed3af9
	gdImagePtr new_img;
Packit ed3af9
Packit ed3af9
	new_img = gdImageCreateTrueColor(new_width, new_height);
Packit ed3af9
	if (!new_img){
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	for (i=0; i < dst_h; i++) {
Packit ed3af9
		long j;
Packit ed3af9
		dst_offset_h = 0;
Packit ed3af9
		for (j=0; j < dst_w; j++) {
Packit ed3af9
			/* Update bitmap */
Packit ed3af9
			gdFixed f_i = gd_itofx(i);
Packit ed3af9
			gdFixed f_j = gd_itofx(j);
Packit ed3af9
			gdFixed f_a = gd_mulfx(f_i, f_dy);
Packit ed3af9
			gdFixed f_b = gd_mulfx(f_j, f_dx);
Packit ed3af9
			const gdFixed m = gd_fxtoi(f_a);
Packit ed3af9
			const gdFixed n = gd_fxtoi(f_b);
Packit ed3af9
			gdFixed f_f = f_a - gd_itofx(m);
Packit ed3af9
			gdFixed f_g = f_b - gd_itofx(n);
Packit ed3af9
Packit ed3af9
			const gdFixed f_w1 = gd_mulfx(f_1-f_f, f_1-f_g);
Packit ed3af9
			const gdFixed f_w2 = gd_mulfx(f_1-f_f, f_g);
Packit ed3af9
			const gdFixed f_w3 = gd_mulfx(f_f, f_1-f_g);
Packit ed3af9
			const gdFixed f_w4 = gd_mulfx(f_f, f_g);
Packit ed3af9
			unsigned int pixel1;
Packit ed3af9
			unsigned int pixel2;
Packit ed3af9
			unsigned int pixel3;
Packit ed3af9
			unsigned int pixel4;
Packit ed3af9
			register gdFixed f_r1, f_r2, f_r3, f_r4,
Packit ed3af9
					f_g1, f_g2, f_g3, f_g4,
Packit ed3af9
					f_b1, f_b2, f_b3, f_b4,
Packit ed3af9
					f_a1, f_a2, f_a3, f_a4;
Packit ed3af9
			/* 0 for bgColor; (n,m) is supposed to be valid anyway */
Packit ed3af9
			pixel1 = getPixelOverflowTC(im, n, m, 0);
Packit ed3af9
			pixel2 = getPixelOverflowTC(im, n + 1, m, pixel1);
Packit ed3af9
			pixel3 = getPixelOverflowTC(im, n, m + 1, pixel1);
Packit ed3af9
			pixel4 = getPixelOverflowTC(im, n + 1, m + 1, pixel1);
Packit ed3af9
Packit ed3af9
			f_r1 = gd_itofx(gdTrueColorGetRed(pixel1));
Packit ed3af9
			f_r2 = gd_itofx(gdTrueColorGetRed(pixel2));
Packit ed3af9
			f_r3 = gd_itofx(gdTrueColorGetRed(pixel3));
Packit ed3af9
			f_r4 = gd_itofx(gdTrueColorGetRed(pixel4));
Packit ed3af9
			f_g1 = gd_itofx(gdTrueColorGetGreen(pixel1));
Packit ed3af9
			f_g2 = gd_itofx(gdTrueColorGetGreen(pixel2));
Packit ed3af9
			f_g3 = gd_itofx(gdTrueColorGetGreen(pixel3));
Packit ed3af9
			f_g4 = gd_itofx(gdTrueColorGetGreen(pixel4));
Packit ed3af9
			f_b1 = gd_itofx(gdTrueColorGetBlue(pixel1));
Packit ed3af9
			f_b2 = gd_itofx(gdTrueColorGetBlue(pixel2));
Packit ed3af9
			f_b3 = gd_itofx(gdTrueColorGetBlue(pixel3));
Packit ed3af9
			f_b4 = gd_itofx(gdTrueColorGetBlue(pixel4));
Packit ed3af9
			f_a1 = gd_itofx(gdTrueColorGetAlpha(pixel1));
Packit ed3af9
			f_a2 = gd_itofx(gdTrueColorGetAlpha(pixel2));
Packit ed3af9
			f_a3 = gd_itofx(gdTrueColorGetAlpha(pixel3));
Packit ed3af9
			f_a4 = gd_itofx(gdTrueColorGetAlpha(pixel4));
Packit ed3af9
			{
Packit ed3af9
				const unsigned char red   = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_r1) + gd_mulfx(f_w2, f_r2) + gd_mulfx(f_w3, f_r3) + gd_mulfx(f_w4, f_r4));
Packit ed3af9
				const unsigned char green = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_g1) + gd_mulfx(f_w2, f_g2) + gd_mulfx(f_w3, f_g3) + gd_mulfx(f_w4, f_g4));
Packit ed3af9
				const unsigned char blue  = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_b1) + gd_mulfx(f_w2, f_b2) + gd_mulfx(f_w3, f_b3) + gd_mulfx(f_w4, f_b4));
Packit ed3af9
				const unsigned char alpha = (unsigned char) gd_fxtoi(gd_mulfx(f_w1, f_a1) + gd_mulfx(f_w2, f_a2) + gd_mulfx(f_w3, f_a3) + gd_mulfx(f_w4, f_a4));
Packit ed3af9
Packit ed3af9
				new_img->tpixels[dst_offset_v][dst_offset_h] = gdTrueColorAlpha(red, green, blue, alpha);
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			dst_offset_h++;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		dst_offset_v++;
Packit ed3af9
	}
Packit ed3af9
	return new_img;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static gdImagePtr
Packit ed3af9
gdImageScaleBilinear(gdImagePtr im, const unsigned int new_width,
Packit ed3af9
                     const unsigned int new_height)
Packit ed3af9
{
Packit ed3af9
	if (im->trueColor) {
Packit ed3af9
		return gdImageScaleBilinearTC(im, new_width, new_height);
Packit ed3af9
	} else {
Packit ed3af9
		return gdImageScaleBilinearPalette(im, new_width, new_height);
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static gdImagePtr
Packit ed3af9
gdImageScaleBicubicFixed(gdImagePtr src, const unsigned int width,
Packit ed3af9
                         const unsigned int height)
Packit ed3af9
{
Packit ed3af9
	const long new_width = MAX(1, width);
Packit ed3af9
	const long new_height = MAX(1, height);
Packit ed3af9
	const int src_w = gdImageSX(src);
Packit ed3af9
	const int src_h = gdImageSY(src);
Packit ed3af9
	const gdFixed f_dx = gd_ftofx((float)src_w / (float)new_width);
Packit ed3af9
	const gdFixed f_dy = gd_ftofx((float)src_h / (float)new_height);
Packit ed3af9
	const gdFixed f_1 = gd_itofx(1);
Packit ed3af9
	const gdFixed f_2 = gd_itofx(2);
Packit ed3af9
	const gdFixed f_4 = gd_itofx(4);
Packit ed3af9
	const gdFixed f_6 = gd_itofx(6);
Packit ed3af9
	const gdFixed f_gamma = gd_ftofx(1.04f);
Packit ed3af9
	gdImagePtr dst;
Packit ed3af9
Packit ed3af9
	unsigned int dst_offset_x;
Packit ed3af9
	unsigned int dst_offset_y = 0;
Packit ed3af9
	long i;
Packit ed3af9
Packit ed3af9
	/* impact perf a bit, but not that much. Implementation for palette
Packit ed3af9
	   images can be done at a later point.
Packit ed3af9
	*/
Packit ed3af9
	if (src->trueColor == 0) {
Packit ed3af9
		gdImagePaletteToTrueColor(src);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	dst = gdImageCreateTrueColor(new_width, new_height);
Packit ed3af9
	if (!dst) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	dst->saveAlphaFlag = 1;
Packit ed3af9
Packit ed3af9
	for (i=0; i < new_height; i++) {
Packit ed3af9
		long j;
Packit ed3af9
		dst_offset_x = 0;
Packit ed3af9
Packit ed3af9
		for (j=0; j < new_width; j++) {
Packit ed3af9
			const gdFixed f_a = gd_mulfx(gd_itofx(i), f_dy);
Packit ed3af9
			const gdFixed f_b = gd_mulfx(gd_itofx(j), f_dx);
Packit ed3af9
			const long m = gd_fxtoi(f_a);
Packit ed3af9
			const long n = gd_fxtoi(f_b);
Packit ed3af9
			const gdFixed f_f = f_a - gd_itofx(m);
Packit ed3af9
			const gdFixed f_g = f_b - gd_itofx(n);
Packit ed3af9
			unsigned int src_offset_x[16], src_offset_y[16];
Packit ed3af9
			long k;
Packit ed3af9
			register gdFixed f_red = 0, f_green = 0, f_blue = 0, f_alpha = 0;
Packit ed3af9
			unsigned char red, green, blue, alpha = 0;
Packit ed3af9
			int *dst_row = dst->tpixels[dst_offset_y];
Packit ed3af9
Packit ed3af9
			if ((m < 1) || (n < 1)) {
Packit ed3af9
				src_offset_x[0] = n;
Packit ed3af9
				src_offset_y[0] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[0] = n - 1;
Packit ed3af9
				src_offset_y[0] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			src_offset_x[1] = n;
Packit ed3af9
			src_offset_y[1] = m;
Packit ed3af9
Packit ed3af9
			if ((m < 1) || (n >= src_w - 1)) {
Packit ed3af9
				src_offset_x[2] = n;
Packit ed3af9
				src_offset_y[2] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[2] = n + 1;
Packit ed3af9
				src_offset_y[2] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if ((m < 1) || (n >= src_w - 2)) {
Packit ed3af9
				src_offset_x[3] = n;
Packit ed3af9
				src_offset_y[3] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[3] = n + 1 + 1;
Packit ed3af9
				src_offset_y[3] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if (n < 1) {
Packit ed3af9
				src_offset_x[4] = n;
Packit ed3af9
				src_offset_y[4] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[4] = n - 1;
Packit ed3af9
				src_offset_y[4] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			src_offset_x[5] = n;
Packit ed3af9
			src_offset_y[5] = m;
Packit ed3af9
			if (n >= src_w-1) {
Packit ed3af9
				src_offset_x[6] = n;
Packit ed3af9
				src_offset_y[6] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[6] = n + 1;
Packit ed3af9
				src_offset_y[6] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if (n >= src_w - 2) {
Packit ed3af9
				src_offset_x[7] = n;
Packit ed3af9
				src_offset_y[7] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[7] = n + 1 + 1;
Packit ed3af9
				src_offset_y[7] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if ((m >= src_h - 1) || (n < 1)) {
Packit ed3af9
				src_offset_x[8] = n;
Packit ed3af9
				src_offset_y[8] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[8] = n - 1;
Packit ed3af9
				src_offset_y[8] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			src_offset_x[9] = n;
Packit ed3af9
			src_offset_y[9] = m;
Packit ed3af9
Packit ed3af9
			if ((m >= src_h-1) || (n >= src_w-1)) {
Packit ed3af9
				src_offset_x[10] = n;
Packit ed3af9
				src_offset_y[10] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[10] = n + 1;
Packit ed3af9
				src_offset_y[10] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if ((m >= src_h - 1) || (n >= src_w - 2)) {
Packit ed3af9
				src_offset_x[11] = n;
Packit ed3af9
				src_offset_y[11] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[11] = n + 1 + 1;
Packit ed3af9
				src_offset_y[11] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if ((m >= src_h - 2) || (n < 1)) {
Packit ed3af9
				src_offset_x[12] = n;
Packit ed3af9
				src_offset_y[12] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[12] = n - 1;
Packit ed3af9
				src_offset_y[12] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if (!(m >= src_h - 2)) {
Packit ed3af9
				src_offset_x[13] = n;
Packit ed3af9
				src_offset_y[13] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if ((m >= src_h - 2) || (n >= src_w - 1)) {
Packit ed3af9
				src_offset_x[14] = n;
Packit ed3af9
				src_offset_y[14] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[14] = n + 1;
Packit ed3af9
				src_offset_y[14] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if ((m >= src_h - 2) || (n >= src_w - 2)) {
Packit ed3af9
				src_offset_x[15] = n;
Packit ed3af9
				src_offset_y[15] = m;
Packit ed3af9
			} else {
Packit ed3af9
				src_offset_x[15] = n  + 1 + 1;
Packit ed3af9
				src_offset_y[15] = m;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			for (k = -1; k < 3; k++) {
Packit ed3af9
				const gdFixed f = gd_itofx(k)-f_f;
Packit ed3af9
				const gdFixed f_fm1 = f - f_1;
Packit ed3af9
				const gdFixed f_fp1 = f + f_1;
Packit ed3af9
				const gdFixed f_fp2 = f + f_2;
Packit ed3af9
				register gdFixed f_a = 0, f_b = 0, f_d = 0, f_c = 0;
Packit ed3af9
				register gdFixed f_RY;
Packit ed3af9
				int l;
Packit ed3af9
Packit ed3af9
				if (f_fp2 > 0) f_a = gd_mulfx(f_fp2, gd_mulfx(f_fp2,f_fp2));
Packit ed3af9
				if (f_fp1 > 0) f_b = gd_mulfx(f_fp1, gd_mulfx(f_fp1,f_fp1));
Packit ed3af9
				if (f > 0)     f_c = gd_mulfx(f, gd_mulfx(f,f));
Packit ed3af9
				if (f_fm1 > 0) f_d = gd_mulfx(f_fm1, gd_mulfx(f_fm1,f_fm1));
Packit ed3af9
Packit ed3af9
				f_RY = gd_divfx((f_a - gd_mulfx(f_4,f_b) + gd_mulfx(f_6,f_c) - gd_mulfx(f_4,f_d)),f_6);
Packit ed3af9
Packit ed3af9
				for (l = -1; l < 3; l++) {
Packit ed3af9
					const gdFixed f = gd_itofx(l) - f_g;
Packit ed3af9
					const gdFixed f_fm1 = f - f_1;
Packit ed3af9
					const gdFixed f_fp1 = f + f_1;
Packit ed3af9
					const gdFixed f_fp2 = f + f_2;
Packit ed3af9
					register gdFixed f_a = 0, f_b = 0, f_c = 0, f_d = 0;
Packit ed3af9
					register gdFixed f_RX, f_R, f_rs, f_gs, f_bs, f_ba;
Packit ed3af9
					register int c;
Packit ed3af9
					const int _k = ((k+1)*4) + (l+1);
Packit ed3af9
Packit ed3af9
					if (f_fp2 > 0) f_a = gd_mulfx(f_fp2,gd_mulfx(f_fp2,f_fp2));
Packit ed3af9
Packit ed3af9
					if (f_fp1 > 0) f_b = gd_mulfx(f_fp1,gd_mulfx(f_fp1,f_fp1));
Packit ed3af9
Packit ed3af9
					if (f > 0) f_c = gd_mulfx(f,gd_mulfx(f,f));
Packit ed3af9
Packit ed3af9
					if (f_fm1 > 0) f_d = gd_mulfx(f_fm1,gd_mulfx(f_fm1,f_fm1));
Packit ed3af9
Packit ed3af9
					f_RX = gd_divfx((f_a-gd_mulfx(f_4,f_b)+gd_mulfx(f_6,f_c)-gd_mulfx(f_4,f_d)),f_6);
Packit ed3af9
					f_R = gd_mulfx(f_RY,f_RX);
Packit ed3af9
Packit ed3af9
					c = src->tpixels[*(src_offset_y + _k)][*(src_offset_x + _k)];
Packit ed3af9
					f_rs = gd_itofx(gdTrueColorGetRed(c));
Packit ed3af9
					f_gs = gd_itofx(gdTrueColorGetGreen(c));
Packit ed3af9
					f_bs = gd_itofx(gdTrueColorGetBlue(c));
Packit ed3af9
					f_ba = gd_itofx(gdTrueColorGetAlpha(c));
Packit ed3af9
Packit ed3af9
					f_red += gd_mulfx(f_rs,f_R);
Packit ed3af9
					f_green += gd_mulfx(f_gs,f_R);
Packit ed3af9
					f_blue += gd_mulfx(f_bs,f_R);
Packit ed3af9
					f_alpha += gd_mulfx(f_ba,f_R);
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			red    = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_red,   f_gamma)),  0, 255);
Packit ed3af9
			green  = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_green, f_gamma)),  0, 255);
Packit ed3af9
			blue   = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_blue,  f_gamma)),  0, 255);
Packit ed3af9
			alpha  = (unsigned char) CLAMP(gd_fxtoi(gd_mulfx(f_alpha,  f_gamma)), 0, 127);
Packit ed3af9
Packit ed3af9
			*(dst_row + dst_offset_x) = gdTrueColorAlpha(red, green, blue, alpha);
Packit ed3af9
Packit ed3af9
			dst_offset_x++;
Packit ed3af9
		}
Packit ed3af9
		dst_offset_y++;
Packit ed3af9
	}
Packit ed3af9
	return dst;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageScale
Packit ed3af9
 *
Packit ed3af9
 * Scale an image
Packit ed3af9
 *
Packit ed3af9
 * Creates a new image, scaled to the requested size using the current
Packit ed3af9
 * <gdInterpolationMethod>.
Packit ed3af9
 *
Packit ed3af9
 * Note that GD_WEIGHTED4 is not yet supported by this function.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src        - The source image.
Packit ed3af9
 *   new_width  - The new width.
Packit ed3af9
 *   new_height - The new height.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   The scaled image on success, NULL on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageCopyResized>
Packit ed3af9
 *   - <gdImageCopyResampled>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageScale(const gdImagePtr src, const unsigned int new_width, const unsigned int new_height)
Packit ed3af9
{
Packit ed3af9
	gdImagePtr im_scaled = NULL;
Packit ed3af9
Packit ed3af9
	if (src == NULL || (uintmax_t)src->interpolation_id >= GD_METHOD_COUNT) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (new_width == 0 || new_height == 0) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
	if (new_width == gdImageSX(src) && new_height == gdImageSY(src)) {
Packit ed3af9
		return gdImageClone(src);
Packit ed3af9
	}
Packit ed3af9
	switch (src->interpolation_id) {
Packit ed3af9
		/*Special cases, optimized implementations */
Packit ed3af9
		case GD_NEAREST_NEIGHBOUR:
Packit ed3af9
			im_scaled = gdImageScaleNearestNeighbour(src, new_width, new_height);
Packit ed3af9
			break;
Packit ed3af9
Packit ed3af9
		case GD_BILINEAR_FIXED:
Packit ed3af9
		case GD_LINEAR:
Packit ed3af9
			im_scaled = gdImageScaleBilinear(src, new_width, new_height);
Packit ed3af9
			break;
Packit ed3af9
Packit ed3af9
		case GD_BICUBIC_FIXED:
Packit ed3af9
		case GD_BICUBIC:
Packit ed3af9
			im_scaled = gdImageScaleBicubicFixed(src, new_width, new_height);
Packit ed3af9
			break;
Packit ed3af9
Packit ed3af9
		/* generic */
Packit ed3af9
		default:
Packit ed3af9
			if (src->interpolation == NULL) {
Packit ed3af9
				return NULL;
Packit ed3af9
			}
Packit ed3af9
			im_scaled = gdImageScaleTwoPass(src, new_width, new_height);
Packit ed3af9
			break;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return im_scaled;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int gdRotatedImageSize(gdImagePtr src, const float angle, gdRectPtr bbox)
Packit ed3af9
{
Packit ed3af9
    gdRect src_area;
Packit ed3af9
    double m[6];
Packit ed3af9
Packit ed3af9
    gdAffineRotate(m, angle);
Packit ed3af9
    src_area.x = 0;
Packit ed3af9
    src_area.y = 0;
Packit ed3af9
    src_area.width = gdImageSX(src);
Packit ed3af9
    src_area.height = gdImageSY(src);
Packit ed3af9
    if (gdTransformAffineBoundingBox(&src_area, m, bbox) != GD_TRUE) {
Packit ed3af9
        return GD_FALSE;
Packit ed3af9
    }
Packit ed3af9
Packit ed3af9
    return GD_TRUE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static gdImagePtr 
Packit ed3af9
gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees,
Packit ed3af9
                              const int bgColor)
Packit ed3af9
{
Packit ed3af9
	float _angle = ((float) (-degrees / 180.0f) * (float)M_PI);
Packit ed3af9
	const int src_w  = gdImageSX(src);
Packit ed3af9
	const int src_h = gdImageSY(src);
Packit ed3af9
	const gdFixed f_0_5 = gd_ftofx(0.5f);
Packit ed3af9
	const gdFixed f_H = gd_itofx(src_h/2);
Packit ed3af9
	const gdFixed f_W = gd_itofx(src_w/2);
Packit ed3af9
	const gdFixed f_cos = gd_ftofx(cos(-_angle));
Packit ed3af9
	const gdFixed f_sin = gd_ftofx(sin(-_angle));
Packit ed3af9
Packit ed3af9
	unsigned int dst_offset_x;
Packit ed3af9
	unsigned int dst_offset_y = 0;
Packit ed3af9
	unsigned int i;
Packit ed3af9
	gdImagePtr dst;
Packit ed3af9
	gdRect bbox;
Packit ed3af9
	int new_height, new_width;
Packit ed3af9
Packit ed3af9
    gdRotatedImageSize(src, degrees, &bbox);
Packit ed3af9
    new_width = bbox.width;
Packit ed3af9
    new_height = bbox.height;
Packit ed3af9
Packit ed3af9
	dst = gdImageCreateTrueColor(new_width, new_height);
Packit ed3af9
	if (!dst) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
	dst->saveAlphaFlag = 1;
Packit ed3af9
	for (i = 0; i < new_height; i++) {
Packit ed3af9
		unsigned int j;
Packit ed3af9
		dst_offset_x = 0;
Packit ed3af9
		for (j = 0; j < new_width; j++) {
Packit ed3af9
			gdFixed f_i = gd_itofx((int)i - (int)new_height / 2);
Packit ed3af9
			gdFixed f_j = gd_itofx((int)j - (int)new_width  / 2);
Packit ed3af9
			gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_0_5 + f_H;
Packit ed3af9
			gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin) + f_0_5 + f_W;
Packit ed3af9
			long m = gd_fxtoi(f_m);
Packit ed3af9
			long n = gd_fxtoi(f_n);
Packit ed3af9
Packit ed3af9
			if ((m > 0) && (m < src_h-1) && (n > 0) && (n < src_w-1)) {
Packit ed3af9
				if (dst_offset_y < new_height) {
Packit ed3af9
					dst->tpixels[dst_offset_y][dst_offset_x++] = src->tpixels[m][n];
Packit ed3af9
				}
Packit ed3af9
			} else {
Packit ed3af9
				if (dst_offset_y < new_height) {
Packit ed3af9
					dst->tpixels[dst_offset_y][dst_offset_x++] = bgColor;
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		dst_offset_y++;
Packit ed3af9
	}
Packit ed3af9
	return dst;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static gdImagePtr
Packit ed3af9
gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor)
Packit ed3af9
{
Packit ed3af9
	float _angle = ((float) (-degrees / 180.0f) * (float)M_PI);
Packit ed3af9
	const int src_w  = gdImageSX(src);
Packit ed3af9
	const int src_h = gdImageSY(src);
Packit ed3af9
	const gdFixed f_H = gd_itofx(src_h/2);
Packit ed3af9
	const gdFixed f_W = gd_itofx(src_w/2);
Packit ed3af9
	const gdFixed f_cos = gd_ftofx(cos(-_angle));
Packit ed3af9
	const gdFixed f_sin = gd_ftofx(sin(-_angle));
Packit ed3af9
Packit ed3af9
	unsigned int dst_offset_x;
Packit ed3af9
	unsigned int dst_offset_y = 0;
Packit ed3af9
	unsigned int i;
Packit ed3af9
	gdImagePtr dst;
Packit ed3af9
	int new_width, new_height;
Packit ed3af9
	gdRect bbox;
Packit ed3af9
Packit ed3af9
	if (bgColor < 0) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (src->interpolation == NULL) {
Packit ed3af9
		gdImageSetInterpolationMethod(src, GD_DEFAULT);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
    gdRotatedImageSize(src, degrees, &bbox);
Packit ed3af9
    new_width = bbox.width;
Packit ed3af9
    new_height = bbox.height;
Packit ed3af9
Packit ed3af9
	dst = gdImageCreateTrueColor(new_width, new_height);
Packit ed3af9
	if (!dst) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
	dst->saveAlphaFlag = 1;
Packit ed3af9
Packit ed3af9
	for (i = 0; i < new_height; i++) {
Packit ed3af9
		unsigned int j;
Packit ed3af9
		dst_offset_x = 0;
Packit ed3af9
		for (j = 0; j < new_width; j++) {
Packit ed3af9
			gdFixed f_i = gd_itofx((int)i - (int)new_height / 2);
Packit ed3af9
			gdFixed f_j = gd_itofx((int)j - (int)new_width  / 2);
Packit ed3af9
			gdFixed f_m = gd_mulfx(f_j,f_sin) + gd_mulfx(f_i,f_cos) + f_H;
Packit ed3af9
			gdFixed f_n = gd_mulfx(f_j,f_cos) - gd_mulfx(f_i,f_sin)  + f_W;
Packit ed3af9
			long m = gd_fxtoi(f_m);
Packit ed3af9
			long n = gd_fxtoi(f_n);
Packit ed3af9
Packit ed3af9
			if (m < -1 || n < -1 || m >= src_h || n >= src_w ) {
Packit ed3af9
				dst->tpixels[dst_offset_y][dst_offset_x++] = bgColor;
Packit ed3af9
			} else {
Packit ed3af9
				dst->tpixels[dst_offset_y][dst_offset_x++] = getPixelInterpolated(src, gd_fxtod(f_n), gd_fxtod(f_m), bgColor);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		dst_offset_y++;
Packit ed3af9
	}
Packit ed3af9
	return dst;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/** 
Packit ed3af9
 * Function: gdImageRotateInterpolated
Packit ed3af9
 *
Packit ed3af9
 * Rotate an image
Packit ed3af9
 *
Packit ed3af9
 * Creates a new image, counter-clockwise rotated by the requested angle
Packit ed3af9
 * using the current <gdInterpolationMethod>. Non-square angles will add a
Packit ed3af9
 * border with bgcolor.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   src     - The source image.
Packit ed3af9
 *   angle   - The angle in degrees.
Packit ed3af9
 *   bgcolor - The color to fill the added background with.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   The rotated image on success, NULL on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdImageCopyRotated>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor)
Packit ed3af9
{
Packit ed3af9
	/* round to two decimals and keep the 100x multiplication to use it in the common square angles 
Packit ed3af9
	   case later. Keep the two decimal precisions so smaller rotation steps can be done, useful for
Packit ed3af9
	   slow animations, f.e. */
Packit ed3af9
	const int angle_rounded = fmod((int) floorf(angle * 100), 360 * 100);
Packit ed3af9
Packit ed3af9
	if (src == NULL || bgcolor < 0) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* impact perf a bit, but not that much. Implementation for palette
Packit ed3af9
	   images can be done at a later point.
Packit ed3af9
	*/
Packit ed3af9
	if (src->trueColor == 0) {
Packit ed3af9
		if (bgcolor < gdMaxColors) {
Packit ed3af9
			bgcolor =  gdTrueColorAlpha(src->red[bgcolor], src->green[bgcolor], src->blue[bgcolor], src->alpha[bgcolor]);
Packit ed3af9
		}
Packit ed3af9
		gdImagePaletteToTrueColor(src);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* 0 && 90 degrees multiple rotation, 0 rotation simply clones the return image and convert it
Packit ed3af9
	   to truecolor, as we must return truecolor image. */
Packit ed3af9
	switch (angle_rounded) {
Packit ed3af9
		case    0: {
Packit ed3af9
			gdImagePtr dst = gdImageClone(src);
Packit ed3af9
Packit ed3af9
			if (dst == NULL) {
Packit ed3af9
				return NULL;
Packit ed3af9
			}
Packit ed3af9
			if (dst->trueColor == 0) {
Packit ed3af9
				gdImagePaletteToTrueColor(dst);
Packit ed3af9
			}
Packit ed3af9
			return dst;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		case -27000:
Packit ed3af9
		case   9000:
Packit ed3af9
			return gdImageRotate90(src, 0);
Packit ed3af9
Packit ed3af9
		case -18000:
Packit ed3af9
		case  18000:
Packit ed3af9
			return gdImageRotate180(src, 0);
Packit ed3af9
Packit ed3af9
		case  -9000:
Packit ed3af9
		case  27000:
Packit ed3af9
			return gdImageRotate270(src, 0);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (src->interpolation_id < 1 || src->interpolation_id > GD_METHOD_COUNT) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	switch (src->interpolation_id) {
Packit ed3af9
		case GD_NEAREST_NEIGHBOUR:
Packit ed3af9
			return gdImageRotateNearestNeighbour(src, angle, bgcolor);
Packit ed3af9
			break;
Packit ed3af9
Packit ed3af9
		case GD_BILINEAR_FIXED:
Packit ed3af9
		case GD_BICUBIC_FIXED:
Packit ed3af9
		default:
Packit ed3af9
			return gdImageRotateGeneric(src, angle, bgcolor);
Packit ed3af9
	}
Packit ed3af9
	return NULL;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Group: Affine Transformation
Packit ed3af9
 **/
Packit ed3af9
Packit ed3af9
 static void gdImageClipRectangle(gdImagePtr im, gdRectPtr r)
Packit ed3af9
{
Packit ed3af9
	int c1x, c1y, c2x, c2y;
Packit ed3af9
	int x1,y1;
Packit ed3af9
Packit ed3af9
	gdImageGetClip(im, &c1x, &c1y, &c2x, &c2y);
Packit ed3af9
	x1 = r->x + r->width - 1;
Packit ed3af9
	y1 = r->y + r->height - 1;
Packit ed3af9
	r->x = CLAMP(r->x, c1x, c2x);
Packit ed3af9
	r->y = CLAMP(r->y, c1y, c2y);
Packit ed3af9
	r->width = CLAMP(x1, c1x, c2x) - r->x + 1;
Packit ed3af9
	r->height = CLAMP(y1, c1y, c2y) - r->y + 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
void gdDumpRect(const char *msg, gdRectPtr r)
Packit ed3af9
{
Packit ed3af9
	printf("%s (%i, %i) (%i, %i)\n", msg, r->x, r->y, r->width, r->height);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdTransformAffineGetImage
Packit ed3af9
 *  Applies an affine transformation to a region and return an image
Packit ed3af9
 *  containing the complete transformation.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 * 	dst - Pointer to a gdImagePtr to store the created image, NULL when
Packit ed3af9
 *        the creation or the transformation failed
Packit ed3af9
 *  src - Source image
Packit ed3af9
 *  src_area - rectangle defining the source region to transform
Packit ed3af9
 *  dstY - Y position in the destination image
Packit ed3af9
 *  affine - The desired affine transformation
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *  GD_TRUE if the affine is rectilinear or GD_FALSE
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdTransformAffineGetImage(gdImagePtr *dst,
Packit ed3af9
		  const gdImagePtr src,
Packit ed3af9
		  gdRectPtr src_area,
Packit ed3af9
		  const double affine[6])
Packit ed3af9
{
Packit ed3af9
	int res;
Packit ed3af9
	double m[6];
Packit ed3af9
	gdRect bbox;
Packit ed3af9
	gdRect area_full;
Packit ed3af9
Packit ed3af9
	if (src_area == NULL) {
Packit ed3af9
		area_full.x = 0;
Packit ed3af9
		area_full.y = 0;
Packit ed3af9
		area_full.width  = gdImageSX(src);
Packit ed3af9
		area_full.height = gdImageSY(src);
Packit ed3af9
		src_area = &area_full;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	gdTransformAffineBoundingBox(src_area, affine, &bbox);
Packit ed3af9
Packit ed3af9
	*dst = gdImageCreateTrueColor(bbox.width, bbox.height);
Packit ed3af9
	if (*dst == NULL) {
Packit ed3af9
		return GD_FALSE;
Packit ed3af9
	}
Packit ed3af9
	(*dst)->saveAlphaFlag = 1;
Packit ed3af9
Packit ed3af9
	if (!src->trueColor) {
Packit ed3af9
		gdImagePaletteToTrueColor(src);
Packit ed3af9
	}
Packit ed3af9
	
Packit ed3af9
	/* Translate to dst origin (0,0) */
Packit ed3af9
	gdAffineTranslate(m, -bbox.x, -bbox.y);
Packit ed3af9
	gdAffineConcat(m, affine, m);
Packit ed3af9
Packit ed3af9
	gdImageAlphaBlending(*dst, 0);
Packit ed3af9
Packit ed3af9
	res = gdTransformAffineCopy(*dst,
Packit ed3af9
		  0,0,
Packit ed3af9
		  src,
Packit ed3af9
		  src_area,
Packit ed3af9
		  m);
Packit ed3af9
Packit ed3af9
	if (res != GD_TRUE) {
Packit ed3af9
		gdImageDestroy(*dst);
Packit ed3af9
		*dst = NULL;
Packit ed3af9
		return GD_FALSE;
Packit ed3af9
	} else {
Packit ed3af9
		return GD_TRUE;
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdTransformAffineCopy
Packit ed3af9
 *  Applies an affine transformation to a region and copy the result
Packit ed3af9
 *  in a destination to the given position.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 * 	dst - Image to draw the transformed image
Packit ed3af9
 *  src - Source image
Packit ed3af9
 *  dstX - X position in the destination image
Packit ed3af9
 *  dstY - Y position in the destination image
Packit ed3af9
 *  src_area - Rectangular region to rotate in the src image
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *  GD_TRUE if the affine is rectilinear or GD_FALSE
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst,
Packit ed3af9
		  int dst_x, int dst_y,
Packit ed3af9
		  const gdImagePtr src,
Packit ed3af9
		  gdRectPtr src_region,
Packit ed3af9
		  const double affine[6])
Packit ed3af9
{
Packit ed3af9
	int c1x,c1y,c2x,c2y;
Packit ed3af9
	int backclip = 0;
Packit ed3af9
	int backup_clipx1, backup_clipy1, backup_clipx2, backup_clipy2;
Packit ed3af9
	register int x, y, src_offset_x, src_offset_y;
Packit ed3af9
	double inv[6];
Packit ed3af9
	int *dst_p;
Packit ed3af9
	gdPointF pt, src_pt;
Packit ed3af9
	gdRect bbox;
Packit ed3af9
	int end_x, end_y;
Packit ed3af9
	gdInterpolationMethod interpolation_id_bak = GD_DEFAULT;
Packit ed3af9
Packit ed3af9
	/* These methods use special implementations */
Packit ed3af9
	if (src->interpolation_id == GD_BILINEAR_FIXED || src->interpolation_id == GD_BICUBIC_FIXED || src->interpolation_id == GD_NEAREST_NEIGHBOUR) {
Packit ed3af9
		interpolation_id_bak = src->interpolation_id;
Packit ed3af9
		
Packit ed3af9
		gdImageSetInterpolationMethod(src, GD_BICUBIC);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
Packit ed3af9
	gdImageClipRectangle(src, src_region);
Packit ed3af9
Packit ed3af9
	if (src_region->x > 0 || src_region->y > 0
Packit ed3af9
		|| src_region->width < gdImageSX(src)
Packit ed3af9
		|| src_region->height < gdImageSY(src)) {
Packit ed3af9
		backclip = 1;
Packit ed3af9
Packit ed3af9
		gdImageGetClip(src, &backup_clipx1, &backup_clipy1,
Packit ed3af9
		&backup_clipx2, &backup_clipy2);
Packit ed3af9
Packit ed3af9
		gdImageSetClip(src, src_region->x, src_region->y,
Packit ed3af9
			src_region->x + src_region->width - 1,
Packit ed3af9
			src_region->y + src_region->height - 1);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (!gdTransformAffineBoundingBox(src_region, affine, &bbox)) {
Packit ed3af9
		if (backclip) {
Packit ed3af9
			gdImageSetClip(src, backup_clipx1, backup_clipy1,
Packit ed3af9
					backup_clipx2, backup_clipy2);
Packit ed3af9
		}
Packit ed3af9
		gdImageSetInterpolationMethod(src, interpolation_id_bak);
Packit ed3af9
		return GD_FALSE;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	gdImageGetClip(dst, &c1x, &c1y, &c2x, &c2y);
Packit ed3af9
Packit ed3af9
	end_x = bbox.width  + abs(bbox.x);
Packit ed3af9
	end_y = bbox.height + abs(bbox.y);
Packit ed3af9
Packit ed3af9
	/* Get inverse affine to let us work with destination -> source */
Packit ed3af9
	gdAffineInvert(inv, affine);
Packit ed3af9
Packit ed3af9
	src_offset_x =  src_region->x;
Packit ed3af9
	src_offset_y =  src_region->y;
Packit ed3af9
Packit ed3af9
	if (dst->alphaBlendingFlag) {
Packit ed3af9
		for (y = bbox.y; y <= end_y; y++) {
Packit ed3af9
			pt.y = y + 0.5;
Packit ed3af9
			for (x = 0; x <= end_x; x++) {
Packit ed3af9
				pt.x = x + 0.5;
Packit ed3af9
				gdAffineApplyToPointF(&src_pt, &pt, inv);
Packit ed3af9
				gdImageSetPixel(dst, dst_x + x, dst_y + y, getPixelInterpolated(src, src_offset_x + src_pt.x, src_offset_y + src_pt.y, 0));
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	} else {
Packit ed3af9
		for (y = 0; y <= end_y; y++) {
Packit ed3af9
			pt.y = y + 0.5 + bbox.y;
Packit ed3af9
			if ((dst_y + y) < 0 || ((dst_y + y) > gdImageSY(dst) -1)) {
Packit ed3af9
				continue;
Packit ed3af9
			}
Packit ed3af9
			dst_p = dst->tpixels[dst_y + y] + dst_x;
Packit ed3af9
Packit ed3af9
			for (x = 0; x <= end_x; x++) {
Packit ed3af9
				pt.x = x + 0.5 + bbox.x;
Packit ed3af9
				gdAffineApplyToPointF(&src_pt, &pt, inv);
Packit ed3af9
Packit ed3af9
				if ((dst_x + x) < 0 || (dst_x + x) > (gdImageSX(dst) - 1)) {
Packit ed3af9
					break;
Packit ed3af9
				}
Packit ed3af9
				*(dst_p++) = getPixelInterpolated(src, src_offset_x + src_pt.x, src_offset_y + src_pt.y, -1);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* Restore clip if required */
Packit ed3af9
	if (backclip) {
Packit ed3af9
		gdImageSetClip(src, backup_clipx1, backup_clipy1,
Packit ed3af9
				backup_clipx2, backup_clipy2);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	gdImageSetInterpolationMethod(src, interpolation_id_bak);
Packit ed3af9
	return GD_TRUE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdTransformAffineBoundingBox
Packit ed3af9
 *  Returns the bounding box of an affine transformation applied to a
Packit ed3af9
 *  rectangular area <gdRect>
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 * 	src - Rectangular source area for the affine transformation
Packit ed3af9
 *  affine - the affine transformation
Packit ed3af9
 *  bbox - the resulting bounding box
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *  GD_TRUE if the affine is rectilinear or GD_FALSE
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPtr bbox)
Packit ed3af9
{
Packit ed3af9
	gdPointF extent[4], min, max, point;
Packit ed3af9
	int i;
Packit ed3af9
Packit ed3af9
	extent[0].x=0.0;
Packit ed3af9
	extent[0].y=0.0;
Packit ed3af9
	extent[1].x=(double) src->width;
Packit ed3af9
	extent[1].y=0.0;
Packit ed3af9
	extent[2].x=(double) src->width;
Packit ed3af9
	extent[2].y=(double) src->height;
Packit ed3af9
	extent[3].x=0.0;
Packit ed3af9
	extent[3].y=(double) src->height;
Packit ed3af9
Packit ed3af9
	for (i=0; i < 4; i++) {
Packit ed3af9
		point=extent[i];
Packit ed3af9
		if (gdAffineApplyToPointF(&extent[i], &point, affine) != GD_TRUE) {
Packit ed3af9
			return GD_FALSE;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	min=extent[0];
Packit ed3af9
	max=extent[0];
Packit ed3af9
Packit ed3af9
	for (i=1; i < 4; i++) {
Packit ed3af9
		if (min.x > extent[i].x)
Packit ed3af9
			min.x=extent[i].x;
Packit ed3af9
		if (min.y > extent[i].y)
Packit ed3af9
			min.y=extent[i].y;
Packit ed3af9
		if (max.x < extent[i].x)
Packit ed3af9
			max.x=extent[i].x;
Packit ed3af9
		if (max.y < extent[i].y)
Packit ed3af9
			max.y=extent[i].y;
Packit ed3af9
	}
Packit ed3af9
	bbox->x = (int) min.x;
Packit ed3af9
	bbox->y = (int) min.y;
Packit ed3af9
	bbox->width  = (int) ceil((max.x - min.x)) + 1;
Packit ed3af9
	bbox->height = (int) ceil(max.y - min.y) + 1;
Packit ed3af9
Packit ed3af9
	return GD_TRUE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Group: Interpolation Method
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageSetInterpolationMethod
Packit ed3af9
 *
Packit ed3af9
 * Set the interpolation method for subsequent operations
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   im - The image.
Packit ed3af9
 *   id - The interpolation method.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   Non-zero on success, zero on failure.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdInterpolationMethod>
Packit ed3af9
 *   - <gdImageGetInterpolationMethod>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(int) gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id)
Packit ed3af9
{
Packit ed3af9
	if (im == NULL || (uintmax_t)id > GD_METHOD_COUNT) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	switch (id) {
Packit ed3af9
		case GD_NEAREST_NEIGHBOUR:
Packit ed3af9
		case GD_WEIGHTED4:
Packit ed3af9
			im->interpolation = NULL;
Packit ed3af9
			break;
Packit ed3af9
Packit ed3af9
		/* generic versions*/
Packit ed3af9
		/* GD_BILINEAR_FIXED and GD_BICUBIC_FIXED are kept for BC reasons */
Packit ed3af9
		case GD_BILINEAR_FIXED:
Packit ed3af9
		case GD_LINEAR:
Packit ed3af9
			im->interpolation = filter_linear;
Packit ed3af9
			break;
Packit ed3af9
		case GD_BELL:
Packit ed3af9
			im->interpolation = filter_bell;
Packit ed3af9
			break;
Packit ed3af9
		case GD_BESSEL:
Packit ed3af9
			im->interpolation = filter_bessel;
Packit ed3af9
			break;
Packit ed3af9
		case GD_BICUBIC_FIXED:
Packit ed3af9
		case GD_BICUBIC:
Packit ed3af9
			im->interpolation = filter_bicubic;
Packit ed3af9
			break;
Packit ed3af9
		case GD_BLACKMAN:
Packit ed3af9
			im->interpolation = filter_blackman;
Packit ed3af9
			break;
Packit ed3af9
		case GD_BOX:
Packit ed3af9
			im->interpolation = filter_box;
Packit ed3af9
			break;
Packit ed3af9
		case GD_BSPLINE:
Packit ed3af9
			im->interpolation = filter_bspline;
Packit ed3af9
			break;
Packit ed3af9
		case GD_CATMULLROM:
Packit ed3af9
			im->interpolation = filter_catmullrom;
Packit ed3af9
			break;
Packit ed3af9
		case GD_GAUSSIAN:
Packit ed3af9
			im->interpolation = filter_gaussian;
Packit ed3af9
			break;
Packit ed3af9
		case GD_GENERALIZED_CUBIC:
Packit ed3af9
			im->interpolation = filter_generalized_cubic;
Packit ed3af9
			break;
Packit ed3af9
		case GD_HERMITE:
Packit ed3af9
			im->interpolation = filter_hermite;
Packit ed3af9
			break;
Packit ed3af9
		case GD_HAMMING:
Packit ed3af9
			im->interpolation = filter_hamming;
Packit ed3af9
			break;
Packit ed3af9
		case GD_HANNING:
Packit ed3af9
			im->interpolation = filter_hanning;
Packit ed3af9
			break;
Packit ed3af9
		case GD_MITCHELL:
Packit ed3af9
			im->interpolation = filter_mitchell;
Packit ed3af9
			break;
Packit ed3af9
		case GD_POWER:
Packit ed3af9
			im->interpolation = filter_power;
Packit ed3af9
			break;
Packit ed3af9
		case GD_QUADRATIC:
Packit ed3af9
			im->interpolation = filter_quadratic;
Packit ed3af9
			break;
Packit ed3af9
		case GD_SINC:
Packit ed3af9
			im->interpolation = filter_sinc;
Packit ed3af9
			break;
Packit ed3af9
		case GD_TRIANGLE:
Packit ed3af9
			im->interpolation = filter_triangle;
Packit ed3af9
			break;
Packit ed3af9
		case GD_DEFAULT:
Packit ed3af9
			id = GD_LINEAR;
Packit ed3af9
			im->interpolation = filter_linear;
Packit ed3af9
		default:
Packit ed3af9
			return 0;
Packit ed3af9
			break;
Packit ed3af9
	}
Packit ed3af9
	im->interpolation_id = id;
Packit ed3af9
	return 1;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageGetInterpolationMethod
Packit ed3af9
 *
Packit ed3af9
 * Get the current interpolation method
Packit ed3af9
 *
Packit ed3af9
 * This is here so that the value can be read via a language or VM with an FFI
Packit ed3af9
 * but no (portable) way to extract the value from the struct.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *   im - The image.
Packit ed3af9
 *
Packit ed3af9
 * Returns:
Packit ed3af9
 *   The current interpolation method.
Packit ed3af9
 *
Packit ed3af9
 * See also:
Packit ed3af9
 *   - <gdInterpolationMethod>
Packit ed3af9
 *   - <gdImageSetInterpolationMethod>
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(gdInterpolationMethod) gdImageGetInterpolationMethod(gdImagePtr im)
Packit ed3af9
{
Packit ed3af9
    return im->interpolation_id;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#ifdef _MSC_VER
Packit ed3af9
# pragma optimize("", on)
Packit ed3af9
#endif