Notepad3/src/Resample.c
2021-12-09 10:09:53 +01:00

906 lines
24 KiB
C

// Resample.cpp : Defines the entry point for the DLL application.
//
//#include "stdafx.h"
#define _USE_MATH_DEFINES
#include <math.h>
#include <assert.h>
#include "Helpers.h"
#include "Resample.h"
/* Quite arbitrary */
#define MAX_FILTER_RADIUS 16.0
#define MIN_RESAMPLE_WIDTH 0x00000001
#define MAX_RESAMPLE_WIDTH 0x00001000
#define MIN_RESAMPLE_HEIGHT 0x00000001
#define MAX_RESAMPLE_HEIGHT 0x00001000
/* RGBA */
#define COLOR_COMPONENTS 4
/* Each core filter has its own radius */
#define DEFAULT_LANCZOS8_RADIUS 8.0
#define DEFAULT_LANCZOS3_RADIUS 3.0
#define DEFAULT_HERMITE_RADIUS 1.0
#define DEFAULT_BOX_RADIUS 0.5
#define DEFAULT_TRIANGLE_RADIUS 1.0
#define DEFAULT_BELL_RADIUS 1.5
#define DEFAULT_CUBICSPLINE_RADIUS 2.0
#define DEFAULT_MITCHELL_RADIUS 2.0
#define DEFAULT_COSINE_RADIUS 1.0
#define DEFAULT_CATMULLROM_RADIUS 2.0
#define DEFAULT_QUADRATIC_RADIUS 1.5
#define DEFAULT_QUADRATICBSPLINE_RADIUS 1.5
#define DEFAULT_CUBICCONVOLUTION_RADIUS 3.0
/* Filter function type */
typedef double (*PFN_FILTER)(double);
/* Core filters */
static double _Lanczos8(double);
static double _Lanczos3(double);
static double _Hermite(double);
static double _Box(double);
static double _Triangle(double);
static double _Bell(double);
static double _CubicSpline(double);
static double _Mitchell(double);
static double _Cosine(double);
static double _CatmullRom(double);
static double _Quadratic(double);
static double _QuadraticBSpline(double);
static double _CubicConvolution(double);
/* helper functions */
static BOOL _setResampleFilter(DWORD dwFilter, PFN_FILTER *ppFnFilter, double *pdRadius);
static HBITMAP _createResampledBitmap(HDC hdc, HBITMAP hBmpSource, DWORD dwWidth, DWORD dwHeight, PFN_FILTER pFnFilter, double dRadius);
static BOOL _fillBITMAPINFO(HBITMAP hBmp, BITMAPINFO *pBinfo);
static BOOL _resample(BYTE *ibuf, LONG iw, LONG ih, BYTE *obuf, LONG ow, LONG oh, PFN_FILTER pFnFilter, double dRadius);
#ifdef _MANAGED
# pragma managed(push, off)
#endif
//BOOL APIENTRY DllMain(HMODULE hModule,
// DWORD ul_reason_for_call,
// LPVOID lpReserved)
// UNREFERENCED_PARAMETER(lpReserved);
// UNREFERENCED_PARAMETER(lpReserved);
// switch (ul_reason_for_call) {
// case DLL_PROCESS_ATTACH:
// case DLL_THREAD_ATTACH:
// case DLL_THREAD_DETACH:
// case DLL_PROCESS_DETACH:
// break;
// }
// return TRUE;
//}
#ifdef _MANAGED
# pragma managed(pop)
#endif
/*-> The exported functions */
/* CreateResampledBitmap
Creates a resampled bitmap given the original one, neew dimensions, the index of the core filter.
The function is in fact a wrapper for the pair of helper functions _setResampleFilter and _createResampledBitmap.
ARGS:
hdc [IN] given device context
hBmpSource [IN] original bitmap handle
dwWidth [IN] resampled bitmap width
dwHeight [IN] resampled bitmap height
dwFilter [IN] index of the choosen core filter
RETURN VALUE:
the handle (HBITMAP) of the resampled bitmap on success, NULL on failure
*/
RESAMPLE_API HBITMAP CreateResampledBitmap(HDC hdc,
HBITMAP hBmpSource,
DWORD dwWidth, DWORD dwHeight,
DWORD dwFilter)
{
double (*pFnFilter)(double);
double dRadius;
if (_setResampleFilter(dwFilter, &pFnFilter, &dRadius) == FALSE) {
SetLastError(E_UNABLE_TO_SET_FILTER);
return NULL;
}
return _createResampledBitmap(hdc, hBmpSource, dwWidth, dwHeight, pFnFilter, dRadius);
}
/* CreateResampledBitmap
Creates a resampled bitmap given the original one, neew dimensions, the index of the core filter
ARGS:
hdc [IN] given device context
hBmpSource [IN] original bitmap handle
dwWidth [IN] resampled bitmap width
dwHeight [IN] resampled bitmap height
dwFilter [IN] index of the choosen core filter
pFnCustomFilter [IN] custom filter function pointer
dRadius [IN] radius of the custom filter
RETURN VALUE:
the handle (HBITMAP) of the resampled bitmap on success, NULL on failure
*/
RESAMPLE_API HBITMAP CreateUserFilterResampledBitmap(HDC hdc,
HBITMAP hBmpSource,
DWORD dwWidth, DWORD dwHeight,
double (*pFnCustomFilter)(double), double dRadius)
{
if (!pFnCustomFilter || dRadius < 0.0 || dRadius > MAX_FILTER_RADIUS) {
SetLastError(E_UNABLE_TO_SET_FILTER);
return NULL;
}
return _createResampledBitmap(hdc, hBmpSource, dwWidth, dwHeight, pFnCustomFilter, dRadius);
}
/* Sets proper (core) filter and radius given filter index
ARGS:
dwFilter [IN] filter index
ppFnFilter [OUT] filter function
pdRadius [OUT] filter radius
*/
BOOL _setResampleFilter(DWORD dwFilter, PFN_FILTER *ppFnFilter, double *pdRadius)
{
BOOL fResult;
fResult = TRUE;
dwFilter = dwFilter % STOCK_FILTERS;
switch (dwFilter) {
case STOCK_FILTER_LANCZOS3:
*ppFnFilter = _Lanczos3;
*pdRadius = DEFAULT_LANCZOS3_RADIUS;
break;
case STOCK_FILTER_LANCZOS8:
*ppFnFilter = _Lanczos8;
*pdRadius = DEFAULT_LANCZOS8_RADIUS;
break;
case STOCK_FILTER_HERMITE:
*ppFnFilter = _Hermite;
*pdRadius = DEFAULT_HERMITE_RADIUS;
break;
case STOCK_FILTER_BOX:
*ppFnFilter = _Box;
*pdRadius = DEFAULT_BOX_RADIUS;
break;
case STOCK_FILTER_TRIANGLE:
*ppFnFilter = _Triangle;
*pdRadius = DEFAULT_TRIANGLE_RADIUS;
break;
case STOCK_FILTER_BELL:
*ppFnFilter = _Bell;
*pdRadius = DEFAULT_BELL_RADIUS;
break;
case STOCK_FILTER_CUBICSPLINE:
*ppFnFilter = _CubicSpline;
*pdRadius = DEFAULT_CUBICSPLINE_RADIUS;
break;
case STOCK_FILTER_MITCHELL:
*ppFnFilter = _Mitchell;
*pdRadius = DEFAULT_MITCHELL_RADIUS;
break;
case STOCK_FILTER_COSINE:
*ppFnFilter = _Cosine;
*pdRadius = DEFAULT_COSINE_RADIUS;
break;
case STOCK_FILTER_CATMULLROM:
*ppFnFilter = _CatmullRom;
*pdRadius = DEFAULT_CATMULLROM_RADIUS;
break;
case STOCK_FILTER_QUADRATIC:
*ppFnFilter = _Quadratic;
*pdRadius = DEFAULT_QUADRATIC_RADIUS;
break;
case STOCK_FILTER_QUADRATICBSPLINE:
*ppFnFilter = _QuadraticBSpline;
*pdRadius = DEFAULT_QUADRATICBSPLINE_RADIUS;
break;
case STOCK_FILTER_CUBICCONVOLUTION:
*ppFnFilter = _CubicConvolution;
*pdRadius = DEFAULT_CUBICCONVOLUTION_RADIUS;
break;
default:
assert(0);
fResult = FALSE;
}
return fResult;
}
/* Creates the resampled bitmap
ARGS:
hdc [IN] provided HDC
hBmpSource [IN] original bitmap handle
dwWidth [IN] resampled bitmap width
dwHeight [IN] resampled bitmap height
pnFnFilter [IN] filter function
dRAdius [IN] filter radius
RETURN VALUE:
Handle (HBITMAP) of the resampled bitmap
*/
HBITMAP _createResampledBitmap(HDC hdc, HBITMAP hBmpSource,
DWORD dwWidth, DWORD dwHeight,
PFN_FILTER pFnFilter, double dRadius)
{
BOOL fResult;
BITMAPINFO binfoSource;
BYTE * pbSource;
HBITMAP hBmpTarget;
BITMAPINFO binfoTarget;
BYTE * pbTarget;
/* Bare initialization */
fResult = FALSE;
pbSource = NULL;
hBmpTarget = NULL;
pbTarget = NULL;
/*<- Bare initialization */
if (!pFnFilter) {
SetLastError(E_UNABLE_TO_SET_FILTER);
return FALSE;
}
if (!hBmpSource) {
SetLastError(E_INVALID_BITMAP);
return FALSE;
}
if (dwWidth < MIN_RESAMPLE_WIDTH) {
dwWidth = MIN_RESAMPLE_WIDTH;
} else if (dwWidth > MAX_RESAMPLE_WIDTH) {
dwWidth = MAX_RESAMPLE_WIDTH;
}
if (dwHeight < MIN_RESAMPLE_HEIGHT) {
dwHeight = MIN_RESAMPLE_HEIGHT;
} else if (dwHeight > MAX_RESAMPLE_HEIGHT) {
dwHeight = MAX_RESAMPLE_HEIGHT;
}
if (_fillBITMAPINFO(hBmpSource, &binfoSource) == FALSE) {
SetLastError(E_INVALID_BITMAP_DATA);
return FALSE;
}
/* Creating target bitmap */
hBmpTarget = CreateCompatibleBitmap(hdc, dwWidth, dwHeight);
if (!hBmpTarget) {
SetLastError(E_UNABLE_TO_CREATE_BITMAP);
return FALSE;
}
/* Getting info about the target bitmap */
if (_fillBITMAPINFO(hBmpTarget, &binfoTarget) == FALSE) {
SetLastError(E_INVALID_OUT_BITMAP_DATA);
goto Cleanup;
}
/* Allocating buffer for the Source image bits */
pbSource = AllocMem(binfoSource.bmiHeader.biSizeImage, HEAP_ZERO_MEMORY);
if (!pbSource) {
SetLastError(E_MEMORY_ERROR);
goto Cleanup;
}
/* Getting data of the source bitmap */
if (binfoSource.bmiHeader.biHeight != GetDIBits(hdc, hBmpSource, 0, binfoSource.bmiHeader.biHeight, pbSource, &binfoSource, DIB_RGB_COLORS)) {
SetLastError(E_UNABLE_TO_LOAD_BITMAP_BITS);
goto Cleanup;
}
/* Allocating buffer for the Target image bits */
pbTarget = AllocMem(binfoTarget.bmiHeader.biSizeImage, HEAP_ZERO_MEMORY);
if (!pbTarget) {
SetLastError(E_MEMORY_ERROR);
goto Cleanup;
}
if (_resample(pbSource, binfoSource.bmiHeader.biWidth, binfoSource.bmiHeader.biHeight,
pbTarget, binfoTarget.bmiHeader.biWidth, binfoTarget.bmiHeader.biHeight,
pFnFilter, dRadius) == FALSE) {
SetLastError(E_RESAMPLE_ERROR);
goto Cleanup;
}
if (binfoTarget.bmiHeader.biHeight != SetDIBits(hdc, hBmpTarget, 0, binfoTarget.bmiHeader.biHeight, pbTarget, &binfoTarget, DIB_RGB_COLORS)) {
SetLastError(E_UNABLE_TO_SET_BITMAP);
goto Cleanup;
}
fResult = TRUE;
Cleanup:
if (pbSource) {
FreeMem(pbSource);
pbSource = NULL;
}
if (pbTarget) {
FreeMem(pbTarget);
pbTarget = NULL;
}
if (fResult == FALSE) {
if (hBmpTarget) {
DeleteObject(hBmpTarget);
hBmpTarget = NULL;
}
}
return hBmpTarget;
} /* <- CreateResampledBitmap */
/* _resample
This function does the real resampling stuff.
ARGS:
ibuf [IN] pointer of original bitmap bits
iw [IN] original image width
ih [IN] original image height
obuf [OUT] resampled image bits
ow [IN] resampled image width
oh [IN] resampled image height
pFnFilter [IN] filter function pointer
dRadius [IN] filter radius
RETURN VALUE
TRUE on success
*/
BOOL _resample(BYTE *ibuf, LONG iw, LONG ih, BYTE *obuf, LONG ow, LONG oh, PFN_FILTER pFnFilter, double dRadius)
{
BOOL fSuccess = FALSE;
LONG i, j, n, c;
double xScale, yScale;
/* Alias (pointer to DWORD) for ibuf */
DWORD *ib;
/* Alias (pointer to DWORD ) for obuf */
DWORD *ob;
// Temporary values
DWORD val = 0;
int col; /* This should remain int (a bit tricky stuff) */
double *h_weight; // Weight contribution [ow][MAX_CONTRIBS]
LONG * h_pixel; // Pixel that contributes [ow][MAX_CONTRIBS]
LONG * h_count; // How many contribution for the pixel [ow]
double *h_wsum; // Sum of weights [ow]
double *v_weight; // Weight contribution [oh][MAX_CONTRIBS]
LONG * v_pixel; // Pixel that contributes [oh][MAX_CONTRIBS]
LONG * v_count; // How many contribution for the pixel [oh]
double *v_wsum; // Sum of weights [oh]
DWORD *tb; // Temporary (intermediate buffer)
double intensity[COLOR_COMPONENTS] = { 0.0, 0.0, 0.0, 0.0 }; // RGBA component intensities
double center; // Center of current sampling
double weight; // Current wight
LONG left; // Left of current sampling
LONG right; // Right of current sampling
double *p_weight; // Temporary pointer
LONG * p_pixel; // Temporary pointer
LONG MAX_CONTRIBS; // Almost-const: max number of contribution for current sampling
double SCALED_RADIUS; // Almost-const: scaled radius for downsampling operations
double FILTER_FACTOR; // Almost-const: filter factor for downsampling operations
/* Preliminary (redundant ? ) check */
if (iw < 1 || ih < 1 || ibuf == NULL || ow < 1 || oh < 1 || obuf == NULL) {
return FALSE;
}
/* Aliasing buffers */
ib = (DWORD *)ibuf;
ob = (DWORD *)obuf;
if (ow == iw && oh == ih) { /* Aame size, no resampling */
CopyMemory(ob, ib, (size_t)iw * (size_t)ih * sizeof(COLORREF));
return TRUE;
}
xScale = ((double)ow / iw);
yScale = ((double)oh / ih);
h_weight = NULL;
h_pixel = NULL;
h_count = NULL;
h_wsum = NULL;
v_weight = NULL;
v_pixel = NULL;
v_count = NULL;
v_wsum = NULL;
tb = NULL;
tb = (DWORD *)AllocMem((size_t)ow * ih * sizeof(DWORD), HEAP_ZERO_MEMORY);
if (!tb) {
goto Cleanup;
}
if (xScale > 1.0) {
/* Horizontal upsampling */
FILTER_FACTOR = 1.0;
SCALED_RADIUS = dRadius;
} else { /* Horizontal downsampling */
FILTER_FACTOR = xScale;
SCALED_RADIUS = dRadius / xScale;
}
/* The maximum number of contributions for a target pixel */
MAX_CONTRIBS = (int)(2 * SCALED_RADIUS + 1);
/* Pre-allocating all of the needed memory */
h_weight = (double *)AllocMem((size_t)ow * MAX_CONTRIBS * sizeof(double), HEAP_ZERO_MEMORY); /* weights */
h_pixel = (LONG *)AllocMem((size_t)ow * MAX_CONTRIBS * sizeof(int), HEAP_ZERO_MEMORY); /* the contributing pixels */
h_count = (LONG *)AllocMem((size_t)ow * sizeof(int), HEAP_ZERO_MEMORY); /* how may contributions for the target pixel */
h_wsum = (double *)AllocMem((size_t)ow * sizeof(double), HEAP_ZERO_MEMORY); /* sum of the weights for the target pixel */
if (!(h_weight && h_pixel || h_count || h_wsum)) {
goto Cleanup;
}
/* Pre-calculate weights contribution for a row */
for (i = 0; i < ow; i++) {
p_weight = h_weight + i * MAX_CONTRIBS;
p_pixel = h_pixel + i * MAX_CONTRIBS;
h_count[i] = 0;
h_wsum[i] = 0.0;
center = ((double)i) / xScale;
left = (int)((center + .5) - SCALED_RADIUS);
right = (int)(left + 2 * SCALED_RADIUS);
for (j = left; j <= right; j++) {
if (j < 0 || j >= iw) {
continue;
}
weight = (*pFnFilter)((center - j) * FILTER_FACTOR);
if (weight == 0.0) {
continue;
}
n = h_count[i]; /* Since h_count[i] is our current index */
p_pixel[n] = j;
p_weight[n] = weight;
h_wsum[i] += weight;
h_count[i]++; /* Increment contribution count */
} /* j */
} /* i */
/* Filter horizontally from input to temporary buffer */
for (n = 0; n < ih; n++) {
/* Here 'n' runs on the vertical coordinate */
for (i = 0; i < ow; i++) { /* i runs on the horizontal coordinate */
p_weight = h_weight + i * MAX_CONTRIBS;
p_pixel = h_pixel + i * MAX_CONTRIBS;
for (c = 0; c < COLOR_COMPONENTS; c++) {
intensity[c] = 0.0;
}
for (j = 0; j < h_count[i]; j++) {
weight = p_weight[j];
val = ib[p_pixel[j] + n * iw]; /* Using val as temporary storage */
/* Acting on color components */
for (c = 0; c < COLOR_COMPONENTS; c++) {
intensity[c] += (val & 0xFF) * weight;
val = val >> 8;
}
}
/* val is already 0 */
for (c = 0; c < COLOR_COMPONENTS; c++) {
val = val << 8;
col = (int)(intensity[COLOR_COMPONENTS - c - 1] / h_wsum[i]);
if (col < 0) {
col = 0;
}
if (col > 255) {
col = 255;
}
val |= col;
}
tb[i + n * ow] = val; /* Temporary buffer ow x ih */
} /* i */
} /* n */
/* Going to vertical stuff */
if (yScale > 1.0) {
FILTER_FACTOR = 1.0;
SCALED_RADIUS = dRadius;
} else {
FILTER_FACTOR = yScale;
SCALED_RADIUS = dRadius / yScale;
}
MAX_CONTRIBS = (int)(2 * SCALED_RADIUS + 1);
/* Pre-calculate filter contributions for a column */
v_weight = (double *)AllocMem((size_t)oh * MAX_CONTRIBS * sizeof(double), HEAP_ZERO_MEMORY); /* Weights */
v_pixel = (LONG *)AllocMem((size_t)oh * MAX_CONTRIBS * sizeof(int), HEAP_ZERO_MEMORY); /* The contributing pixels */
v_count = (LONG *)AllocMem((size_t)oh * sizeof(int), HEAP_ZERO_MEMORY); /* How may contributions for the target pixel */
v_wsum = (double *)AllocMem((size_t)oh * sizeof(double), HEAP_ZERO_MEMORY); /* Sum of the weights for the target pixel */
if (!(v_weight && v_pixel && v_count && v_wsum)) {
goto Cleanup;
}
for (i = 0; i < oh; i++) {
p_weight = v_weight + i * MAX_CONTRIBS;
p_pixel = v_pixel + i * MAX_CONTRIBS;
v_count[i] = 0;
v_wsum[i] = 0.0;
center = ((double)i) / yScale;
left = (int)(center + .5 - SCALED_RADIUS);
right = (int)(left + 2 * SCALED_RADIUS);
for (j = left; j <= right; j++) {
if (j < 0 || j >= ih) {
continue;
}
weight = (*pFnFilter)((center - j) * FILTER_FACTOR);
if (weight == 0.0) {
continue;
}
n = v_count[i]; /* Our current index */
p_pixel[n] = j;
p_weight[n] = weight;
v_wsum[i] += weight;
v_count[i]++; /* Increment the contribution count */
} /* j */
} /* i */
/* Filter vertically from work to output */
for (n = 0; n < ow; n++) {
for (i = 0; i < oh; i++) {
p_weight = v_weight + i * MAX_CONTRIBS;
p_pixel = v_pixel + i * MAX_CONTRIBS;
for (c = 0; c < COLOR_COMPONENTS; c++) {
intensity[c] = 0.0;
}
for (j = 0; j < v_count[i]; j++) {
weight = p_weight[j];
val = tb[n + ow * p_pixel[j]]; /* Using val as temporary storage */
/* Acting on color components */
for (c = 0; c < COLOR_COMPONENTS; c++) {
intensity[c] += (val & 0xFF) * weight;
val = val >> 8;
}
}
/* val is already 0 */
for (c = 0; c < COLOR_COMPONENTS; c++) {
val = val << 8;
col = (int)(intensity[COLOR_COMPONENTS - c - 1] / v_wsum[i]);
if (col < 0) {
col = 0;
}
if (col > 255) {
col = 255;
}
val |= col;
}
ob[n + i * ow] = val;
} /* i */
} /* n */
fSuccess = TRUE;
Cleanup: /* CLEANUP */
if (tb) {
FreeMem(tb);
tb = NULL;
}
if (h_weight) {
FreeMem(h_weight);
h_weight = NULL;
}
if (h_pixel) {
FreeMem(h_pixel);
h_pixel = NULL;
}
if (h_count) {
FreeMem(h_count);
h_count = NULL;
}
if (h_wsum) {
FreeMem(h_wsum);
h_wsum = NULL;
}
if (v_weight) {
FreeMem(v_weight);
v_weight = NULL;
}
if (v_pixel) {
FreeMem(v_pixel);
v_pixel = NULL;
}
if (v_count) {
FreeMem(v_count);
v_count = NULL;
}
if (v_wsum) {
FreeMem(v_wsum);
v_wsum = NULL;
}
return fSuccess;
} /* _resample */
/* _fillBITMAPINFO helper function
fills a BITMAPINFO struct given a HBITMAP
ARGS:
hBmp [IN] handle of the bitmap
pBinfo [INOUT] pointer to a valid BITMAPINFO struct
RETURN VALUE:
TRUE on success
*/
BOOL _fillBITMAPINFO(HBITMAP hBmp, BITMAPINFO *pBinfo)
{
BITMAP bmp = { 0 };
if (!GetObject(hBmp, sizeof(BITMAP), &bmp)) {
return FALSE;
}
if (bmp.bmPlanes != 1 || bmp.bmBitsPixel < 24) {
return FALSE;
}
/* Getting info about the source bitmap
*/
ZeroMemory(pBinfo, sizeof(BITMAPINFO));
pBinfo->bmiHeader.biSize = sizeof(pBinfo->bmiHeader);
pBinfo->bmiHeader.biWidth = bmp.bmWidth;
pBinfo->bmiHeader.biHeight = bmp.bmHeight;
pBinfo->bmiHeader.biBitCount = bmp.bmBitsPixel;
pBinfo->bmiHeader.biPlanes = 1;
pBinfo->bmiHeader.biCompression = BI_RGB;
pBinfo->bmiHeader.biSizeImage = bmp.bmBitsPixel * bmp.bmWidth * bmp.bmHeight / 8;
return TRUE;
}
/* Lanczos8 filter, default radius 8
*/
double _Lanczos8(double x)
{
const double R = 8.0;
if (x < 0.0) {
x = -x;
}
if (x == 0.0) {
return 1;
}
if (x < R) {
x *= M_PI;
return R * sin(x) * sin(x / R) / (x * x);
}
return 0.0;
}
/* Lanczos3 filter, default radius 3
*/
double _Lanczos3(double x)
{
const double R = 3.0;
if (x < 0.0) {
x = -x;
}
if (x == 0.0) {
return 1;
}
if (x < R) {
x *= M_PI;
return R * sin(x) * sin(x / R) / (x * x);
}
return 0.0;
}
/* Hermite filter, default radius 1
*/
double _Hermite(double x)
{
if (x < 0.0) {
x = -x;
}
if (x < 1.0) {
return ((2.0 * x - 3) * x * x + 1.0);
}
return 0.0;
}
/* Box filter, default radius 0.5
*/
double _Box(double x)
{
if (x < 0.0) {
x = -x;
}
if (x <= 0.5) {
return 1.0;
}
return 0.0;
}
/* Trangle filter, default radius 1
*/
double _Triangle(double x)
{
if (x < 0.0) {
x = -x;
}
if (x < 1.0) {
return (1.0 - x);
}
return 0.0;
}
/* Bell filter, default radius 1.5
*/
double _Bell(double x)
{
if (x < 0.0) {
x = -x;
}
if (x < 0.5) {
return (0.75 - x * x);
}
if (x < 1.5) {
return (0.5 * pow(x - 1.5, 2.0));
}
return 0.0;
}
/* CubicSpline filter, default radius 2
*/
double _CubicSpline(double x)
{
double x2;
if (x < 0.0) {
x = -x;
}
if (x < 1.0) {
x2 = x * x;
return (0.5 * x2 * x - x2 + 2.0 / 3.0);
}
if (x < 2.0) {
x = 2.0 - x;
return (pow(x, 3.0) / 6.0);
}
return 0;
}
/* Mitchell filter, default radius 2.0
*/
double _Mitchell(double x)
{
const double C = 1.0 / 3.0;
double x2;
if (x < 0.0) {
x = -x;
}
x2 = x * x;
if (x < 1.0) {
x = (((12.0 - 9.0 * C - 6.0 * C) * (x * x2)) + ((-18.0 + 12.0 * C + 6.0 * C) * x2) + (6.0 - 2.0 * C));
return (x / 6.0);
}
if (x < 2.0) {
x = (((-C - 6.0 * C) * (x * x2)) + ((6.0 * C + 30.0 * C) * x2) + ((-12.0 * C - 48.0 * C) * x) + (8.0 * C + 24.0 * C));
return (x / 6.0);
}
return 0.0;
}
/* Cosine filter, default radius 1
*/
double _Cosine(double x)
{
if ((x >= -1.0) && (x <= 1.0)) {
return ((cos(x * M_PI) + 1.0) / 2.0);
}
return 0;
}
/* CatmullRom filter, default radius 2
*/
double _CatmullRom(double x)
{
//const double C = 0.5;
double x2;
if (x < 0.0) {
x = -x;
}
x2 = x * x;
if (x <= 1.0) {
return (1.5 * x2 * x - 2.5 * x2 + 1);
}
if (x <= 2.0) {
return (-0.5 * x2 * x + 2.5 * x2 - 4 * x + 2);
}
return 0;
}
/* Quadratic filter, default radius 1.5
*/
double _Quadratic(double x)
{
if (x < 0.0) {
x = -x;
}
if (x <= 0.5) {
return (-2.0 * x * x + 1);
}
if (x <= 1.5) {
return (x * x - 2.5 * x + 1.5);
}
return 0.0;
}
/* QuadraticBSpline filter, default radius 1.5
*/
double _QuadraticBSpline(double x)
{
if (x < 0.0) {
x = -x;
}
if (x <= 0.5) {
return (-x * x + 0.75);
}
if (x <= 1.5) {
return (0.5 * x * x - 1.5 * x + 1.125);
}
return 0.0;
}
/* CubicConvolution filter, default radius 3
*/
double _CubicConvolution(double x)
{
double x2;
if (x < 0.0) {
x = -x;
}
x2 = x * x;
if (x <= 1.0) {
return ((4.0 / 3.0) * x2 * x - (7.0 / 3.0) * x2 + 1.0);
}
if (x <= 2.0) {
return (-(7.0 / 12.0) * x2 * x + 3 * x2 - (59.0 / 12.0) * x + 2.5);
}
if (x <= 3.0) {
return ((1.0 / 12.0) * x2 * x - (2.0 / 3.0) * x2 + 1.75 * x - 1.5);
}
return 0;
}