diff options
| author | George Hazan <george.hazan@gmail.com> | 2012-05-30 17:27:49 +0000 | 
|---|---|---|
| committer | George Hazan <george.hazan@gmail.com> | 2012-05-30 17:27:49 +0000 | 
| commit | 88708cffa15662dcd2755fce699112d24a10a087 (patch) | |
| tree | 55d362220b42a52b52eaef2254f894c9a61fb4fd /plugins/FreeImage/Source/FreeImageToolkit/BSplineRotate.cpp | |
| parent | 7fa5563a954339f3feeb156285ef56bfde7cbec8 (diff) | |
update for zlib & FreeImage
git-svn-id: http://svn.miranda-ng.org/main/trunk@238 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/FreeImage/Source/FreeImageToolkit/BSplineRotate.cpp')
| -rw-r--r-- | plugins/FreeImage/Source/FreeImageToolkit/BSplineRotate.cpp | 1460 | 
1 files changed, 730 insertions, 730 deletions
diff --git a/plugins/FreeImage/Source/FreeImageToolkit/BSplineRotate.cpp b/plugins/FreeImage/Source/FreeImageToolkit/BSplineRotate.cpp index ed468b4dac..690db87d8c 100644 --- a/plugins/FreeImage/Source/FreeImageToolkit/BSplineRotate.cpp +++ b/plugins/FreeImage/Source/FreeImageToolkit/BSplineRotate.cpp @@ -1,730 +1,730 @@ -// ==========================================================
 -// Bitmap rotation using B-Splines
 -//
 -// Design and implementation by
 -// - Philippe Thévenaz (philippe.thevenaz@epfl.ch)
 -// Adaptation for FreeImage by
 -// - Hervé Drolon (drolon@infonie.fr)
 -//
 -// This file is part of FreeImage 3
 -//
 -// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 -// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 -// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 -// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 -// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 -// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 -// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 -// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 -// THIS DISCLAIMER.
 -//
 -// Use at your own risk!
 -// ==========================================================
 -
 -/* 
 -==========================================================
 -This code was taken and adapted from the following reference : 
 -
 -[1] Philippe Thévenaz, Spline interpolation, a C source code 
 -implementation. http://bigwww.epfl.ch/thevenaz/
 -
 -It implements ideas described in the following papers : 
 -
 -[2] Unser M., Splines: A Perfect Fit for Signal and Image Processing. 
 -IEEE Signal Processing Magazine, vol. 16, no. 6, pp. 22-38, November 1999. 
 -
 -[3] Unser M., Aldroubi A., Eden M., B-Spline Signal Processing: Part I--Theory.
 -IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 821-832, February 1993. 
 -
 -[4] Unser M., Aldroubi A., Eden M., B-Spline Signal Processing: Part II--Efficient Design and Applications.
 -IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 834-848, February 1993.
 -
 -========================================================== 
 -*/
 -
 -
 -#include <float.h>
 -#include "FreeImage.h"
 -#include "Utilities.h"
 -
 -#define PI	((double)3.14159265358979323846264338327950288419716939937510)
 -
 -#define ROTATE_QUADRATIC 2L	// Use B-splines of degree 2 (quadratic interpolation)
 -#define ROTATE_CUBIC     3L	// Use B-splines of degree 3 (cubic interpolation)
 -#define ROTATE_QUARTIC   4L	// Use B-splines of degree 4 (quartic interpolation)
 -#define ROTATE_QUINTIC   5L	// Use B-splines of degree 5 (quintic interpolation)
 -
 -
 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////
 -// Prototypes definition
 -
 -static void ConvertToInterpolationCoefficients(double *c, long DataLength, double *z, long NbPoles,	double Tolerance);
 -static double InitialCausalCoefficient(double *c, long DataLength, double z, double Tolerance);
 -static void GetColumn(double *Image, long Width, long x, double *Line, long Height);
 -static void	GetRow(double *Image, long y, double *Line, long Width);
 -static double InitialAntiCausalCoefficient(double *c, long DataLength, double z);
 -static void	PutColumn(double *Image, long Width, long x, double *Line, long Height);
 -static void	PutRow(double *Image, long y, double *Line, long Width);
 -static bool SamplesToCoefficients(double *Image, long Width, long Height, long spline_degree);
 -static double InterpolatedValue(double *Bcoeff, long Width, long Height, double x, double y, long spline_degree);
 -
 -static FIBITMAP * Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, long spline_degree, BOOL use_mask);
 -
 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////
 -// Coefficients routines
 -
 -/**
 - ConvertToInterpolationCoefficients
 -
 - @param c Input samples --> output coefficients
 - @param DataLength Number of samples or coefficients
 - @param z Poles
 - @param NbPoles Number of poles
 - @param Tolerance Admissible relative error
 -*/
 -static void 
 -ConvertToInterpolationCoefficients(double *c, long DataLength, double *z, long NbPoles,	double Tolerance) {
 -	double	Lambda = 1;
 -	long	n, k;
 -
 -	// special case required by mirror boundaries
 -	if(DataLength == 1L) {
 -		return;
 -	}
 -	// compute the overall gain
 -	for(k = 0L; k < NbPoles; k++) {
 -		Lambda = Lambda * (1.0 - z[k]) * (1.0 - 1.0 / z[k]);
 -	}
 -	// apply the gain 
 -	for (n = 0L; n < DataLength; n++) {
 -		c[n] *= Lambda;
 -	}
 -	// loop over all poles 
 -	for (k = 0L; k < NbPoles; k++) {
 -		// causal initialization 
 -		c[0] = InitialCausalCoefficient(c, DataLength, z[k], Tolerance);
 -		// causal recursion 
 -		for (n = 1L; n < DataLength; n++) {
 -			c[n] += z[k] * c[n - 1L];
 -		}
 -		// anticausal initialization 
 -		c[DataLength - 1L] = InitialAntiCausalCoefficient(c, DataLength, z[k]);
 -		// anticausal recursion 
 -		for (n = DataLength - 2L; 0 <= n; n--) {
 -			c[n] = z[k] * (c[n + 1L] - c[n]);
 -		}
 -	}
 -} 
 -
 -/**
 - InitialCausalCoefficient
 -
 - @param c Coefficients
 - @param DataLength Number of coefficients
 - @param z Actual pole
 - @param Tolerance Admissible relative error
 - @return
 -*/
 -static double 
 -InitialCausalCoefficient(double	*c, long DataLength, double	z, double Tolerance) {
 -	double	Sum, zn, z2n, iz;
 -	long	n, Horizon;
 -
 -	// this initialization corresponds to mirror boundaries 
 -	Horizon = DataLength;
 -	if(Tolerance > 0) {
 -		Horizon = (long)ceil(log(Tolerance) / log(fabs(z)));
 -	}
 -	if(Horizon < DataLength) {
 -		// accelerated loop
 -		zn = z;
 -		Sum = c[0];
 -		for (n = 1L; n < Horizon; n++) {
 -			Sum += zn * c[n];
 -			zn *= z;
 -		}
 -		return(Sum);
 -	}
 -	else {
 -		// full loop 
 -		zn = z;
 -		iz = 1.0 / z;
 -		z2n = pow(z, (double)(DataLength - 1L));
 -		Sum = c[0] + z2n * c[DataLength - 1L];
 -		z2n *= z2n * iz;
 -		for (n = 1L; n <= DataLength - 2L; n++) {
 -			Sum += (zn + z2n) * c[n];
 -			zn *= z;
 -			z2n *= iz;
 -		}
 -		return(Sum / (1.0 - zn * zn));
 -	}
 -}
 -
 -/**
 - GetColumn
 -
 - @param Image Input image array
 - @param Width Width of the image
 - @param x x coordinate of the selected line
 - @param Line Output linear array
 - @param Height Length of the line
 -*/
 -static void 
 -GetColumn(double *Image, long Width, long x, double *Line, long Height) {
 -	long y;
 -
 -	Image = Image + x;
 -	for(y = 0L; y < Height; y++) {
 -		Line[y] = (double)*Image;
 -		Image += Width;
 -	}
 -}
 -
 -/**
 - GetRow
 -
 - @param Image Input image array
 - @param y y coordinate of the selected line
 - @param Line Output linear array
 - @param Width Length of the line
 -*/
 -static void	
 -GetRow(double *Image, long y, double *Line, long Width) {
 -	long	x;
 -
 -	Image = Image + (y * Width);
 -	for(x = 0L; x < Width; x++) {
 -		Line[x] = (double)*Image++;
 -	}
 -}
 -
 -/**
 - InitialAntiCausalCoefficient
 -
 - @param c Coefficients
 - @param DataLength Number of samples or coefficients
 - @param z Actual pole
 - @return
 -*/
 -static double 
 -InitialAntiCausalCoefficient(double	*c, long DataLength, double	z) {
 -	// this initialization corresponds to mirror boundaries
 -	return((z / (z * z - 1.0)) * (z * c[DataLength - 2L] + c[DataLength - 1L]));
 -}
 -
 -/**
 - PutColumn
 -
 - @param Image Output image array
 - @param Width Width of the image
 - @param x x coordinate of the selected line
 - @param Line Input linear array
 - @param Height Length of the line and height of the image
 -*/
 -static void	
 -PutColumn(double *Image, long Width, long x, double *Line, long Height) {
 -	long	y;
 -
 -	Image = Image + x;
 -	for(y = 0L; y < Height; y++) {
 -		*Image = (double)Line[y];
 -		Image += Width;
 -	}
 -}
 -
 -/**
 - PutRow
 -
 - @param Image Output image array
 - @param y y coordinate of the selected line
 - @param Line Input linear array
 - @param Width length of the line and width of the image
 -*/
 -static void	
 -PutRow(double *Image, long y, double *Line, long Width) {
 -	long	x;
 -
 -	Image = Image + (y * Width);
 -	for(x = 0L; x < Width; x++) {
 -		*Image++ = (double)Line[x];
 -	}
 -}
 -
 -/**
 - SamplesToCoefficients.<br>
 - Implement the algorithm that converts the image samples into B-spline coefficients. 
 - This efficient procedure essentially relies on the three papers cited above; 
 - data are processed in-place. 
 - Even though this algorithm is robust with respect to quantization, 
 - we advocate the use of a floating-point format for the data. 
 -
 - @param Image Input / Output image (in-place processing)
 - @param Width Width of the image
 - @param Height Height of the image
 - @param spline_degree Degree of the spline model
 - @return Returns true if success, false otherwise
 -*/
 -static bool	
 -SamplesToCoefficients(double *Image, long Width, long Height, long spline_degree) {
 -	double	*Line;
 -	double	Pole[2];
 -	long	NbPoles;
 -	long	x, y;
 -
 -	// recover the poles from a lookup table
 -	switch (spline_degree) {
 -		case 2L:
 -			NbPoles = 1L;
 -			Pole[0] = sqrt(8.0) - 3.0;
 -			break;
 -		case 3L:
 -			NbPoles = 1L;
 -			Pole[0] = sqrt(3.0) - 2.0;
 -			break;
 -		case 4L:
 -			NbPoles = 2L;
 -			Pole[0] = sqrt(664.0 - sqrt(438976.0)) + sqrt(304.0) - 19.0;
 -			Pole[1] = sqrt(664.0 + sqrt(438976.0)) - sqrt(304.0) - 19.0;
 -			break;
 -		case 5L:
 -			NbPoles = 2L;
 -			Pole[0] = sqrt(135.0 / 2.0 - sqrt(17745.0 / 4.0)) + sqrt(105.0 / 4.0)
 -				- 13.0 / 2.0;
 -			Pole[1] = sqrt(135.0 / 2.0 + sqrt(17745.0 / 4.0)) - sqrt(105.0 / 4.0)
 -				- 13.0 / 2.0;
 -			break;
 -		default:
 -			// Invalid spline degree
 -			return false;
 -	}
 -
 -	// convert the image samples into interpolation coefficients 
 -
 -	// in-place separable process, along x 
 -	Line = (double *)malloc(Width * sizeof(double));
 -	if (Line == NULL) {
 -		// Row allocation failed
 -		return false;
 -	}
 -	for (y = 0L; y < Height; y++) {
 -		GetRow(Image, y, Line, Width);
 -		ConvertToInterpolationCoefficients(Line, Width, Pole, NbPoles, DBL_EPSILON);
 -		PutRow(Image, y, Line, Width);
 -	}
 -	free(Line);
 -
 -	// in-place separable process, along y 
 -	Line = (double *)malloc(Height * sizeof(double));
 -	if (Line == NULL) {
 -		// Column allocation failed
 -		return false;
 -	}
 -	for (x = 0L; x < Width; x++) {
 -		GetColumn(Image, Width, x, Line, Height);
 -		ConvertToInterpolationCoefficients(Line, Height, Pole, NbPoles, DBL_EPSILON);
 -		PutColumn(Image, Width, x, Line, Height);
 -	}
 -	free(Line);
 -
 -	return true;
 -}
 -
 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////
 -// Interpolation routines
 -
 -/**
 -Perform the bidimensional interpolation of an image.
 -Given an array of spline coefficients, return the value of 
 -the underlying continuous spline model, sampled at the location (x, y). 
 -The model degree can be 2 (quadratic), 3 (cubic), 4 (quartic), or 5 (quintic).
 -
 -@param Bcoeff Input B-spline array of coefficients
 -@param Width Width of the image
 -@param Height Height of the image
 -@param x x coordinate where to interpolate
 -@param y y coordinate where to interpolate
 -@param spline_degree Degree of the spline model
 -@return Returns the value of the underlying continuous spline model, 
 -sampled at the location (x, y)
 -*/
 -static double 
 -InterpolatedValue(double *Bcoeff, long Width, long Height, double x, double y, long spline_degree) {
 -	double	*p;
 -	double	xWeight[6], yWeight[6];
 -	double	interpolated;
 -	double	w, w2, w4, t, t0, t1;
 -	long	xIndex[6], yIndex[6];
 -	long	Width2 = 2L * Width - 2L, Height2 = 2L * Height - 2L;
 -	long	i, j, k;
 -
 -	// compute the interpolation indexes
 -	if (spline_degree & 1L) {
 -		i = (long)floor(x) - spline_degree / 2L;
 -		j = (long)floor(y) - spline_degree / 2L;
 -		for(k = 0; k <= spline_degree; k++) {
 -			xIndex[k] = i++;
 -			yIndex[k] = j++;
 -		}
 -	}
 -	else {
 -		i = (long)floor(x + 0.5) - spline_degree / 2L;
 -		j = (long)floor(y + 0.5) - spline_degree / 2L;
 -		for (k = 0; k <= spline_degree; k++) {
 -			xIndex[k] = i++;
 -			yIndex[k] = j++;
 -		}
 -	}
 -
 -	// compute the interpolation weights
 -	switch (spline_degree) {
 -		case 2L:
 -			/* x */
 -			w = x - (double)xIndex[1];
 -			xWeight[1] = 3.0 / 4.0 - w * w;
 -			xWeight[2] = (1.0 / 2.0) * (w - xWeight[1] + 1.0);
 -			xWeight[0] = 1.0 - xWeight[1] - xWeight[2];
 -			/* y */
 -			w = y - (double)yIndex[1];
 -			yWeight[1] = 3.0 / 4.0 - w * w;
 -			yWeight[2] = (1.0 / 2.0) * (w - yWeight[1] + 1.0);
 -			yWeight[0] = 1.0 - yWeight[1] - yWeight[2];
 -			break;
 -		case 3L:
 -			/* x */
 -			w = x - (double)xIndex[1];
 -			xWeight[3] = (1.0 / 6.0) * w * w * w;
 -			xWeight[0] = (1.0 / 6.0) + (1.0 / 2.0) * w * (w - 1.0) - xWeight[3];
 -			xWeight[2] = w + xWeight[0] - 2.0 * xWeight[3];
 -			xWeight[1] = 1.0 - xWeight[0] - xWeight[2] - xWeight[3];
 -			/* y */
 -			w = y - (double)yIndex[1];
 -			yWeight[3] = (1.0 / 6.0) * w * w * w;
 -			yWeight[0] = (1.0 / 6.0) + (1.0 / 2.0) * w * (w - 1.0) - yWeight[3];
 -			yWeight[2] = w + yWeight[0] - 2.0 * yWeight[3];
 -			yWeight[1] = 1.0 - yWeight[0] - yWeight[2] - yWeight[3];
 -			break;
 -		case 4L:
 -			/* x */
 -			w = x - (double)xIndex[2];
 -			w2 = w * w;
 -			t = (1.0 / 6.0) * w2;
 -			xWeight[0] = 1.0 / 2.0 - w;
 -			xWeight[0] *= xWeight[0];
 -			xWeight[0] *= (1.0 / 24.0) * xWeight[0];
 -			t0 = w * (t - 11.0 / 24.0);
 -			t1 = 19.0 / 96.0 + w2 * (1.0 / 4.0 - t);
 -			xWeight[1] = t1 + t0;
 -			xWeight[3] = t1 - t0;
 -			xWeight[4] = xWeight[0] + t0 + (1.0 / 2.0) * w;
 -			xWeight[2] = 1.0 - xWeight[0] - xWeight[1] - xWeight[3] - xWeight[4];
 -			/* y */
 -			w = y - (double)yIndex[2];
 -			w2 = w * w;
 -			t = (1.0 / 6.0) * w2;
 -			yWeight[0] = 1.0 / 2.0 - w;
 -			yWeight[0] *= yWeight[0];
 -			yWeight[0] *= (1.0 / 24.0) * yWeight[0];
 -			t0 = w * (t - 11.0 / 24.0);
 -			t1 = 19.0 / 96.0 + w2 * (1.0 / 4.0 - t);
 -			yWeight[1] = t1 + t0;
 -			yWeight[3] = t1 - t0;
 -			yWeight[4] = yWeight[0] + t0 + (1.0 / 2.0) * w;
 -			yWeight[2] = 1.0 - yWeight[0] - yWeight[1] - yWeight[3] - yWeight[4];
 -			break;
 -		case 5L:
 -			/* x */
 -			w = x - (double)xIndex[2];
 -			w2 = w * w;
 -			xWeight[5] = (1.0 / 120.0) * w * w2 * w2;
 -			w2 -= w;
 -			w4 = w2 * w2;
 -			w -= 1.0 / 2.0;
 -			t = w2 * (w2 - 3.0);
 -			xWeight[0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - xWeight[5];
 -			t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0);
 -			t1 = (-1.0 / 12.0) * w * (t + 4.0);
 -			xWeight[2] = t0 + t1;
 -			xWeight[3] = t0 - t1;
 -			t0 = (1.0 / 16.0) * (9.0 / 5.0 - t);
 -			t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0);
 -			xWeight[1] = t0 + t1;
 -			xWeight[4] = t0 - t1;
 -			/* y */
 -			w = y - (double)yIndex[2];
 -			w2 = w * w;
 -			yWeight[5] = (1.0 / 120.0) * w * w2 * w2;
 -			w2 -= w;
 -			w4 = w2 * w2;
 -			w -= 1.0 / 2.0;
 -			t = w2 * (w2 - 3.0);
 -			yWeight[0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - yWeight[5];
 -			t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0);
 -			t1 = (-1.0 / 12.0) * w * (t + 4.0);
 -			yWeight[2] = t0 + t1;
 -			yWeight[3] = t0 - t1;
 -			t0 = (1.0 / 16.0) * (9.0 / 5.0 - t);
 -			t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0);
 -			yWeight[1] = t0 + t1;
 -			yWeight[4] = t0 - t1;
 -			break;
 -		default:
 -			// Invalid spline degree
 -			return 0;
 -	}
 -
 -	// apply the mirror boundary conditions
 -	for(k = 0; k <= spline_degree; k++) {
 -		xIndex[k] = (Width == 1L) ? (0L) : ((xIndex[k] < 0L) ?
 -			(-xIndex[k] - Width2 * ((-xIndex[k]) / Width2))
 -			: (xIndex[k] - Width2 * (xIndex[k] / Width2)));
 -		if (Width <= xIndex[k]) {
 -			xIndex[k] = Width2 - xIndex[k];
 -		}
 -		yIndex[k] = (Height == 1L) ? (0L) : ((yIndex[k] < 0L) ?
 -			(-yIndex[k] - Height2 * ((-yIndex[k]) / Height2))
 -			: (yIndex[k] - Height2 * (yIndex[k] / Height2)));
 -		if (Height <= yIndex[k]) {
 -			yIndex[k] = Height2 - yIndex[k];
 -		}
 -	}
 -
 -	// perform interpolation
 -	interpolated = 0.0;
 -	for(j = 0; j <= spline_degree; j++) {
 -		p = Bcoeff + (yIndex[j] * Width);
 -		w = 0.0;
 -		for(i = 0; i <= spline_degree; i++) {
 -			w += xWeight[i] * p[xIndex[i]];
 -		}
 -		interpolated += yWeight[j] * w;
 -	}
 -
 -	return interpolated;
 -}
 -
 -/////////////////////////////////////////////////////////////////////////////////////////////////////////////
 -// FreeImage implementation
 -
 -
 -/** 
 - Image translation and rotation using B-Splines.
 -
 - @param dib Input 8-bit greyscale image
 - @param angle Output image rotation in degree
 - @param x_shift Output image horizontal shift
 - @param y_shift Output image vertical shift
 - @param x_origin Output origin of the x-axis
 - @param y_origin Output origin of the y-axis
 - @param spline_degree Output degree of the B-spline model
 - @param use_mask Whether or not to mask the image
 - @return Returns the translated & rotated dib if successful, returns NULL otherwise
 -*/
 -static FIBITMAP * 
 -Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, long spline_degree, BOOL use_mask) {
 -	double	*ImageRasterArray;
 -	double	p;
 -	double	a11, a12, a21, a22;
 -	double	x0, y0, x1, y1;
 -	long	x, y;
 -	long	spline;
 -	bool	bResult;
 -
 -	int bpp = FreeImage_GetBPP(dib);
 -	if(bpp != 8) {
 -		return NULL;
 -	}
 -	
 -	int width = FreeImage_GetWidth(dib);
 -	int height = FreeImage_GetHeight(dib);
 -	switch(spline_degree) {
 -		case ROTATE_QUADRATIC:
 -			spline = 2L;	// Use splines of degree 2 (quadratic interpolation)
 -			break;
 -		case ROTATE_CUBIC:
 -			spline = 3L;	// Use splines of degree 3 (cubic interpolation)
 -			break;
 -		case ROTATE_QUARTIC:
 -			spline = 4L;	// Use splines of degree 4 (quartic interpolation)
 -			break;
 -		case ROTATE_QUINTIC:
 -			spline = 5L;	// Use splines of degree 5 (quintic interpolation)
 -			break;
 -		default:
 -			spline = 3L;
 -	}
 -
 -	// allocate output image
 -	FIBITMAP *dst = FreeImage_Allocate(width, height, bpp);
 -	if(!dst)
 -		return NULL;
 -	// buid a grey scale palette
 -	RGBQUAD *pal = FreeImage_GetPalette(dst);
 -	for(int i = 0; i < 256; i++) {
 -		pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)i;
 -	}
 -
 -	// allocate a temporary array
 -	ImageRasterArray = (double*)malloc(width * height * sizeof(double));
 -	if(!ImageRasterArray) {
 -		FreeImage_Unload(dst);
 -		return NULL;
 -	}
 -	// copy data samples
 -	for(y = 0; y < height; y++) {
 -		double *pImage = &ImageRasterArray[y*width];
 -		BYTE *src_bits = FreeImage_GetScanLine(dib, height-1-y);
 -
 -		for(x = 0; x < width; x++) {
 -			pImage[x] = (double)src_bits[x];
 -		}
 -	}
 -
 -	// convert between a representation based on image samples
 -	// and a representation based on image B-spline coefficients
 -	bResult = SamplesToCoefficients(ImageRasterArray, width, height, spline);
 -	if(!bResult) {
 -		FreeImage_Unload(dst);
 -		free(ImageRasterArray);
 -		return NULL;
 -	}
 -
 -	// prepare the geometry
 -	angle *= PI / 180.0;
 -	a11 = cos(angle);
 -	a12 = -sin(angle);
 -	a21 = sin(angle);
 -	a22 = cos(angle);
 -	x0 = a11 * (x_shift + x_origin) + a12 * (y_shift + y_origin);
 -	y0 = a21 * (x_shift + x_origin) + a22 * (y_shift + y_origin);
 -	x_shift = x_origin - x0;
 -	y_shift = y_origin - y0;
 -
 -	// visit all pixels of the output image and assign their value
 -	for(y = 0; y < height; y++) {
 -		BYTE *dst_bits = FreeImage_GetScanLine(dst, height-1-y);
 -		
 -		x0 = a12 * (double)y + x_shift;
 -		y0 = a22 * (double)y + y_shift;
 -
 -		for(x = 0; x < width; x++) {
 -			x1 = x0 + a11 * (double)x;
 -			y1 = y0 + a21 * (double)x;
 -			if(use_mask) {
 -				if((x1 <= -0.5) || (((double)width - 0.5) <= x1) || (y1 <= -0.5) || (((double)height - 0.5) <= y1)) {
 -					p = 0;
 -				}
 -				else {
 -					p = (double)InterpolatedValue(ImageRasterArray, width, height, x1, y1, spline);
 -				}
 -			}
 -			else {
 -				p = (double)InterpolatedValue(ImageRasterArray, width, height, x1, y1, spline);
 -			}
 -			// clamp and convert to BYTE
 -			dst_bits[x] = (BYTE)MIN(MAX((int)0, (int)(p + 0.5)), (int)255);
 -		}
 -	}
 -
 -	// free working array and return
 -	free(ImageRasterArray);
 -
 -	return dst;
 -}
 -
 -/** 
 - Image rotation using a 3rd order (cubic) B-Splines.
 -
 - @param dib Input dib (8, 24 or 32-bit)
 - @param angle Output image rotation
 - @param x_shift Output image horizontal shift
 - @param y_shift Output image vertical shift
 - @param x_origin Output origin of the x-axis
 - @param y_origin Output origin of the y-axis
 - @param use_mask Whether or not to mask the image
 - @return Returns the translated & rotated dib if successful, returns NULL otherwise
 -*/
 -FIBITMAP * DLL_CALLCONV 
 -FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask) {
 -
 -	int x, y, bpp;
 -	int channel, nb_channels;
 -	BYTE *src_bits, *dst_bits;
 -	FIBITMAP *src8 = NULL, *dst8 = NULL, *dst = NULL;
 -
 -	if(!FreeImage_HasPixels(dib)) return NULL;
 -
 -	try {
 -
 -		bpp = FreeImage_GetBPP(dib);
 -
 -		if(bpp == 8) {
 -			FIBITMAP *dst_8 = Rotate8Bit(dib, angle, x_shift, y_shift, x_origin, y_origin, ROTATE_CUBIC, use_mask);
 -			if(dst_8) {
 -				// copy metadata from src to dst
 -				FreeImage_CloneMetadata(dst_8, dib);
 -			}
 -			return dst_8;
 -		}
 -		if((bpp == 24) || (bpp == 32)) {
 -			// allocate dst image
 -			int width  = FreeImage_GetWidth(dib);
 -			int height = FreeImage_GetHeight(dib);
 -			if( bpp == 24 ) {
 -				dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
 -			} else {
 -				dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
 -			}
 -			if(!dst) throw(1);
 -
 -			// allocate a temporary 8-bit dib (no need to build a palette)
 -			src8 = FreeImage_Allocate(width, height, 8);
 -			if(!src8) throw(1);
 -
 -			// process each channel separately
 -			// -------------------------------
 -			nb_channels = (bpp / 8);
 -
 -			for(channel = 0; channel < nb_channels; channel++) {
 -				// extract channel from source dib
 -				for(y = 0; y < height; y++) {
 -					src_bits = FreeImage_GetScanLine(dib, y);
 -					dst_bits = FreeImage_GetScanLine(src8, y);
 -					for(x = 0; x < width; x++) {
 -						dst_bits[x] = src_bits[channel];
 -						src_bits += nb_channels;
 -					}
 -				}
 -
 -				// process channel
 -				dst8 = Rotate8Bit(src8, angle, x_shift, y_shift, x_origin, y_origin, ROTATE_CUBIC, use_mask);
 -				if(!dst8) throw(1);
 -
 -				// insert channel to destination dib
 -				for(y = 0; y < height; y++) {
 -					src_bits = FreeImage_GetScanLine(dst8, y);
 -					dst_bits = FreeImage_GetScanLine(dst, y);
 -					for(x = 0; x < width; x++) {
 -						dst_bits[channel] = src_bits[x];
 -						dst_bits += nb_channels;
 -					}
 -				}
 -
 -				FreeImage_Unload(dst8);
 -			}
 -
 -			FreeImage_Unload(src8);
 -
 -			// copy metadata from src to dst
 -			FreeImage_CloneMetadata(dst, dib);
 -			
 -			return dst;
 -		}
 -	} catch(int) {
 -		if(src8) FreeImage_Unload(src8);
 -		if(dst8) FreeImage_Unload(dst8);
 -		if(dst)  FreeImage_Unload(dst);
 -	}
 -
 -	return NULL;
 -}
 +// ========================================================== +// Bitmap rotation using B-Splines +// +// Design and implementation by +// - Philippe Thévenaz (philippe.thevenaz@epfl.ch) +// Adaptation for FreeImage by +// - Hervé Drolon (drolon@infonie.fr) +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +/*  +========================================================== +This code was taken and adapted from the following reference :  + +[1] Philippe Thévenaz, Spline interpolation, a C source code  +implementation. http://bigwww.epfl.ch/thevenaz/ + +It implements ideas described in the following papers :  + +[2] Unser M., Splines: A Perfect Fit for Signal and Image Processing.  +IEEE Signal Processing Magazine, vol. 16, no. 6, pp. 22-38, November 1999.  + +[3] Unser M., Aldroubi A., Eden M., B-Spline Signal Processing: Part I--Theory. +IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 821-832, February 1993.  + +[4] Unser M., Aldroubi A., Eden M., B-Spline Signal Processing: Part II--Efficient Design and Applications. +IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 834-848, February 1993. + +==========================================================  +*/ + + +#include <float.h> +#include "FreeImage.h" +#include "Utilities.h" + +#define PI	((double)3.14159265358979323846264338327950288419716939937510) + +#define ROTATE_QUADRATIC 2L	// Use B-splines of degree 2 (quadratic interpolation) +#define ROTATE_CUBIC     3L	// Use B-splines of degree 3 (cubic interpolation) +#define ROTATE_QUARTIC   4L	// Use B-splines of degree 4 (quartic interpolation) +#define ROTATE_QUINTIC   5L	// Use B-splines of degree 5 (quintic interpolation) + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Prototypes definition + +static void ConvertToInterpolationCoefficients(double *c, long DataLength, double *z, long NbPoles,	double Tolerance); +static double InitialCausalCoefficient(double *c, long DataLength, double z, double Tolerance); +static void GetColumn(double *Image, long Width, long x, double *Line, long Height); +static void	GetRow(double *Image, long y, double *Line, long Width); +static double InitialAntiCausalCoefficient(double *c, long DataLength, double z); +static void	PutColumn(double *Image, long Width, long x, double *Line, long Height); +static void	PutRow(double *Image, long y, double *Line, long Width); +static bool SamplesToCoefficients(double *Image, long Width, long Height, long spline_degree); +static double InterpolatedValue(double *Bcoeff, long Width, long Height, double x, double y, long spline_degree); + +static FIBITMAP * Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, long spline_degree, BOOL use_mask); + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Coefficients routines + +/** + ConvertToInterpolationCoefficients + + @param c Input samples --> output coefficients + @param DataLength Number of samples or coefficients + @param z Poles + @param NbPoles Number of poles + @param Tolerance Admissible relative error +*/ +static void  +ConvertToInterpolationCoefficients(double *c, long DataLength, double *z, long NbPoles,	double Tolerance) { +	double	Lambda = 1; +	long	n, k; + +	// special case required by mirror boundaries +	if(DataLength == 1L) { +		return; +	} +	// compute the overall gain +	for(k = 0L; k < NbPoles; k++) { +		Lambda = Lambda * (1.0 - z[k]) * (1.0 - 1.0 / z[k]); +	} +	// apply the gain  +	for (n = 0L; n < DataLength; n++) { +		c[n] *= Lambda; +	} +	// loop over all poles  +	for (k = 0L; k < NbPoles; k++) { +		// causal initialization  +		c[0] = InitialCausalCoefficient(c, DataLength, z[k], Tolerance); +		// causal recursion  +		for (n = 1L; n < DataLength; n++) { +			c[n] += z[k] * c[n - 1L]; +		} +		// anticausal initialization  +		c[DataLength - 1L] = InitialAntiCausalCoefficient(c, DataLength, z[k]); +		// anticausal recursion  +		for (n = DataLength - 2L; 0 <= n; n--) { +			c[n] = z[k] * (c[n + 1L] - c[n]); +		} +	} +}  + +/** + InitialCausalCoefficient + + @param c Coefficients + @param DataLength Number of coefficients + @param z Actual pole + @param Tolerance Admissible relative error + @return +*/ +static double  +InitialCausalCoefficient(double	*c, long DataLength, double	z, double Tolerance) { +	double	Sum, zn, z2n, iz; +	long	n, Horizon; + +	// this initialization corresponds to mirror boundaries  +	Horizon = DataLength; +	if(Tolerance > 0) { +		Horizon = (long)ceil(log(Tolerance) / log(fabs(z))); +	} +	if(Horizon < DataLength) { +		// accelerated loop +		zn = z; +		Sum = c[0]; +		for (n = 1L; n < Horizon; n++) { +			Sum += zn * c[n]; +			zn *= z; +		} +		return(Sum); +	} +	else { +		// full loop  +		zn = z; +		iz = 1.0 / z; +		z2n = pow(z, (double)(DataLength - 1L)); +		Sum = c[0] + z2n * c[DataLength - 1L]; +		z2n *= z2n * iz; +		for (n = 1L; n <= DataLength - 2L; n++) { +			Sum += (zn + z2n) * c[n]; +			zn *= z; +			z2n *= iz; +		} +		return(Sum / (1.0 - zn * zn)); +	} +} + +/** + GetColumn + + @param Image Input image array + @param Width Width of the image + @param x x coordinate of the selected line + @param Line Output linear array + @param Height Length of the line +*/ +static void  +GetColumn(double *Image, long Width, long x, double *Line, long Height) { +	long y; + +	Image = Image + x; +	for(y = 0L; y < Height; y++) { +		Line[y] = (double)*Image; +		Image += Width; +	} +} + +/** + GetRow + + @param Image Input image array + @param y y coordinate of the selected line + @param Line Output linear array + @param Width Length of the line +*/ +static void	 +GetRow(double *Image, long y, double *Line, long Width) { +	long	x; + +	Image = Image + (y * Width); +	for(x = 0L; x < Width; x++) { +		Line[x] = (double)*Image++; +	} +} + +/** + InitialAntiCausalCoefficient + + @param c Coefficients + @param DataLength Number of samples or coefficients + @param z Actual pole + @return +*/ +static double  +InitialAntiCausalCoefficient(double	*c, long DataLength, double	z) { +	// this initialization corresponds to mirror boundaries +	return((z / (z * z - 1.0)) * (z * c[DataLength - 2L] + c[DataLength - 1L])); +} + +/** + PutColumn + + @param Image Output image array + @param Width Width of the image + @param x x coordinate of the selected line + @param Line Input linear array + @param Height Length of the line and height of the image +*/ +static void	 +PutColumn(double *Image, long Width, long x, double *Line, long Height) { +	long	y; + +	Image = Image + x; +	for(y = 0L; y < Height; y++) { +		*Image = (double)Line[y]; +		Image += Width; +	} +} + +/** + PutRow + + @param Image Output image array + @param y y coordinate of the selected line + @param Line Input linear array + @param Width length of the line and width of the image +*/ +static void	 +PutRow(double *Image, long y, double *Line, long Width) { +	long	x; + +	Image = Image + (y * Width); +	for(x = 0L; x < Width; x++) { +		*Image++ = (double)Line[x]; +	} +} + +/** + SamplesToCoefficients.<br> + Implement the algorithm that converts the image samples into B-spline coefficients.  + This efficient procedure essentially relies on the three papers cited above;  + data are processed in-place.  + Even though this algorithm is robust with respect to quantization,  + we advocate the use of a floating-point format for the data.  + + @param Image Input / Output image (in-place processing) + @param Width Width of the image + @param Height Height of the image + @param spline_degree Degree of the spline model + @return Returns true if success, false otherwise +*/ +static bool	 +SamplesToCoefficients(double *Image, long Width, long Height, long spline_degree) { +	double	*Line; +	double	Pole[2]; +	long	NbPoles; +	long	x, y; + +	// recover the poles from a lookup table +	switch (spline_degree) { +		case 2L: +			NbPoles = 1L; +			Pole[0] = sqrt(8.0) - 3.0; +			break; +		case 3L: +			NbPoles = 1L; +			Pole[0] = sqrt(3.0) - 2.0; +			break; +		case 4L: +			NbPoles = 2L; +			Pole[0] = sqrt(664.0 - sqrt(438976.0)) + sqrt(304.0) - 19.0; +			Pole[1] = sqrt(664.0 + sqrt(438976.0)) - sqrt(304.0) - 19.0; +			break; +		case 5L: +			NbPoles = 2L; +			Pole[0] = sqrt(135.0 / 2.0 - sqrt(17745.0 / 4.0)) + sqrt(105.0 / 4.0) +				- 13.0 / 2.0; +			Pole[1] = sqrt(135.0 / 2.0 + sqrt(17745.0 / 4.0)) - sqrt(105.0 / 4.0) +				- 13.0 / 2.0; +			break; +		default: +			// Invalid spline degree +			return false; +	} + +	// convert the image samples into interpolation coefficients  + +	// in-place separable process, along x  +	Line = (double *)malloc(Width * sizeof(double)); +	if (Line == NULL) { +		// Row allocation failed +		return false; +	} +	for (y = 0L; y < Height; y++) { +		GetRow(Image, y, Line, Width); +		ConvertToInterpolationCoefficients(Line, Width, Pole, NbPoles, DBL_EPSILON); +		PutRow(Image, y, Line, Width); +	} +	free(Line); + +	// in-place separable process, along y  +	Line = (double *)malloc(Height * sizeof(double)); +	if (Line == NULL) { +		// Column allocation failed +		return false; +	} +	for (x = 0L; x < Width; x++) { +		GetColumn(Image, Width, x, Line, Height); +		ConvertToInterpolationCoefficients(Line, Height, Pole, NbPoles, DBL_EPSILON); +		PutColumn(Image, Width, x, Line, Height); +	} +	free(Line); + +	return true; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Interpolation routines + +/** +Perform the bidimensional interpolation of an image. +Given an array of spline coefficients, return the value of  +the underlying continuous spline model, sampled at the location (x, y).  +The model degree can be 2 (quadratic), 3 (cubic), 4 (quartic), or 5 (quintic). + +@param Bcoeff Input B-spline array of coefficients +@param Width Width of the image +@param Height Height of the image +@param x x coordinate where to interpolate +@param y y coordinate where to interpolate +@param spline_degree Degree of the spline model +@return Returns the value of the underlying continuous spline model,  +sampled at the location (x, y) +*/ +static double  +InterpolatedValue(double *Bcoeff, long Width, long Height, double x, double y, long spline_degree) { +	double	*p; +	double	xWeight[6], yWeight[6]; +	double	interpolated; +	double	w, w2, w4, t, t0, t1; +	long	xIndex[6], yIndex[6]; +	long	Width2 = 2L * Width - 2L, Height2 = 2L * Height - 2L; +	long	i, j, k; + +	// compute the interpolation indexes +	if (spline_degree & 1L) { +		i = (long)floor(x) - spline_degree / 2L; +		j = (long)floor(y) - spline_degree / 2L; +		for(k = 0; k <= spline_degree; k++) { +			xIndex[k] = i++; +			yIndex[k] = j++; +		} +	} +	else { +		i = (long)floor(x + 0.5) - spline_degree / 2L; +		j = (long)floor(y + 0.5) - spline_degree / 2L; +		for (k = 0; k <= spline_degree; k++) { +			xIndex[k] = i++; +			yIndex[k] = j++; +		} +	} + +	// compute the interpolation weights +	switch (spline_degree) { +		case 2L: +			/* x */ +			w = x - (double)xIndex[1]; +			xWeight[1] = 3.0 / 4.0 - w * w; +			xWeight[2] = (1.0 / 2.0) * (w - xWeight[1] + 1.0); +			xWeight[0] = 1.0 - xWeight[1] - xWeight[2]; +			/* y */ +			w = y - (double)yIndex[1]; +			yWeight[1] = 3.0 / 4.0 - w * w; +			yWeight[2] = (1.0 / 2.0) * (w - yWeight[1] + 1.0); +			yWeight[0] = 1.0 - yWeight[1] - yWeight[2]; +			break; +		case 3L: +			/* x */ +			w = x - (double)xIndex[1]; +			xWeight[3] = (1.0 / 6.0) * w * w * w; +			xWeight[0] = (1.0 / 6.0) + (1.0 / 2.0) * w * (w - 1.0) - xWeight[3]; +			xWeight[2] = w + xWeight[0] - 2.0 * xWeight[3]; +			xWeight[1] = 1.0 - xWeight[0] - xWeight[2] - xWeight[3]; +			/* y */ +			w = y - (double)yIndex[1]; +			yWeight[3] = (1.0 / 6.0) * w * w * w; +			yWeight[0] = (1.0 / 6.0) + (1.0 / 2.0) * w * (w - 1.0) - yWeight[3]; +			yWeight[2] = w + yWeight[0] - 2.0 * yWeight[3]; +			yWeight[1] = 1.0 - yWeight[0] - yWeight[2] - yWeight[3]; +			break; +		case 4L: +			/* x */ +			w = x - (double)xIndex[2]; +			w2 = w * w; +			t = (1.0 / 6.0) * w2; +			xWeight[0] = 1.0 / 2.0 - w; +			xWeight[0] *= xWeight[0]; +			xWeight[0] *= (1.0 / 24.0) * xWeight[0]; +			t0 = w * (t - 11.0 / 24.0); +			t1 = 19.0 / 96.0 + w2 * (1.0 / 4.0 - t); +			xWeight[1] = t1 + t0; +			xWeight[3] = t1 - t0; +			xWeight[4] = xWeight[0] + t0 + (1.0 / 2.0) * w; +			xWeight[2] = 1.0 - xWeight[0] - xWeight[1] - xWeight[3] - xWeight[4]; +			/* y */ +			w = y - (double)yIndex[2]; +			w2 = w * w; +			t = (1.0 / 6.0) * w2; +			yWeight[0] = 1.0 / 2.0 - w; +			yWeight[0] *= yWeight[0]; +			yWeight[0] *= (1.0 / 24.0) * yWeight[0]; +			t0 = w * (t - 11.0 / 24.0); +			t1 = 19.0 / 96.0 + w2 * (1.0 / 4.0 - t); +			yWeight[1] = t1 + t0; +			yWeight[3] = t1 - t0; +			yWeight[4] = yWeight[0] + t0 + (1.0 / 2.0) * w; +			yWeight[2] = 1.0 - yWeight[0] - yWeight[1] - yWeight[3] - yWeight[4]; +			break; +		case 5L: +			/* x */ +			w = x - (double)xIndex[2]; +			w2 = w * w; +			xWeight[5] = (1.0 / 120.0) * w * w2 * w2; +			w2 -= w; +			w4 = w2 * w2; +			w -= 1.0 / 2.0; +			t = w2 * (w2 - 3.0); +			xWeight[0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - xWeight[5]; +			t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0); +			t1 = (-1.0 / 12.0) * w * (t + 4.0); +			xWeight[2] = t0 + t1; +			xWeight[3] = t0 - t1; +			t0 = (1.0 / 16.0) * (9.0 / 5.0 - t); +			t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0); +			xWeight[1] = t0 + t1; +			xWeight[4] = t0 - t1; +			/* y */ +			w = y - (double)yIndex[2]; +			w2 = w * w; +			yWeight[5] = (1.0 / 120.0) * w * w2 * w2; +			w2 -= w; +			w4 = w2 * w2; +			w -= 1.0 / 2.0; +			t = w2 * (w2 - 3.0); +			yWeight[0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - yWeight[5]; +			t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0); +			t1 = (-1.0 / 12.0) * w * (t + 4.0); +			yWeight[2] = t0 + t1; +			yWeight[3] = t0 - t1; +			t0 = (1.0 / 16.0) * (9.0 / 5.0 - t); +			t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0); +			yWeight[1] = t0 + t1; +			yWeight[4] = t0 - t1; +			break; +		default: +			// Invalid spline degree +			return 0; +	} + +	// apply the mirror boundary conditions +	for(k = 0; k <= spline_degree; k++) { +		xIndex[k] = (Width == 1L) ? (0L) : ((xIndex[k] < 0L) ? +			(-xIndex[k] - Width2 * ((-xIndex[k]) / Width2)) +			: (xIndex[k] - Width2 * (xIndex[k] / Width2))); +		if (Width <= xIndex[k]) { +			xIndex[k] = Width2 - xIndex[k]; +		} +		yIndex[k] = (Height == 1L) ? (0L) : ((yIndex[k] < 0L) ? +			(-yIndex[k] - Height2 * ((-yIndex[k]) / Height2)) +			: (yIndex[k] - Height2 * (yIndex[k] / Height2))); +		if (Height <= yIndex[k]) { +			yIndex[k] = Height2 - yIndex[k]; +		} +	} + +	// perform interpolation +	interpolated = 0.0; +	for(j = 0; j <= spline_degree; j++) { +		p = Bcoeff + (yIndex[j] * Width); +		w = 0.0; +		for(i = 0; i <= spline_degree; i++) { +			w += xWeight[i] * p[xIndex[i]]; +		} +		interpolated += yWeight[j] * w; +	} + +	return interpolated; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FreeImage implementation + + +/**  + Image translation and rotation using B-Splines. + + @param dib Input 8-bit greyscale image + @param angle Output image rotation in degree + @param x_shift Output image horizontal shift + @param y_shift Output image vertical shift + @param x_origin Output origin of the x-axis + @param y_origin Output origin of the y-axis + @param spline_degree Output degree of the B-spline model + @param use_mask Whether or not to mask the image + @return Returns the translated & rotated dib if successful, returns NULL otherwise +*/ +static FIBITMAP *  +Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, long spline_degree, BOOL use_mask) { +	double	*ImageRasterArray; +	double	p; +	double	a11, a12, a21, a22; +	double	x0, y0, x1, y1; +	long	x, y; +	long	spline; +	bool	bResult; + +	int bpp = FreeImage_GetBPP(dib); +	if(bpp != 8) { +		return NULL; +	} +	 +	int width = FreeImage_GetWidth(dib); +	int height = FreeImage_GetHeight(dib); +	switch(spline_degree) { +		case ROTATE_QUADRATIC: +			spline = 2L;	// Use splines of degree 2 (quadratic interpolation) +			break; +		case ROTATE_CUBIC: +			spline = 3L;	// Use splines of degree 3 (cubic interpolation) +			break; +		case ROTATE_QUARTIC: +			spline = 4L;	// Use splines of degree 4 (quartic interpolation) +			break; +		case ROTATE_QUINTIC: +			spline = 5L;	// Use splines of degree 5 (quintic interpolation) +			break; +		default: +			spline = 3L; +	} + +	// allocate output image +	FIBITMAP *dst = FreeImage_Allocate(width, height, bpp); +	if(!dst) +		return NULL; +	// buid a grey scale palette +	RGBQUAD *pal = FreeImage_GetPalette(dst); +	for(int i = 0; i < 256; i++) { +		pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)i; +	} + +	// allocate a temporary array +	ImageRasterArray = (double*)malloc(width * height * sizeof(double)); +	if(!ImageRasterArray) { +		FreeImage_Unload(dst); +		return NULL; +	} +	// copy data samples +	for(y = 0; y < height; y++) { +		double *pImage = &ImageRasterArray[y*width]; +		BYTE *src_bits = FreeImage_GetScanLine(dib, height-1-y); + +		for(x = 0; x < width; x++) { +			pImage[x] = (double)src_bits[x]; +		} +	} + +	// convert between a representation based on image samples +	// and a representation based on image B-spline coefficients +	bResult = SamplesToCoefficients(ImageRasterArray, width, height, spline); +	if(!bResult) { +		FreeImage_Unload(dst); +		free(ImageRasterArray); +		return NULL; +	} + +	// prepare the geometry +	angle *= PI / 180.0; +	a11 = cos(angle); +	a12 = -sin(angle); +	a21 = sin(angle); +	a22 = cos(angle); +	x0 = a11 * (x_shift + x_origin) + a12 * (y_shift + y_origin); +	y0 = a21 * (x_shift + x_origin) + a22 * (y_shift + y_origin); +	x_shift = x_origin - x0; +	y_shift = y_origin - y0; + +	// visit all pixels of the output image and assign their value +	for(y = 0; y < height; y++) { +		BYTE *dst_bits = FreeImage_GetScanLine(dst, height-1-y); +		 +		x0 = a12 * (double)y + x_shift; +		y0 = a22 * (double)y + y_shift; + +		for(x = 0; x < width; x++) { +			x1 = x0 + a11 * (double)x; +			y1 = y0 + a21 * (double)x; +			if(use_mask) { +				if((x1 <= -0.5) || (((double)width - 0.5) <= x1) || (y1 <= -0.5) || (((double)height - 0.5) <= y1)) { +					p = 0; +				} +				else { +					p = (double)InterpolatedValue(ImageRasterArray, width, height, x1, y1, spline); +				} +			} +			else { +				p = (double)InterpolatedValue(ImageRasterArray, width, height, x1, y1, spline); +			} +			// clamp and convert to BYTE +			dst_bits[x] = (BYTE)MIN(MAX((int)0, (int)(p + 0.5)), (int)255); +		} +	} + +	// free working array and return +	free(ImageRasterArray); + +	return dst; +} + +/**  + Image rotation using a 3rd order (cubic) B-Splines. + + @param dib Input dib (8, 24 or 32-bit) + @param angle Output image rotation + @param x_shift Output image horizontal shift + @param y_shift Output image vertical shift + @param x_origin Output origin of the x-axis + @param y_origin Output origin of the y-axis + @param use_mask Whether or not to mask the image + @return Returns the translated & rotated dib if successful, returns NULL otherwise +*/ +FIBITMAP * DLL_CALLCONV  +FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask) { + +	int x, y, bpp; +	int channel, nb_channels; +	BYTE *src_bits, *dst_bits; +	FIBITMAP *src8 = NULL, *dst8 = NULL, *dst = NULL; + +	if(!FreeImage_HasPixels(dib)) return NULL; + +	try { + +		bpp = FreeImage_GetBPP(dib); + +		if(bpp == 8) { +			FIBITMAP *dst_8 = Rotate8Bit(dib, angle, x_shift, y_shift, x_origin, y_origin, ROTATE_CUBIC, use_mask); +			if(dst_8) { +				// copy metadata from src to dst +				FreeImage_CloneMetadata(dst_8, dib); +			} +			return dst_8; +		} +		if((bpp == 24) || (bpp == 32)) { +			// allocate dst image +			int width  = FreeImage_GetWidth(dib); +			int height = FreeImage_GetHeight(dib); +			if( bpp == 24 ) { +				dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); +			} else { +				dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); +			} +			if(!dst) throw(1); + +			// allocate a temporary 8-bit dib (no need to build a palette) +			src8 = FreeImage_Allocate(width, height, 8); +			if(!src8) throw(1); + +			// process each channel separately +			// ------------------------------- +			nb_channels = (bpp / 8); + +			for(channel = 0; channel < nb_channels; channel++) { +				// extract channel from source dib +				for(y = 0; y < height; y++) { +					src_bits = FreeImage_GetScanLine(dib, y); +					dst_bits = FreeImage_GetScanLine(src8, y); +					for(x = 0; x < width; x++) { +						dst_bits[x] = src_bits[channel]; +						src_bits += nb_channels; +					} +				} + +				// process channel +				dst8 = Rotate8Bit(src8, angle, x_shift, y_shift, x_origin, y_origin, ROTATE_CUBIC, use_mask); +				if(!dst8) throw(1); + +				// insert channel to destination dib +				for(y = 0; y < height; y++) { +					src_bits = FreeImage_GetScanLine(dst8, y); +					dst_bits = FreeImage_GetScanLine(dst, y); +					for(x = 0; x < width; x++) { +						dst_bits[channel] = src_bits[x]; +						dst_bits += nb_channels; +					} +				} + +				FreeImage_Unload(dst8); +			} + +			FreeImage_Unload(src8); + +			// copy metadata from src to dst +			FreeImage_CloneMetadata(dst, dib); +			 +			return dst; +		} +	} catch(int) { +		if(src8) FreeImage_Unload(src8); +		if(dst8) FreeImage_Unload(dst8); +		if(dst)  FreeImage_Unload(dst); +	} + +	return NULL; +}  | 
