Files
GTASource/rage/scaleform/Src/GRenderer/GResizeImage.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

863 lines
28 KiB
C++

/**********************************************************************
Filename : GResizeImage.cpp
Content : Bitmap Image resizing with filtering
Created : 2007
Authors : Maxim Shemanarev
Copyright : (c) 2001-2006 Scaleform Corp. All Rights Reserved.
Notes :
Licensees may use this file in accordance with the valid Scaleform
Commercial License Agreement provided with the software.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
----------------------------------------------------------------------
The code of these classes was taken from the Anti-Grain Geometry
Project and modified for the use by Scaleform.
Permission to use without restrictions is hereby granted to
Scaleform Corporation by the author of Anti-Grain Geometry Project.
See http://antigtain.com for details.
**********************************************************************/
#include "GResizeImage.h"
//--------------------------------------------------------------------
void GImageFilterLut::reallocLut(Float radius)
{
Radius = radius;
Diameter = unsigned(ceilf(radius)) * 2;
Start = -int(Diameter / 2 - 1);
unsigned size = Diameter << GImgSubpixelShift;
if (size > WeightArray.GetSize())
WeightArray.Resize(size);
}
//--------------------------------------------------------------------
// This function normalizes integer values and corrects the rounding
// errors. It corrects the filter values according to the rule
// of 1.0 which means that any sum of pixel weights must be equal to 1.0.
// So, the filter function must produce a graph of the proper shape.
//--------------------------------------------------------------------
void GImageFilterLut::Normalize()
{
unsigned i;
int flip = 1;
for(i = 0; i < GImgSubpixelScale; i++)
{
for(;;)
{
int sum = 0;
unsigned j;
for(j = 0; j < Diameter; j++)
{
sum += WeightArray[j * GImgSubpixelScale + i];
}
if(sum == GImgFilterScale) break;
Float k = Float(GImgFilterScale) / Float(sum);
sum = 0;
for(j = 0; j < Diameter; j++)
{
sum += WeightArray[j * GImgSubpixelScale + i] =
SInt16(gfrnd(WeightArray[j * GImgSubpixelScale + i] * k));
}
sum -= GImgFilterScale;
int inc = (sum > 0) ? -1 : 1;
for(j = 0; j < Diameter && sum; j++)
{
flip ^= 1;
unsigned idx = flip ? Diameter/2 + j/2 : Diameter/2 - j/2;
int v = WeightArray[idx * GImgSubpixelScale + i];
if(v < GImgFilterScale)
{
WeightArray[idx * GImgSubpixelScale + i] =
SInt16(WeightArray[idx * GImgSubpixelScale + i] + inc);
sum += inc;
}
}
}
}
unsigned pivot = Diameter << (GImgSubpixelShift - 1);
for(i = 0; i < pivot; i++)
{
WeightArray[pivot + i] = WeightArray[pivot - i];
}
unsigned end = (Diameter << GImgSubpixelShift) - 1;
WeightArray[0] = WeightArray[end];
}
//------------------------------------------------------------------------
#if defined(GFC_CC_MWERKS) && defined(GFC_OS_PS2)
#pragma optimization_level 0
#endif
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBoxGray8(UByte* pDst, const UByte* pSrc)
{
*pDst = *pSrc;
}
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBoxRGB24(UByte* pDst, const UByte* pSrc)
{
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
}
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBoxRGBA32(UByte* pDst, const UByte* pSrc)
{
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
pDst[3] = pSrc[3];
}
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBoxRGBtoRGBA32(UByte* pDst, const UByte* pSrc)
{
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
pDst[3] = 255;
}
//------------------------------------------------------------------------
template<class FilterFunction>
static void
GImageResizeBox( UByte* pDst, int dstWidth, int dstHeight, int dstPitch, int dstBpp,
const UByte* pSrc, int srcWidth, int srcHeight, int srcPitch, int srcBpp,
FilterFunction filter)
{
GArrayUnsafe<int> srcCoordX;
srcCoordX.Resize(dstWidth);
int x, y;
int offset = GImgSubpixelOffset * srcWidth / dstWidth;
// Prepare the X-interpolator and fill the interpolation array for faster access
GLinearInterpolator ix(offset,
offset + (srcWidth << GImgSubpixelShift),
dstWidth);
for(x = 0; x < dstWidth; x++)
{
srcCoordX[x] = ix.y();
++ix;
}
// Prepare the Y-interpolator
offset = GImgSubpixelOffset * srcHeight / dstHeight;
GLinearInterpolator iy(offset,
offset + (srcHeight << GImgSubpixelShift),
dstHeight);
for(y = 0; y < dstHeight; y++)
{
int xInt;
int yInt = iy.y() >> GImgSubpixelShift;
if(yInt < 0) yInt = 0;
if(yInt >= srcHeight) yInt = srcHeight - 1;
const UByte* pSrcRow = pSrc + srcPitch * yInt;
UByte* pDstRow = pDst + dstPitch * y;
// Filter left pixels, while the filtering window
// is out of the left bound of the source image.
for(x = 0; x < dstWidth; x++)
{
xInt = srcCoordX[x] >> GImgSubpixelShift;
if(xInt >= 0) break;
filter(pDstRow, pSrcRow);
pDstRow += dstBpp;
}
// Filter central pixels, while the filtering window
// is fully visible in the source image.
int srcWidth1 = srcWidth - 1;
for(; x < dstWidth; x++)
{
xInt = srcCoordX[x] >> GImgSubpixelShift;
if(xInt >= srcWidth1) break;
filter(pDstRow, pSrcRow + xInt * srcBpp);
pDstRow += dstBpp;
}
// Filter right pixels, when the filtering window
// is out of the right bound of the source image.
pSrcRow += (srcWidth - 1) * srcBpp;
for(; x < dstWidth; x++)
{
filter(pDstRow, pSrcRow);
pDstRow += dstBpp;
}
++iy;
}
}
//------------------------------------------------------------------------
void GSTDCALL GResizeImageBox(UByte* pDst,
int dstWidth, int dstHeight, int dstPitch,
const UByte* pSrc,
int srcWidth, int srcHeight, int srcPitch,
GResizeImageType type)
{
if (dstWidth <= 0 || dstHeight <= 0 ||
srcWidth <= 0 || srcHeight <= 0) return;
switch(type)
{
case GResizeRgbToRgb:
GImageResizeBox(pDst, dstWidth, dstHeight, dstPitch, 3,
pSrc, srcWidth, srcHeight, srcPitch, 3,
GPixelFilterBoxRGB24);
break;
case GResizeRgbaToRgba:
GImageResizeBox(pDst, dstWidth, dstHeight, dstPitch, 4,
pSrc, srcWidth, srcHeight, srcPitch, 4,
GPixelFilterBoxRGBA32);
break;
case GResizeRgbToRgba:
GImageResizeBox(pDst, dstWidth, dstHeight, dstPitch, 4,
pSrc, srcWidth, srcHeight, srcPitch, 3,
GPixelFilterBoxRGBtoRGBA32);
break;
case GResizeGray:
GImageResizeBox(pDst, dstWidth, dstHeight, dstPitch, 1,
pSrc, srcWidth, srcHeight, srcPitch, 1,
GPixelFilterBoxGray8);
break;
}
}
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBilinearRGBA32(UByte* pDst,
const UByte* pSrc1,
const UByte* pSrc2,
const UByte* pSrc3,
const UByte* pSrc4,
int xFract, int yFract)
{
int dst[4] = { GImgSubpixelInitial, GImgSubpixelInitial,
GImgSubpixelInitial, GImgSubpixelInitial };
int weight;
weight = (GImgSubpixelScale - xFract) * (GImgSubpixelScale - yFract);
dst[0] += weight * pSrc1[0];
dst[1] += weight * pSrc1[1];
dst[2] += weight * pSrc1[2];
dst[3] += weight * pSrc1[3];
weight = xFract * (GImgSubpixelScale - yFract);
dst[0] += weight * pSrc2[0];
dst[1] += weight * pSrc2[1];
dst[2] += weight * pSrc2[2];
dst[3] += weight * pSrc2[3];
weight = (GImgSubpixelScale - xFract) * yFract;
dst[0] += weight * pSrc3[0];
dst[1] += weight * pSrc3[1];
dst[2] += weight * pSrc3[2];
dst[3] += weight * pSrc3[3];
weight = xFract * yFract;
dst[0] += weight * pSrc4[0];
dst[1] += weight * pSrc4[1];
dst[2] += weight * pSrc4[2];
dst[3] += weight * pSrc4[3];
pDst[0] = (UByte)(dst[0] >> GImgSubpixelShift2);
pDst[1] = (UByte)(dst[1] >> GImgSubpixelShift2);
pDst[2] = (UByte)(dst[2] >> GImgSubpixelShift2);
pDst[3] = (UByte)(dst[3] >> GImgSubpixelShift2);
}
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBilinearRGB24(UByte* pDst,
const UByte* pSrc1,
const UByte* pSrc2,
const UByte* pSrc3,
const UByte* pSrc4,
int xFract, int yFract)
{
int dst[3] = { GImgSubpixelInitial, GImgSubpixelInitial, GImgSubpixelInitial };
int weight;
weight = (GImgSubpixelScale - xFract) * (GImgSubpixelScale - yFract);
dst[0] += weight * pSrc1[0];
dst[1] += weight * pSrc1[1];
dst[2] += weight * pSrc1[2];
weight = xFract * (GImgSubpixelScale - yFract);
dst[0] += weight * pSrc2[0];
dst[1] += weight * pSrc2[1];
dst[2] += weight * pSrc2[2];
weight = (GImgSubpixelScale - xFract) * yFract;
dst[0] += weight * pSrc3[0];
dst[1] += weight * pSrc3[1];
dst[2] += weight * pSrc3[2];
weight = xFract * yFract;
dst[0] += weight * pSrc4[0];
dst[1] += weight * pSrc4[1];
dst[2] += weight * pSrc4[2];
pDst[0] = (UByte)(dst[0] >> GImgSubpixelShift2);
pDst[1] = (UByte)(dst[1] >> GImgSubpixelShift2);
pDst[2] = (UByte)(dst[2] >> GImgSubpixelShift2);
}
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBilinearRGBtoRGBA32(UByte* pDst,
const UByte* pSrc1,
const UByte* pSrc2,
const UByte* pSrc3,
const UByte* pSrc4,
int xFract, int yFract)
{
GPixelFilterBilinearRGB24(pDst, pSrc1, pSrc2, pSrc3, pSrc4, xFract, yFract);
pDst[3] = 255;
}
//------------------------------------------------------------------------
static GINLINE void GPixelFilterBilinearGray8(UByte* pDst,
const UByte* pSrc1,
const UByte* pSrc2,
const UByte* pSrc3,
const UByte* pSrc4,
int xFract, int yFract)
{
*pDst = (UByte)((GImgSubpixelInitial +
*pSrc1 * (GImgSubpixelScale - xFract) * (GImgSubpixelScale - yFract) +
*pSrc2 * xFract * (GImgSubpixelScale - yFract) +
*pSrc3 * (GImgSubpixelScale - xFract) * yFract +
*pSrc4 * xFract * yFract) >> GImgSubpixelShift2);
}
//------------------------------------------------------------------------
template<class FilterFunction>
static void
GImageResizeFilter2x2( UByte* pDst, int dstWidth, int dstHeight, int dstPitch, int dstBpp,
const UByte* pSrc, int srcWidth, int srcHeight, int srcPitch, int srcBpp,
FilterFunction filter)
{
GArrayUnsafe<int> srcCoordX;
srcCoordX.Resize(dstWidth);
int x, y;
int offset = GImgSubpixelOffset * srcWidth / dstWidth;
// Prepare the X-interpolator and fill the interpolation array for faster acceess
GLinearInterpolator ix(offset,
offset + (srcWidth << GImgSubpixelShift),
dstWidth);
for(x = 0; x < dstWidth; x++)
{
srcCoordX[x] = ix.y() - GImgSubpixelOffset;
++ix;
}
// Prepare the Y-interpolator
offset = GImgSubpixelOffset * srcHeight / dstHeight;
GLinearInterpolator iy(offset,
offset + (srcHeight << GImgSubpixelShift),
dstHeight);
UByte* pDst2 = pDst;
for(y = 0; y < dstHeight; y++)
{
int yFract = iy.y() - GImgSubpixelOffset;
int yInt = yFract >> GImgSubpixelShift;
yFract &= GImgSubpixelMask;
const UByte* pSrcRow1 = (yInt < 0) ? pSrc : pSrc + srcPitch * yInt;
++yInt;
if(yInt >= srcHeight) yInt = srcHeight - 1;
const UByte* pSrcRow2 = pSrc + srcPitch * yInt;
UByte* pDst3 = pDst2;
int xInt, xFract, x1, x2;
// Filter left pixels, while the filtering window
// is out of the left bound of the source image.
for(x = 0; x < dstWidth; x++)
{
xFract = srcCoordX[x];
xInt = xFract >> GImgSubpixelShift;
xFract &= GImgSubpixelMask;
if(xInt >= 0) break;
filter(pDst3,
pSrcRow1, pSrcRow1,
pSrcRow2, pSrcRow2,
xFract, yFract);
pDst3 += dstBpp;
}
// Filter central pixels, while the filtering window
// is fully visible in the source image.
int srcWidth1 = srcWidth - 1;
for(; x < dstWidth; x++)
{
xFract = srcCoordX[x];
xInt = xFract >> GImgSubpixelShift;
xFract &= GImgSubpixelMask;
if(xInt >= srcWidth1) break;
x1 = xInt * srcBpp;
x2 = (xInt + 1) * srcBpp;
filter(pDst3,
pSrcRow1 + x1, pSrcRow1 + x2,
pSrcRow2 + x1, pSrcRow2 + x2,
xFract, yFract);
pDst3 += dstBpp;
}
// Filter right pixels, when the filtering window
// is out of the right bound of the source image.
pSrcRow1 += (srcWidth - 1) * srcBpp;
pSrcRow2 += (srcWidth - 1) * srcBpp;
for(; x < dstWidth; x++)
{
xFract = srcCoordX[x] & GImgSubpixelMask;
filter(pDst3,
pSrcRow1, pSrcRow1,
pSrcRow2, pSrcRow2,
xFract, yFract);
pDst3 += dstBpp;
}
++iy;
pDst2 += dstPitch;
}
}
//--------------------------------------------------------------------
void GSTDCALL GResizeImageBilinear(UByte* pDst,
int dstWidth, int dstHeight, int dstPitch,
const UByte* pSrc,
int srcWidth, int srcHeight, int srcPitch,
GResizeImageType type)
{
if (dstWidth <= 0 || dstHeight <= 0 ||
srcWidth <= 0 || srcHeight <= 0) return;
switch(type)
{
case GResizeRgbToRgb:
GImageResizeFilter2x2(pDst, dstWidth, dstHeight, dstPitch, 3,
pSrc, srcWidth, srcHeight, srcPitch, 3,
GPixelFilterBilinearRGB24);
break;
case GResizeRgbaToRgba:
GImageResizeFilter2x2(pDst, dstWidth, dstHeight, dstPitch, 4,
pSrc, srcWidth, srcHeight, srcPitch, 4,
GPixelFilterBilinearRGBA32);
break;
case GResizeRgbToRgba:
GImageResizeFilter2x2(pDst, dstWidth, dstHeight, dstPitch, 4,
pSrc, srcWidth, srcHeight, srcPitch, 3,
GPixelFilterBilinearRGBtoRGBA32);
break;
case GResizeGray:
GImageResizeFilter2x2(pDst, dstWidth, dstHeight, dstPitch, 1,
pSrc, srcWidth, srcHeight, srcPitch, 1,
GPixelFilterBilinearGray8);
break;
}
}
//--------------------------------------------------------------------
struct GPixelFilterGray8
{
enum { SrcBpp = 1, DstBpp = 1 };
static GINLINE void CopySrcPixel(UByte* pDst, const UByte* pSrc)
{
*pDst = *pSrc;
}
static GINLINE void Filter(UByte* pDst,
const UByte* pSrc,
const SInt16* weightArray,
int xFilter, int xCounter)
{
int dst = GImgFilterScale/2;
for(;;)
{
dst += weightArray[xFilter] * *pSrc++;
if(--xCounter == 0) break;
xFilter += GImgSubpixelScale;
}
dst >>= GImgFilterShift;
if(dst < 0) dst = 0;
if(dst > 255) dst = 255;
*pDst = (UByte)dst;
}
};
//--------------------------------------------------------------------
struct GPixelFilterRGB24
{
enum { SrcBpp = 3, DstBpp = 3 };
static GINLINE void CopySrcPixel(UByte* pDst, const UByte* pSrc)
{
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
}
static GINLINE void Filter(UByte* pDst,
const UByte* pSrc,
const SInt16* weightArray,
int xFilter, int xCounter)
{
int dst[] = { GImgFilterScale/2, GImgFilterScale/2, GImgFilterScale/2 };
for(;;)
{
int weight = weightArray[xFilter];
dst[0] += weight * pSrc[0];
dst[1] += weight * pSrc[1];
dst[2] += weight * pSrc[2];
if(--xCounter == 0) break;
xFilter += GImgSubpixelScale;
pSrc += SrcBpp;
}
dst[0] >>= GImgFilterShift;
dst[1] >>= GImgFilterShift;
dst[2] >>= GImgFilterShift;
if(dst[0] < 0) dst[0] = 0;
if(dst[1] < 0) dst[1] = 0;
if(dst[2] < 0) dst[2] = 0;
if(dst[0] > 255) dst[0] = 255;
if(dst[1] > 255) dst[1] = 255;
if(dst[2] > 255) dst[2] = 255;
pDst[0] = (UByte)dst[0];
pDst[1] = (UByte)dst[1];
pDst[2] = (UByte)dst[2];
}
};
//--------------------------------------------------------------------
struct GPixelFilterRGBA32
{
enum { SrcBpp = 4, DstBpp = 4 };
static GINLINE void CopySrcPixel(UByte* pDst, const UByte* pSrc)
{
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
pDst[3] = pSrc[3];
}
static GINLINE void Filter(UByte* pDst,
const UByte* pSrc,
const SInt16* weightArray,
int xFilter, int xCounter)
{
int dst[4] = { GImgFilterScale/2, GImgFilterScale/2,
GImgFilterScale/2, GImgFilterScale/2 };
for(;;)
{
int weight = weightArray[xFilter];
dst[0] += weight * pSrc[0];
dst[1] += weight * pSrc[1];
dst[2] += weight * pSrc[2];
dst[3] += weight * pSrc[3];
if(--xCounter == 0) break;
xFilter += GImgSubpixelScale;
pSrc += SrcBpp;
}
dst[0] >>= GImgFilterShift;
dst[1] >>= GImgFilterShift;
dst[2] >>= GImgFilterShift;
dst[3] >>= GImgFilterShift;
if(dst[0] < 0) dst[0] = 0;
if(dst[1] < 0) dst[1] = 0;
if(dst[2] < 0) dst[2] = 0;
if(dst[3] < 0) dst[3] = 0;
if(dst[0] > 255) dst[0] = 255;
if(dst[1] > 255) dst[1] = 255;
if(dst[2] > 255) dst[2] = 255;
if(dst[3] > 255) dst[3] = 255;
pDst[0] = (UByte)dst[0];
pDst[1] = (UByte)dst[1];
pDst[2] = (UByte)dst[2];
pDst[3] = (UByte)dst[3];
}
};
//--------------------------------------------------------------------
struct GPixelFilterRGB24toRGBA32
{
enum { SrcBpp = 3, DstBpp = 4 };
static GINLINE void CopySrcPixel(UByte* pDst, const UByte* pSrc)
{
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
}
static GINLINE void Filter(UByte* pDst,
const UByte* pSrc,
const SInt16* weightArray,
int xFilter, int xCounter)
{
GPixelFilterRGB24::Filter(pDst, pSrc, weightArray, xFilter, xCounter);
pDst[3] = 255;
}
};
//--------------------------------------------------------------------
template<class FilterType>
static void GResizeImageRow( UByte* pDst, unsigned dstWidth, int dstInc,
const UByte* pSrc, unsigned srcWidth,
const int* srcCoordX,
const FilterType& filter,
const GImageFilterLut& lut)
{
GUNUSED(filter); // Suppress stupid warning
unsigned diameter = lut.GetDiameter();
int start = lut.GetStart();
const SInt16* weights = lut.GetWeightArray();
unsigned i;
unsigned x;
int xFract;
int xInt;
int j;
UByte tmpSrc[(GImgMaxFilterRadius*2+2) * FilterType::SrcBpp];
// Filter left pixels, while the filtering window
// is out of the left bound of the source image.
for(x = 0; x < dstWidth; ++x)
{
xFract = srcCoordX[x];
xInt = (xFract >> GImgSubpixelShift) + start;
if (xInt >= 0) break;
for (i = 0; i < diameter; ++i)
{
j = xInt + int(i);
if (j < 0) j = 0;
filter.CopySrcPixel(tmpSrc + i * FilterType::SrcBpp,
pSrc + j * FilterType::SrcBpp);
}
filter.Filter(pDst, tmpSrc, weights,
GImgSubpixelMask - (xFract & GImgSubpixelMask),
diameter);
pDst += dstInc;
}
// Filter central pixels, while the filtering window
// is fully visible in the source image.
for(; x < dstWidth; ++x)
{
xFract = srcCoordX[x];
xInt = (xFract >> GImgSubpixelShift) + start;
if (xInt + diameter > srcWidth) break;
filter.Filter(pDst,
pSrc + FilterType::SrcBpp * xInt,
weights,
GImgSubpixelMask - (xFract & GImgSubpixelMask),
diameter);
pDst += dstInc;
}
// Filter right pixels, when the filtering window
// is out of the right bound of the source image.
for(; x < dstWidth; ++x)
{
xFract = srcCoordX[x];
xInt = (xFract >> GImgSubpixelShift) + start;
for (i = 0; i < diameter; ++i)
{
j = xInt + int(i);
if (j >= int(srcWidth)) j = int(srcWidth) - 1;
filter.CopySrcPixel(tmpSrc + i * FilterType::SrcBpp,
pSrc + j * FilterType::SrcBpp);
}
filter.Filter(pDst, tmpSrc, weights,
GImgSubpixelMask - (xFract & GImgSubpixelMask),
diameter);
pDst += dstInc;
}
}
//--------------------------------------------------------------------
static void GCreateResizeInterpolationArray(GArrayUnsafe<int>& srcCoord,
int dstWidth, int srcWidth)
{
int x;
int offset = GImgSubpixelOffset * srcWidth / dstWidth;
GLinearInterpolator ix(offset,
offset + (srcWidth << GImgSubpixelShift),
dstWidth);
srcCoord.Resize(dstWidth);
for(x = 0; x < dstWidth; ++x)
{
srcCoord[x] = ix.y() - GImgSubpixelOffset;
++ix;
}
}
//--------------------------------------------------------------------
template<class FilterType1, class FilterType2>
static void GResizeImageTwoPass(UByte* pDst,
int dstWidth, int dstHeight, int dstPitch,
const UByte* pSrc,
int srcWidth, int srcHeight, int srcPitch,
const FilterType1& filter1,
const FilterType2& filter2,
const GImageFilterLut& lut)
{
GArrayUnsafe<int> srcCoordX;
GArrayUnsafe<UByte> tmpImg;
int y;
// This function resizes the image with filtering in two passes,
// by X and Y with transposition for faster access to the memory.
// It requires a temporary buffer of dstWidth * srcHeight, but
// reduces the computational complexity from R*R to R+R, where
// R is the radius of the filter.
//-----------------------------
tmpImg.Resize(dstWidth * srcHeight * FilterType1::DstBpp);
// Filter the image in the X direction and transpose it.
UByte* pTmp = &tmpImg[0];
GCreateResizeInterpolationArray(srcCoordX, dstWidth, srcWidth);
for(y = 0; y < srcHeight; ++y)
{
GResizeImageRow(pTmp, dstWidth, srcHeight * FilterType1::DstBpp,
pSrc, srcWidth,
&srcCoordX[0], filter1, lut);
pSrc += srcPitch;
pTmp += FilterType1::DstBpp;
}
// Filter the image in the Y direction and transpose it back.
pTmp = &tmpImg[0];
GCreateResizeInterpolationArray(srcCoordX, dstHeight, srcHeight);
for(y = 0; y < dstWidth; ++y)
{
GResizeImageRow(pDst, dstHeight, dstPitch,
pTmp, srcHeight,
&srcCoordX[0], filter2, lut);
pTmp += srcHeight * FilterType1::DstBpp;
pDst += FilterType2::DstBpp;
}
}
//--------------------------------------------------------------------
void GSTDCALL GResizeImage(UByte* pDst,
int dstWidth, int dstHeight, int dstPitch,
const UByte* pSrc,
int srcWidth, int srcHeight, int srcPitch,
GResizeImageType type,
const GImageFilterLut& lut)
{
if (dstWidth <= 0 || dstHeight <= 0 ||
srcWidth <= 0 || srcHeight <= 0) return;
switch(type)
{
case GResizeRgbToRgb:
{
GPixelFilterRGB24 filter;
GResizeImageTwoPass(pDst, dstWidth, dstHeight, dstPitch,
pSrc, srcWidth, srcHeight, srcPitch,
filter, filter, lut);
}
break;
case GResizeRgbaToRgba:
{
GPixelFilterRGBA32 filter;
GResizeImageTwoPass(pDst, dstWidth, dstHeight, dstPitch,
pSrc, srcWidth, srcHeight, srcPitch,
filter, filter, lut);
}
break;
case GResizeRgbToRgba:
{
GPixelFilterRGB24 filter1;
GPixelFilterRGB24toRGBA32 filter2;
GResizeImageTwoPass(pDst, dstWidth, dstHeight, dstPitch,
pSrc, srcWidth, srcHeight, srcPitch,
filter1, filter2, lut);
}
break;
case GResizeGray:
{
GPixelFilterGray8 filter;
GResizeImageTwoPass(pDst, dstWidth, dstHeight, dstPitch,
pSrc, srcWidth, srcHeight, srcPitch,
filter, filter, lut);
}
break;
}
}