summaryrefslogtreecommitdiff
path: root/plugins/FreeImage/Source/FreeImageToolkit/Resize.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2012-05-30 17:27:49 +0000
committerGeorge Hazan <george.hazan@gmail.com>2012-05-30 17:27:49 +0000
commit88708cffa15662dcd2755fce699112d24a10a087 (patch)
tree55d362220b42a52b52eaef2254f894c9a61fb4fd /plugins/FreeImage/Source/FreeImageToolkit/Resize.cpp
parent7fa5563a954339f3feeb156285ef56bfde7cbec8 (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/Resize.cpp')
-rw-r--r--plugins/FreeImage/Source/FreeImageToolkit/Resize.cpp1302
1 files changed, 656 insertions, 646 deletions
diff --git a/plugins/FreeImage/Source/FreeImageToolkit/Resize.cpp b/plugins/FreeImage/Source/FreeImageToolkit/Resize.cpp
index c98fe97391..5dcec62af0 100644
--- a/plugins/FreeImage/Source/FreeImageToolkit/Resize.cpp
+++ b/plugins/FreeImage/Source/FreeImageToolkit/Resize.cpp
@@ -1,646 +1,656 @@
-// ==========================================================
-// Upsampling / downsampling classes
-//
-// Design and implementation by
-// - Hervé Drolon (drolon@infonie.fr)
-// - Detlev Vendt (detlev.vendt@brillit.de)
-//
-// 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!
-// ==========================================================
-
-#include "Resize.h"
-
-/**
- Filter weights table.
- This class stores contribution information for an entire line (row or column).
-*/
-CWeightsTable::CWeightsTable(CGenericFilter *pFilter, DWORD uDstSize, DWORD uSrcSize) {
- DWORD u;
- double dWidth;
- double dFScale = 1.0;
- double dFilterWidth = pFilter->GetWidth();
-
- // scale factor
- double dScale = double(uDstSize) / double(uSrcSize);
-
- if(dScale < 1.0) {
- // minification
- dWidth = dFilterWidth / dScale;
- dFScale = dScale;
- } else {
- // magnification
- dWidth= dFilterWidth;
- }
-
- // allocate a new line contributions structure
- //
- // window size is the number of sampled pixels
- m_WindowSize = 2 * (int)ceil(dWidth) + 1;
- m_LineLength = uDstSize;
- // allocate list of contributions
- m_WeightTable = (Contribution*)malloc(m_LineLength * sizeof(Contribution));
- for(u = 0 ; u < m_LineLength ; u++) {
- // allocate contributions for every pixel
- m_WeightTable[u].Weights = (double*)malloc(m_WindowSize * sizeof(double));
- }
-
- // offset for discrete to continuous coordinate conversion
- double dOffset = (0.5 / dScale) - 0.5;
-
-
- for(u = 0; u < m_LineLength; u++) {
- // scan through line of contributions
- double dCenter = (double)u / dScale + dOffset; // reverse mapping
- // find the significant edge points that affect the pixel
- int iLeft = MAX (0, (int)floor (dCenter - dWidth));
- int iRight = MIN ((int)ceil (dCenter + dWidth), int(uSrcSize) - 1);
-
- // cut edge points to fit in filter window in case of spill-off
- if((iRight - iLeft + 1) > int(m_WindowSize)) {
- if(iLeft < (int(uSrcSize) - 1 / 2)) {
- iLeft++;
- } else {
- iRight--;
- }
- }
-
- m_WeightTable[u].Left = iLeft;
- m_WeightTable[u].Right = iRight;
-
- int iSrc = 0;
- double dTotalWeight = 0; // zero sum of weights
- for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
- // calculate weights
- double weight = dFScale * pFilter->Filter(dFScale * (dCenter - (double)iSrc));
- m_WeightTable[u].Weights[iSrc-iLeft] = weight;
- dTotalWeight += weight;
- }
- if((dTotalWeight > 0) && (dTotalWeight != 1)) {
- // normalize weight of neighbouring points
- for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
- // normalize point
- m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight;
- }
- // simplify the filter, discarding null weights at the right
- iSrc = iRight - iLeft;
- while(m_WeightTable[u].Weights[iSrc] == 0){
- m_WeightTable[u].Right--;
- iSrc--;
- if(m_WeightTable[u].Right == m_WeightTable[u].Left)
- break;
- }
-
- }
- }
-}
-
-CWeightsTable::~CWeightsTable() {
- for(DWORD u = 0; u < m_LineLength; u++) {
- // free contributions for every pixel
- free(m_WeightTable[u].Weights);
- }
- // free list of pixels contributions
- free(m_WeightTable);
-}
-
-// ---------------------------------------------
-
-/**
- CResizeEngine<br>
- This class performs filtered zoom. It scales an image to the desired dimensions with
- any of the CGenericFilter derived filter class.<br>
- It works with 8-, 24- and 32-bit buffers.<br><br>
-
- <b>References</b> : <br>
- [1] Paul Heckbert, C code to zoom raster images up or down, with nice filtering.
- UC Berkeley, August 1989. [online] http://www-2.cs.cmu.edu/afs/cs.cmu.edu/Web/People/ph/heckbert.html
- [2] Eran Yariv, Two Pass Scaling using Filters. The Code Project, December 1999.
- [online] http://www.codeproject.com/bitmap/2_pass_scaling.asp
-
-*/
-
-FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height) {
- DWORD src_width = FreeImage_GetWidth(src);
- DWORD src_height = FreeImage_GetHeight(src);
-
- unsigned redMask = FreeImage_GetRedMask(src);
- unsigned greenMask = FreeImage_GetGreenMask(src);
- unsigned blueMask = FreeImage_GetBlueMask(src);
-
- unsigned bpp = FreeImage_GetBPP(src);
- if(bpp == 1) {
- // convert output to 8-bit
- bpp = 8;
- }
-
- FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
-
- // allocate the dst image
- FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, bpp, redMask, greenMask, blueMask);
- if(!dst) return NULL;
-
- if(bpp == 8) {
- if(FreeImage_GetColorType(src) == FIC_MINISWHITE) {
- // build an inverted greyscale palette
- RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
- for(int i = 0; i < 256; i++) {
- dst_pal[i].rgbRed = dst_pal[i].rgbGreen =
- dst_pal[i].rgbBlue = (BYTE)(255 - i);
- }
- } else {
- // build a greyscale palette
- RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
- for(int i = 0; i < 256; i++) {
- dst_pal[i].rgbRed = dst_pal[i].rgbGreen =
- dst_pal[i].rgbBlue = (BYTE)i;
- }
- }
- }
-
- // decide which filtering order (xy or yx) is faster for this mapping by
- // counting convolution multiplies
-
- if(dst_width*src_height <= dst_height*src_width) {
- // xy filtering
- // -------------
-
- // allocate a temporary image
- FIBITMAP *tmp = FreeImage_AllocateT(image_type, dst_width, src_height, bpp, redMask, greenMask, blueMask);
- if(!tmp) {
- FreeImage_Unload(dst);
- return NULL;
- }
-
- // scale source image horizontally into temporary image
- horizontalFilter(src, src_width, src_height, tmp, dst_width, src_height);
-
- // scale temporary image vertically into result image
- verticalFilter(tmp, dst_width, src_height, dst, dst_width, dst_height);
-
- // free temporary image
- FreeImage_Unload(tmp);
-
- } else {
- // yx filtering
- // -------------
-
- // allocate a temporary image
- FIBITMAP *tmp = FreeImage_AllocateT(image_type, src_width, dst_height, bpp, redMask, greenMask, blueMask);
- if(!tmp) {
- FreeImage_Unload(dst);
- return NULL;
- }
-
- // scale source image vertically into temporary image
- verticalFilter(src, src_width, src_height, tmp, src_width, dst_height);
-
- // scale temporary image horizontally into result image
- horizontalFilter(tmp, src_width, dst_height, dst, dst_width, dst_height);
-
- // free temporary image
- FreeImage_Unload(tmp);
- }
-
- return dst;
-}
-
-
-/// Performs horizontal image filtering
-void CResizeEngine::horizontalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height) {
- if(dst_width == src_width) {
- // no scaling required, just copy
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- if(FreeImage_GetBPP(dst) != 8) break;
- for(unsigned y = 0; y < dst_height; y++) {
- // convert each row
- BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
- FreeImage_ConvertLine1To8(dst_bits, src_bits, dst_width);
- }
- }
- break;
-
- default:
- {
- BYTE *src_bits = FreeImage_GetBits(src);
- BYTE *dst_bits = FreeImage_GetBits(dst);
- memcpy(dst_bits, src_bits, dst_height * FreeImage_GetPitch(dst));
- }
- break;
- }
- }
- else {
- unsigned index; // pixel index
-
- // allocate and calculate the contributions
- CWeightsTable weightsTable(m_pFilter, dst_width, src_width);
-
- // step through rows
- switch(FreeImage_GetImageType(src)) {
- case FIT_BITMAP:
- {
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- // scale and convert to 8-bit
- if(FreeImage_GetBPP(dst) != 8) break;
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value = 0;
- int iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(x, i-iLeft);
-
- BYTE pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
- value += (weight * (double)pixel);
- }
- value *= 255;
-
- // clamp and place result in destination pixel
- dst_bits[x] = (BYTE)MIN(MAX((int)0, (int)(value + 0.5)), (int)255);
- }
- }
- }
- break;
-
- case 8:
- case 24:
- case 32:
- {
- // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
- unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value[4] = {0, 0, 0, 0}; // 4 = 32bpp max
- int iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(x, i-iLeft);
-
- index = i * bytespp;
- for (unsigned j = 0; j < bytespp; j++) {
- value[j] += (weight * (double)src_bits[index++]);
- }
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < bytespp; j++) {
- dst_bits[j] = (BYTE)MIN(MAX((int)0, (int)(value[j] + 0.5)), (int)255);
- }
-
- dst_bits += bytespp;
- }
- }
- }
- break;
- }
- }
- break;
-
- case FIT_UINT16:
- case FIT_RGB16:
- case FIT_RGBA16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- unsigned wordspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(WORD);
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y);
- WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value[4] = {0, 0, 0, 0}; // 4 = 64bpp max
- int iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(x, i-iLeft);
-
- index = i * wordspp;
- for (unsigned j = 0; j < wordspp; j++) {
- value[j] += (weight * (double)src_bits[index++]);
- }
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < wordspp; j++) {
- dst_bits[j] = (WORD)MIN(MAX((int)0, (int)(value[j] + 0.5)), (int)0xFFFF);
- }
-
- dst_bits += wordspp;
- }
- }
- }
- break;
-
- case FIT_FLOAT:
- case FIT_RGBF:
- case FIT_RGBAF:
- {
- // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
- unsigned floatspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(float);
-
- for(unsigned y = 0; y < dst_height; y++) {
- // scale each row
- float *src_bits = (float*)FreeImage_GetScanLine(src, y);
- float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
-
- for(unsigned x = 0; x < dst_width; x++) {
- // loop through row
- double value[4] = {0, 0, 0, 0}; // 4 = 64bpp max
- int iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(x, i-iLeft);
-
- index = i * floatspp;
- for (unsigned j = 0; j < floatspp; j++) {
- value[j] += (weight * (double)src_bits[index++]);
- }
- }
-
- // place result in destination pixel
- for (unsigned j = 0; j < floatspp; j++) {
- dst_bits[j] = (float)value[j];
- }
-
- dst_bits += floatspp;
- }
- }
- }
- break;
-
- }
- }
-}
-
-/// Performs vertical image filtering
-void CResizeEngine::verticalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height) {
- if(src_height == dst_height) {
- // no scaling required, just copy
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- if(FreeImage_GetBPP(dst) != 8) break;
- for(unsigned y = 0; y < dst_height; y++) {
- // convert each row
- BYTE *src_bits = FreeImage_GetScanLine(src, y);
- BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
- FreeImage_ConvertLine1To8(dst_bits, src_bits, dst_width);
- }
- }
- break;
-
- default:
- {
- BYTE *src_bits = FreeImage_GetBits(src);
- BYTE *dst_bits = FreeImage_GetBits(dst);
- memcpy(dst_bits, src_bits, dst_height * FreeImage_GetPitch(dst));
- }
- break;
- }
-
- }
- else {
- unsigned index; // pixel index
-
- // allocate and calculate the contributions
- CWeightsTable weightsTable(m_pFilter, dst_height, src_height);
-
-
- // step through columns
- switch(FreeImage_GetImageType(src)) {
- case FIT_BITMAP:
- {
- switch(FreeImage_GetBPP(src)) {
- case 1:
- {
- // scale and convert to 8-bit
- if(FreeImage_GetBPP(dst) != 8) break;
-
- unsigned src_pitch = FreeImage_GetPitch(src);
- unsigned dst_pitch = FreeImage_GetPitch(dst);
-
- for(unsigned x = 0; x < dst_width; x++) {
-
- // work on column x in dst
- BYTE *dst_bits = FreeImage_GetBits(dst) + x;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value = 0;
- int iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- BYTE *src_bits = FreeImage_GetScanLine(src, iLeft);
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(y, i-iLeft);
-
- BYTE pixel = (src_bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
- value += (weight * (double)pixel);
-
- src_bits += src_pitch;
- }
- value *= 255;
-
- // clamp and place result in destination pixel
- *dst_bits = (BYTE)MIN(MAX((int)0, (int)(value + 0.5)), (int)255);
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case 8:
- case 24:
- case 32:
- {
- // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
- unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
-
- unsigned src_pitch = FreeImage_GetPitch(src);
- unsigned dst_pitch = FreeImage_GetPitch(dst);
-
- for(unsigned x = 0; x < dst_width; x++) {
- index = x * bytespp;
-
- // work on column x in dst
- BYTE *dst_bits = FreeImage_GetBits(dst) + index;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value[4] = {0, 0, 0, 0}; // 4 = 32bpp max
- int iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- BYTE *src_bits = FreeImage_GetScanLine(src, iLeft) + index;
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(y, i-iLeft);
- for (unsigned j = 0; j < bytespp; j++) {
- value[j] += (weight * (double)src_bits[j]);
- }
-
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < bytespp; j++) {
- dst_bits[j] = (BYTE)MIN(MAX((int)0, (int)(value[j] + 0.5)), (int)255);
- }
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
- }
- }
- break;
-
- case FIT_UINT16:
- case FIT_RGB16:
- case FIT_RGBA16:
- {
- // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
- unsigned wordspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(WORD);
-
- unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
- unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
-
- for(unsigned x = 0; x < dst_width; x++) {
- index = x * wordspp;
-
- // work on column x in dst
- WORD *dst_bits = (WORD*)FreeImage_GetBits(dst) + index;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value[4] = {0, 0, 0, 0}; // 4 = 64bpp max
- int iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, iLeft) + index;
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(y, i-iLeft);
- for (unsigned j = 0; j < wordspp; j++) {
- value[j] += (weight * (double)src_bits[j]);
- }
-
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < wordspp; j++) {
- dst_bits[j] = (WORD)MIN(MAX((int)0, (int)(value[j] + 0.5)), (int)0xFFFF);
- }
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- case FIT_FLOAT:
- case FIT_RGBF:
- case FIT_RGBAF:
- {
- // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
- unsigned floatspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(float);
-
- unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(float);
- unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(float);
-
- for(unsigned x = 0; x < dst_width; x++) {
- index = x * floatspp;
-
- // work on column x in dst
- float *dst_bits = (float*)FreeImage_GetBits(dst) + index;
-
- // scale each column
- for(unsigned y = 0; y < dst_height; y++) {
- // loop through column
- double value[4] = {0, 0, 0, 0}; // 4 = 64bpp max
- int iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
- int iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
-
- float *src_bits = (float*)FreeImage_GetScanLine(src, iLeft) + index;
-
- for(int i = iLeft; i <= iRight; i++) {
- // scan between boundaries
- // accumulate weighted effect of each neighboring pixel
- double weight = weightsTable.getWeight(y, i-iLeft);
- for (unsigned j = 0; j < floatspp; j++) {
- value[j] += (weight * (double)src_bits[j]);
- }
-
- src_bits += src_pitch;
- }
-
- // clamp and place result in destination pixel
- for (unsigned j = 0; j < floatspp; j++) {
- dst_bits[j] = (float)value[j];
- }
-
- dst_bits += dst_pitch;
- }
- }
- }
- break;
-
- }
- }
-}
-
+// ==========================================================
+// Upsampling / downsampling classes
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+// - Detlev Vendt (detlev.vendt@brillit.de)
+//
+// 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!
+// ==========================================================
+
+#include "Resize.h"
+
+/**
+ Filter weights table.
+ This class stores contribution information for an entire line (row or column).
+*/
+CWeightsTable::CWeightsTable(CGenericFilter *pFilter, unsigned uDstSize, unsigned uSrcSize) {
+ unsigned u;
+ double dWidth;
+ double dFScale = 1.0;
+ const double dFilterWidth = pFilter->GetWidth();
+
+ // scale factor
+ const double dScale = double(uDstSize) / double(uSrcSize);
+
+ if(dScale < 1.0) {
+ // minification
+ dWidth = dFilterWidth / dScale;
+ dFScale = dScale;
+ } else {
+ // magnification
+ dWidth= dFilterWidth;
+ }
+
+ // allocate a new line contributions structure
+ //
+ // window size is the number of sampled pixels
+ m_WindowSize = 2 * (int)ceil(dWidth) + 1;
+ m_LineLength = uDstSize;
+ // allocate list of contributions
+ m_WeightTable = (Contribution*)malloc(m_LineLength * sizeof(Contribution));
+ for(u = 0 ; u < m_LineLength ; u++) {
+ // allocate contributions for every pixel
+ m_WeightTable[u].Weights = (double*)malloc(m_WindowSize * sizeof(double));
+ }
+
+ // offset for discrete to continuous coordinate conversion
+ const double dOffset = (0.5 / dScale) - 0.5;
+
+
+ for(u = 0; u < m_LineLength; u++) {
+ // scan through line of contributions
+ const double dCenter = (double)u / dScale + dOffset; // reverse mapping
+ // find the significant edge points that affect the pixel
+ int iLeft = MAX (0, (int)floor (dCenter - dWidth));
+ int iRight = MIN ((int)ceil (dCenter + dWidth), int(uSrcSize) - 1);
+
+ // cut edge points to fit in filter window in case of spill-off
+ if((iRight - iLeft + 1) > int(m_WindowSize)) {
+ if(iLeft < (int(uSrcSize) - 1 / 2)) {
+ iLeft++;
+ } else {
+ iRight--;
+ }
+ }
+
+ m_WeightTable[u].Left = iLeft;
+ m_WeightTable[u].Right = iRight;
+
+ int iSrc = 0;
+ double dTotalWeight = 0; // zero sum of weights
+ for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
+ // calculate weights
+ const double weight = dFScale * pFilter->Filter(dFScale * (dCenter - (double)iSrc));
+ m_WeightTable[u].Weights[iSrc-iLeft] = weight;
+ dTotalWeight += weight;
+ }
+ if((dTotalWeight > 0) && (dTotalWeight != 1)) {
+ // normalize weight of neighbouring points
+ for(iSrc = iLeft; iSrc <= iRight; iSrc++) {
+ // normalize point
+ m_WeightTable[u].Weights[iSrc-iLeft] /= dTotalWeight;
+ }
+ // simplify the filter, discarding null weights at the right
+ iSrc = iRight - iLeft;
+ while(m_WeightTable[u].Weights[iSrc] == 0){
+ m_WeightTable[u].Right--;
+ iSrc--;
+ if(m_WeightTable[u].Right == m_WeightTable[u].Left)
+ break;
+ }
+
+ }
+ }
+}
+
+CWeightsTable::~CWeightsTable() {
+ for(unsigned u = 0; u < m_LineLength; u++) {
+ // free contributions for every pixel
+ free(m_WeightTable[u].Weights);
+ }
+ // free list of pixels contributions
+ free(m_WeightTable);
+}
+
+// ---------------------------------------------
+
+/**
+ CResizeEngine<br>
+ This class performs filtered zoom. It scales an image to the desired dimensions with
+ any of the CGenericFilter derived filter class.<br>
+ It works with 8-, 24- and 32-bit buffers.<br><br>
+
+ <b>References</b> : <br>
+ [1] Paul Heckbert, C code to zoom raster images up or down, with nice filtering.
+ UC Berkeley, August 1989. [online] http://www-2.cs.cmu.edu/afs/cs.cmu.edu/Web/People/ph/heckbert.html
+ [2] Eran Yariv, Two Pass Scaling using Filters. The Code Project, December 1999.
+ [online] http://www.codeproject.com/bitmap/2_pass_scaling.asp
+
+*/
+
+FIBITMAP* CResizeEngine::scale(FIBITMAP *src, unsigned dst_width, unsigned dst_height) {
+ unsigned src_width = FreeImage_GetWidth(src);
+ unsigned src_height = FreeImage_GetHeight(src);
+
+ unsigned redMask = FreeImage_GetRedMask(src);
+ unsigned greenMask = FreeImage_GetGreenMask(src);
+ unsigned blueMask = FreeImage_GetBlueMask(src);
+
+ unsigned bpp = FreeImage_GetBPP(src);
+ if(bpp == 1) {
+ // convert output to 8-bit
+ bpp = 8;
+ }
+
+ FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src);
+
+ // allocate the dst image
+ FIBITMAP *dst = FreeImage_AllocateT(image_type, dst_width, dst_height, bpp, redMask, greenMask, blueMask);
+ if(!dst) return NULL;
+
+ if(bpp == 8) {
+ if(FreeImage_GetColorType(src) == FIC_MINISWHITE) {
+ // build an inverted greyscale palette
+ RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
+ for(unsigned i = 0; i < 256; i++) {
+ dst_pal[i].rgbRed = dst_pal[i].rgbGreen = dst_pal[i].rgbBlue = (BYTE)(255 - i);
+ }
+ } else {
+ // build a greyscale palette
+ RGBQUAD *dst_pal = FreeImage_GetPalette(dst);
+ for(unsigned i = 0; i < 256; i++) {
+ dst_pal[i].rgbRed = dst_pal[i].rgbGreen = dst_pal[i].rgbBlue = (BYTE)i;
+ }
+ }
+ }
+
+ /**
+ Decide which filtering order (xy or yx) is faster for this mapping.
+ --- The theory ---
+ Try to minimize calculations by counting the number of convolution multiplies
+ if(dst_width*src_height <= src_width*dst_height) {
+ // xy filtering
+ } else {
+ // yx filtering
+ }
+ --- The practice ---
+ Try to minimize calculations by counting the number of vertical convolutions (the most time consuming task)
+ if(dst_width*dst_height <= src_width*dst_height) {
+ // xy filtering
+ } else {
+ // yx filtering
+ }
+ */
+
+ if(dst_width <= src_width) {
+ // xy filtering
+ // -------------
+
+ // allocate a temporary image
+ FIBITMAP *tmp = FreeImage_AllocateT(image_type, dst_width, src_height, bpp, redMask, greenMask, blueMask);
+ if(!tmp) {
+ FreeImage_Unload(dst);
+ return NULL;
+ }
+
+ // scale source image horizontally into temporary image
+ horizontalFilter(src, src_width, src_height, tmp, dst_width, src_height);
+
+ // scale temporary image vertically into result image
+ verticalFilter(tmp, dst_width, src_height, dst, dst_width, dst_height);
+
+ // free temporary image
+ FreeImage_Unload(tmp);
+
+ } else {
+ // yx filtering
+ // -------------
+
+ // allocate a temporary image
+ FIBITMAP *tmp = FreeImage_AllocateT(image_type, src_width, dst_height, bpp, redMask, greenMask, blueMask);
+ if(!tmp) {
+ FreeImage_Unload(dst);
+ return NULL;
+ }
+
+ // scale source image vertically into temporary image
+ verticalFilter(src, src_width, src_height, tmp, src_width, dst_height);
+
+ // scale temporary image horizontally into result image
+ horizontalFilter(tmp, src_width, dst_height, dst, dst_width, dst_height);
+
+ // free temporary image
+ FreeImage_Unload(tmp);
+ }
+
+ return dst;
+}
+
+
+/// Performs horizontal image filtering
+void CResizeEngine::horizontalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height) {
+ if(dst_width == src_width) {
+ // no scaling required, just copy
+ switch(FreeImage_GetBPP(src)) {
+ case 1:
+ {
+ if(FreeImage_GetBPP(dst) != 8) break;
+ for(unsigned y = 0; y < dst_height; y++) {
+ // convert each row
+ BYTE *src_bits = FreeImage_GetScanLine(src, y);
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+ FreeImage_ConvertLine1To8(dst_bits, src_bits, dst_width);
+ }
+ }
+ break;
+
+ default:
+ {
+ const BYTE *src_bits = FreeImage_GetBits(src);
+ BYTE *dst_bits = FreeImage_GetBits(dst);
+ memcpy(dst_bits, src_bits, dst_height * FreeImage_GetPitch(dst));
+ }
+ break;
+ }
+ }
+ else {
+
+ // allocate and calculate the contributions
+ CWeightsTable weightsTable(m_pFilter, dst_width, src_width);
+
+ // step through rows
+ switch(FreeImage_GetImageType(src)) {
+ case FIT_BITMAP:
+ {
+ switch(FreeImage_GetBPP(src)) {
+ case 1:
+ {
+ // scale and convert to 8-bit
+ if(FreeImage_GetBPP(dst) != 8) break;
+
+ for(unsigned y = 0; y < dst_height; y++) {
+ // scale each row
+ const BYTE *src_bits = FreeImage_GetScanLine(src, y);
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ double value = 0;
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i-iLeft);
+
+ const BYTE pixel = (src_bits[i >> 3] & (0x80 >> (i & 0x07))) != 0;
+ value += (weight * (double)pixel);
+ }
+ value *= 255;
+
+ // clamp and place result in destination pixel
+ dst_bits[x] = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 255);
+ }
+ }
+ }
+ break;
+
+ case 8:
+ case 24:
+ case 32:
+ {
+ // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
+ const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
+
+ for(unsigned y = 0; y < dst_height; y++) {
+ // scale each row
+ const BYTE *src_bits = FreeImage_GetScanLine(src, y);
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ double value[4] = {0, 0, 0, 0}; // 4 = 32 bpp max
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i-iLeft);
+
+ unsigned index = i * bytespp; // pixel index
+ for (unsigned j = 0; j < bytespp; j++) {
+ value[j] += (weight * (double)src_bits[index++]);
+ }
+ }
+
+ // clamp and place result in destination pixel
+ for (unsigned j = 0; j < bytespp; j++) {
+ dst_bits[j] = (BYTE)CLAMP<int>((int)(value[j] + 0.5), 0, 0xFF);
+ }
+
+ dst_bits += bytespp;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case FIT_UINT16:
+ case FIT_RGB16:
+ case FIT_RGBA16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(WORD);
+
+ for(unsigned y = 0; y < dst_height; y++) {
+ // scale each row
+ const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y);
+ WORD *dst_bits = (WORD*)FreeImage_GetScanLine(dst, y);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ double value[4] = {0, 0, 0, 0}; // 4 = 64 bpp max
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i-iLeft);
+
+ unsigned index = i * wordspp; // pixel index
+ for (unsigned j = 0; j < wordspp; j++) {
+ value[j] += (weight * (double)src_bits[index++]);
+ }
+ }
+
+ // clamp and place result in destination pixel
+ for (unsigned j = 0; j < wordspp; j++) {
+ dst_bits[j] = (WORD)CLAMP<int>((int)(value[j] + 0.5), 0, 0xFFFF);
+ }
+
+ dst_bits += wordspp;
+ }
+ }
+ }
+ break;
+
+ case FIT_FLOAT:
+ case FIT_RGBF:
+ case FIT_RGBAF:
+ {
+ // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
+ const unsigned floatspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(float);
+
+ for(unsigned y = 0; y < dst_height; y++) {
+ // scale each row
+ const float *src_bits = (float*)FreeImage_GetScanLine(src, y);
+ float *dst_bits = (float*)FreeImage_GetScanLine(dst, y);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ // loop through row
+ double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
+ const unsigned iLeft = weightsTable.getLeftBoundary(x); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(x); // retrieve right boundary
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(x, i-iLeft);
+
+ unsigned index = i * floatspp; // pixel index
+ for (unsigned j = 0; j < floatspp; j++) {
+ value[j] += (weight * (double)src_bits[index++]);
+ }
+ }
+
+ // place result in destination pixel
+ for (unsigned j = 0; j < floatspp; j++) {
+ dst_bits[j] = (float)value[j];
+ }
+
+ dst_bits += floatspp;
+ }
+ }
+ }
+ break;
+
+ }
+ }
+}
+
+/// Performs vertical image filtering
+void CResizeEngine::verticalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height) {
+ if(src_height == dst_height) {
+ // no scaling required, just copy
+ switch(FreeImage_GetBPP(src)) {
+ case 1:
+ {
+ if(FreeImage_GetBPP(dst) != 8) break;
+ for(unsigned y = 0; y < dst_height; y++) {
+ // convert each row
+ BYTE *src_bits = FreeImage_GetScanLine(src, y);
+ BYTE *dst_bits = FreeImage_GetScanLine(dst, y);
+ FreeImage_ConvertLine1To8(dst_bits, src_bits, dst_width);
+ }
+ }
+ break;
+
+ default:
+ {
+ const BYTE *src_bits = FreeImage_GetBits(src);
+ BYTE *dst_bits = FreeImage_GetBits(dst);
+ memcpy(dst_bits, src_bits, dst_height * FreeImage_GetPitch(dst));
+ }
+ break;
+ }
+
+ }
+ else {
+
+ // allocate and calculate the contributions
+ CWeightsTable weightsTable(m_pFilter, dst_height, src_height);
+
+ // step through columns
+ switch(FreeImage_GetImageType(src)) {
+ case FIT_BITMAP:
+ {
+ switch(FreeImage_GetBPP(src)) {
+ case 1:
+ {
+ // scale and convert to 8-bit
+ if(FreeImage_GetBPP(dst) != 8) break;
+
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+
+ // work on column x in dst
+ BYTE *dst_bits = FreeImage_GetBits(dst) + x;
+
+ // scale each column
+ for(unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ double value = 0;
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
+
+ BYTE *src_bits = FreeImage_GetScanLine(src, iLeft);
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i-iLeft);
+
+ const BYTE pixel = (src_bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
+ value += (weight * (double)pixel);
+
+ src_bits += src_pitch;
+ }
+ value *= 255;
+
+ // clamp and place result in destination pixel
+ *dst_bits = (BYTE)CLAMP<int>((int)(value + 0.5), 0, 0xFF);
+
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case 8:
+ case 24:
+ case 32:
+ {
+ // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit)
+ const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
+
+ const unsigned src_pitch = FreeImage_GetPitch(src);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ const unsigned index = x * bytespp; // pixel index
+
+ // work on column x in dst
+ BYTE *dst_bits = FreeImage_GetBits(dst) + index;
+
+ // scale each column
+ for(unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ double value[4] = {0, 0, 0, 0}; // 4 = 32 bpp max
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
+
+ const BYTE *src_bits = FreeImage_GetScanLine(src, iLeft) + index;
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i-iLeft);
+ for (unsigned j = 0; j < bytespp; j++) {
+ value[j] += (weight * (double)src_bits[j]);
+ }
+
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ for (unsigned j = 0; j < bytespp; j++) {
+ dst_bits[j] = (BYTE)CLAMP<int>((int)(value[j] + 0.5), 0, 0xFF);
+ }
+
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case FIT_UINT16:
+ case FIT_RGB16:
+ case FIT_RGBA16:
+ {
+ // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit)
+ const unsigned wordspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(WORD);
+
+ const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ const unsigned index = x * wordspp; // pixel index
+
+ // work on column x in dst
+ WORD *dst_bits = (WORD*)FreeImage_GetBits(dst) + index;
+
+ // scale each column
+ for(unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ double value[4] = {0, 0, 0, 0}; // 4 = 64 bpp max
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
+
+ const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, iLeft) + index;
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i-iLeft);
+ for (unsigned j = 0; j < wordspp; j++) {
+ value[j] += (weight * (double)src_bits[j]);
+ }
+
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ for (unsigned j = 0; j < wordspp; j++) {
+ dst_bits[j] = (WORD)CLAMP<int>((int)(value[j] + 0.5), 0, 0xFFFF);
+ }
+
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ case FIT_FLOAT:
+ case FIT_RGBF:
+ case FIT_RGBAF:
+ {
+ // Calculate the number of floats per pixel (1 for 32-bit, 3 for 96-bit or 4 for 128-bit)
+ const unsigned floatspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(float);
+
+ const unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(float);
+ const unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(float);
+
+ for(unsigned x = 0; x < dst_width; x++) {
+ const unsigned index = x * floatspp; // pixel index
+
+ // work on column x in dst
+ float *dst_bits = (float*)FreeImage_GetBits(dst) + index;
+
+ // scale each column
+ for(unsigned y = 0; y < dst_height; y++) {
+ // loop through column
+ double value[4] = {0, 0, 0, 0}; // 4 = 128 bpp max
+ const unsigned iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary
+ const unsigned iRight = weightsTable.getRightBoundary(y); // retrieve right boundary
+
+ const float *src_bits = (float*)FreeImage_GetScanLine(src, iLeft) + index;
+
+ for(unsigned i = iLeft; i <= iRight; i++) {
+ // scan between boundaries
+ // accumulate weighted effect of each neighboring pixel
+ const double weight = weightsTable.getWeight(y, i-iLeft);
+ for (unsigned j = 0; j < floatspp; j++) {
+ value[j] += (weight * (double)src_bits[j]);
+ }
+
+ src_bits += src_pitch;
+ }
+
+ // clamp and place result in destination pixel
+ for (unsigned j = 0; j < floatspp; j++) {
+ dst_bits[j] = (float)value[j];
+ }
+
+ dst_bits += dst_pitch;
+ }
+ }
+ }
+ break;
+
+ }
+ }
+}
+