📄 resample.c
字号:
// Resample.cpp : Defines the entry point for the DLL application.
//
#include <windows.h>
#define _USE_MATH_DEFINES
#define M_PI 3.14159265358979323846
#include <math.h>
#include <assert.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);
#ifndef WINCE
static HBITMAP _createResampledBitmap(HDC hdc, HBITMAP hBmpSource, DWORD dwWidth, DWORD dwHeight, PFN_FILTER pFnFilter, double dRadius);
#else
static BOOL _shrinkRGB24(LPBYTE source, int srcwidth, int srcheight, LPBYTE destion, int destwidth, int destheight, PFN_FILTER filter, double radius);
#endif
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
) {
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
#ifndef WINCE
/*-> 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);
}
#else
BOOL ShrinkRGB32(LPBYTE source, int srcwidth, int srcheight, LPBYTE destion, int destwidth, int destheight, unsigned filter) {
BOOL Result = FALSE;
double(* pFnFilter)(double);
double dRadius;
if (_setResampleFilter(filter, &pFnFilter, &dRadius) == FALSE) {
SetLastError(E_UNABLE_TO_SET_FILTER);
return FALSE;
}
return _shrinkRGB24(source, srcwidth, srcheight, destion, destwidth, destheight, pFnFilter, dRadius);
}
BOOL _shrinkRGB24(LPBYTE source, int srcwidth, int srcheight, LPBYTE destion, int destwidth, int destheight, PFN_FILTER filter, double radius) {
BOOL Result = FALSE;
if (_resample(source, srcwidth, srcheight,
destion, destwidth, destheight,
filter, radius) == FALSE) {
SetLastError(E_RESAMPLE_ERROR);
return Result;
}
return Result;
}
#endif
/* 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
*/
#ifndef WINCE
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);
}
#endif
/* 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;
}
#ifndef WINCE
/* 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 = GlobalAlloc(0, binfoSource.bmiHeader.biSizeImage);
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 = GlobalAlloc(0, binfoTarget.bmiHeader.biSizeImage);
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) GlobalFree(pbSource);
if (pbTarget) GlobalFree(pbTarget);
if (fResult == FALSE) {
if (hBmpTarget) {
DeleteObject(hBmpTarget);
hBmpTarget = NULL;
}
}
return hBmpTarget;
}/* <- CreateResampledBitmap */
#endif // WINCE
/* _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;
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]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -