244 lines
7.2 KiB
C++
244 lines
7.2 KiB
C++
|
#pragma once
|
||
|
#include <stdint.h>
|
||
|
#include <algorithm>
|
||
|
|
||
|
namespace Etc
|
||
|
{
|
||
|
|
||
|
enum FilterEnums
|
||
|
{
|
||
|
MaxFilterSize = 32
|
||
|
};
|
||
|
|
||
|
enum WrapFlags
|
||
|
{
|
||
|
FILTER_WRAP_NONE = 0,
|
||
|
FILTER_WRAP_X = 0x1,
|
||
|
FILTER_WRAP_Y = 0x2
|
||
|
};
|
||
|
|
||
|
typedef struct tagFilterWeights
|
||
|
{
|
||
|
int first;
|
||
|
int numWeights;
|
||
|
double weight[MaxFilterSize * 2 + 1];
|
||
|
} FilterWeights;
|
||
|
|
||
|
typedef struct tagRGBCOLOR
|
||
|
{
|
||
|
union
|
||
|
{
|
||
|
uint32_t ulColor;
|
||
|
uint8_t rgba[4];
|
||
|
};
|
||
|
} RGBCOLOR;
|
||
|
|
||
|
|
||
|
double FilterBox( double t );
|
||
|
double FilterLinear( double t );
|
||
|
double FilterLanczos3( double t );
|
||
|
|
||
|
int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
|
||
|
RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) );
|
||
|
void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
|
||
|
RGBCOLOR *pDstImage, int dstWidth, int dstHeight );
|
||
|
|
||
|
|
||
|
void CalcContributions(int srcSize, int destSize, double filterSize, bool wrap, double(*FilterProc)(double), FilterWeights contrib[]);
|
||
|
|
||
|
template <typename T>
|
||
|
void FilterResample(T *pSrcImage, int srcWidth, int srcHeight, T *pDstImage, int dstWidth, int dstHeight)
|
||
|
{
|
||
|
float xScale;
|
||
|
float yScale;
|
||
|
|
||
|
T *pSrcPixel;
|
||
|
T *pDstPixel;
|
||
|
|
||
|
xScale = (float)srcWidth / dstWidth;
|
||
|
yScale = (float)srcHeight / dstHeight;
|
||
|
|
||
|
for (int iRow = 0; iRow < dstHeight; iRow++)
|
||
|
{
|
||
|
for (int iCol = 0; iCol < dstWidth; iCol++)
|
||
|
{
|
||
|
int samples;
|
||
|
int iFirstSampleRow;
|
||
|
int iFirstSampleCol;
|
||
|
int iLastSampleRow;
|
||
|
int iLastSampleCol;
|
||
|
float red;
|
||
|
float green;
|
||
|
float blue;
|
||
|
float alpha;
|
||
|
|
||
|
iFirstSampleRow = (int)(iRow * yScale);
|
||
|
iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
|
||
|
if (iLastSampleRow >= srcHeight)
|
||
|
{
|
||
|
iLastSampleRow = srcHeight - 1;
|
||
|
}
|
||
|
|
||
|
iFirstSampleCol = (int)(iCol * xScale);
|
||
|
iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
|
||
|
if (iLastSampleCol >= srcWidth)
|
||
|
{
|
||
|
iLastSampleCol = srcWidth - 1;
|
||
|
}
|
||
|
|
||
|
samples = 0;
|
||
|
red = 0.f;
|
||
|
green = 0.f;
|
||
|
blue = 0.f;
|
||
|
alpha = 0.f;
|
||
|
for (int iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++)
|
||
|
{
|
||
|
for (int iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++)
|
||
|
{
|
||
|
pSrcPixel = pSrcImage + (iSampleRow * srcWidth + iSampleCol) * 4;
|
||
|
red += static_cast<float>(pSrcPixel[0]);
|
||
|
green += static_cast<float>(pSrcPixel[1]);
|
||
|
blue += static_cast<float>(pSrcPixel[2]);
|
||
|
alpha += static_cast<float>(pSrcPixel[3]);
|
||
|
|
||
|
samples++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pDstPixel = pDstImage + (iRow * dstWidth + iCol) * 4;
|
||
|
if (samples > 0)
|
||
|
{
|
||
|
pDstPixel[0] = static_cast<T>(red / samples);
|
||
|
pDstPixel[1] = static_cast<T>(green / samples);
|
||
|
pDstPixel[2] = static_cast<T>(blue / samples);
|
||
|
pDstPixel[3] = static_cast<T>(alpha / samples);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDstPixel[0] = static_cast<T>(red);
|
||
|
pDstPixel[1] = static_cast<T>(green);
|
||
|
pDstPixel[2] = static_cast<T>(blue);
|
||
|
pDstPixel[3] = static_cast<T>(alpha);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//**-------------------------------------------------------------------------
|
||
|
//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
|
||
|
//** int srcWidth, int srcHeight,
|
||
|
//** RGBCOLOR *pDestImage,
|
||
|
//** int destWidth, int destHeight,
|
||
|
//** double (*FilterProc)(double) )
|
||
|
//** Returns: 0 on failure and 1 on success
|
||
|
//** Description: Filters a 2d image with a two pass filter by averaging the
|
||
|
//** weighted contributions of the pixels within the filter region. The
|
||
|
//** contributions are determined by a weighting function parameter.
|
||
|
//**-------------------------------------------------------------------------
|
||
|
template <typename T>
|
||
|
int FilterTwoPass(T *pSrcImage, int srcWidth, int srcHeight,
|
||
|
T *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double(*FilterProc)(double))
|
||
|
{
|
||
|
const int numComponents = 4;
|
||
|
FilterWeights *contrib;
|
||
|
T *pPixel;
|
||
|
T *pTempImage;
|
||
|
double dRed;
|
||
|
double dGreen;
|
||
|
double dBlue;
|
||
|
double dAlpha;
|
||
|
double filterSize = 3.0;
|
||
|
|
||
|
int maxDim = (srcWidth>srcHeight) ? srcWidth : srcHeight;
|
||
|
contrib = new FilterWeights[maxDim];
|
||
|
|
||
|
//**------------------------------------------------------------------------
|
||
|
//** Need to create a temporary image to stuff the horizontally scaled image
|
||
|
//**------------------------------------------------------------------------
|
||
|
pTempImage = new T[destWidth * srcHeight * numComponents];
|
||
|
if (pTempImage == NULL)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//**-------------------------------------------------------
|
||
|
//** Horizontally filter the image into the temporary image
|
||
|
//**-------------------------------------------------------
|
||
|
bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
|
||
|
CalcContributions(srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib);
|
||
|
for (int iRow = 0; iRow < srcHeight; iRow++)
|
||
|
{
|
||
|
for (int iCol = 0; iCol < destWidth; iCol++)
|
||
|
{
|
||
|
dRed = 0;
|
||
|
dGreen = 0;
|
||
|
dBlue = 0;
|
||
|
dAlpha = 0;
|
||
|
|
||
|
for (int iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++)
|
||
|
{
|
||
|
int iSrcCol = iWeight + contrib[iCol].first;
|
||
|
if(bWrapHorizontal)
|
||
|
{
|
||
|
iSrcCol = (iSrcCol < 0)?(srcWidth+iSrcCol):(iSrcCol >= srcWidth)?(iSrcCol-srcWidth):iSrcCol;
|
||
|
}
|
||
|
T* pSrcPixel = pSrcImage + ((iRow * srcWidth) + iSrcCol)*numComponents;
|
||
|
dRed += contrib[iCol].weight[iWeight] * pSrcPixel[0];
|
||
|
dGreen += contrib[iCol].weight[iWeight] * pSrcPixel[1];
|
||
|
dBlue += contrib[iCol].weight[iWeight] * pSrcPixel[2];
|
||
|
dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel[3];
|
||
|
}
|
||
|
|
||
|
pPixel = pTempImage + ((iRow * destWidth) + iCol)*numComponents;
|
||
|
pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
|
||
|
pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
|
||
|
pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
|
||
|
pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//**-------------------------------------------------------
|
||
|
//** Vertically filter the image into the destination image
|
||
|
//**-------------------------------------------------------
|
||
|
bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
|
||
|
CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
|
||
|
for (int iCol = 0; iCol < destWidth; iCol++)
|
||
|
{
|
||
|
for (int iRow = 0; iRow < destHeight; iRow++)
|
||
|
{
|
||
|
dRed = 0;
|
||
|
dGreen = 0;
|
||
|
dBlue = 0;
|
||
|
dAlpha = 0;
|
||
|
|
||
|
for (int iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++)
|
||
|
{
|
||
|
int iSrcRow = iWeight + contrib[iRow].first;
|
||
|
if (bWrapVertical)
|
||
|
{
|
||
|
iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
|
||
|
}
|
||
|
T* pSrcPixel = pTempImage + ((iSrcRow * destWidth) + iCol)*numComponents;
|
||
|
dRed += contrib[iRow].weight[iWeight] * pSrcPixel[0];
|
||
|
dGreen += contrib[iRow].weight[iWeight] * pSrcPixel[1];
|
||
|
dBlue += contrib[iRow].weight[iWeight] * pSrcPixel[2];
|
||
|
dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel[3];
|
||
|
}
|
||
|
|
||
|
pPixel = pDestImage + ((iRow * destWidth) + iCol)*numComponents;
|
||
|
pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
|
||
|
pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
|
||
|
pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
|
||
|
pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete[] pTempImage;
|
||
|
delete[] contrib;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|