Blame src/gd_interpolation.c

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