📄 resample.c
字号:
DWORD * tb; // Temporary (intermediate buffer)
double intensity[COLOR_COMPONENTS]; // 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, iw * 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 *) GlobalAlloc(0, ow * ih * sizeof(DWORD));
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 *) GlobalAlloc(0, ow * MAX_CONTRIBS * sizeof(double)); /* weights */
h_pixel = (int *) GlobalAlloc(0, ow * MAX_CONTRIBS * sizeof(int)); /* the contributing pixels */
h_count = (int *) GlobalAlloc(0, ow * sizeof(int)); /* how may contributions for the target pixel */
h_wsum = (double *)GlobalAlloc(0, ow * sizeof(double)); /* 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 *) GlobalAlloc(0, oh * MAX_CONTRIBS * sizeof(double)); /* Weights */
v_pixel = (int *) GlobalAlloc(0, oh * MAX_CONTRIBS * sizeof(int)); /* The contributing pixels */
v_count = (int *) GlobalAlloc(0, oh * sizeof(int)); /* How may contributions for the target pixel */
v_wsum = (double *)GlobalAlloc(0, oh * sizeof(double)); /* 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) GlobalFree(tb);
if (h_weight) GlobalFree(h_weight);
if (h_pixel) GlobalFree(h_pixel);
if (h_count) GlobalFree(h_count);
if (h_wsum) GlobalFree(h_wsum);
if (v_weight) GlobalFree(v_weight);
if (v_pixel) GlobalFree(v_pixel);
if (v_count) GlobalFree(v_count);
if (v_wsum) GlobalFree(v_wsum);
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;
ZeroMemory(& bmp, sizeof(bmp));
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(*pBinfo));
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -