mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@62634 954022d7-b5bf-4e40-9824-e11837661b57
6172 lines
161 KiB
C++
6172 lines
161 KiB
C++
|
||
#include "stdafx.h"
|
||
#include "ImageTransform.h"
|
||
#include "ImageTransformIPP.h"
|
||
#include <ChromoKey.h>
|
||
|
||
BOOL ImageTransform3::CompactImage(SAFEARRAY** Array, BYTE* data, int width, int height)
|
||
{
|
||
// check for valid input parameters
|
||
if (!Array || !data || width < 2 || height < 2)
|
||
return FALSE;
|
||
|
||
// compute SAFEARRAY bounds
|
||
SAFEARRAYBOUND rgsaBound[3];
|
||
rgsaBound[0].lLbound = 0;
|
||
rgsaBound[0].cElements = 4;
|
||
rgsaBound[1].lLbound = 0;
|
||
rgsaBound[1].cElements = width;
|
||
rgsaBound[2].lLbound = 0;
|
||
rgsaBound[2].cElements = height;
|
||
|
||
// compose SAFEARRAY with image data
|
||
*Array = SafeArrayCreate(VT_UI1, 3, rgsaBound);
|
||
|
||
// this is the simpliest and mostly common case
|
||
m_oMemoryUtils.memcpy((BYTE*)(*Array)->pvData, data, 4*width*height);
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ExtractImage(SAFEARRAY* Array, BYTE*& data, int& width, int& height)
|
||
{
|
||
// check for valid arrey
|
||
if (!Array)
|
||
return FALSE;
|
||
|
||
// variables
|
||
VARTYPE type;
|
||
long lBoundC, uBoundC;
|
||
long lBoundW, uBoundW;
|
||
long lBoundH, uBoundH;
|
||
|
||
// check for valid pixel array size
|
||
if (SafeArrayGetDim(Array) != 3)
|
||
return FALSE;
|
||
|
||
// check for valid array element type
|
||
if (FAILED(SafeArrayGetVartype(Array, &type)) || type != VT_UI1 || SafeArrayGetElemsize(Array) != 1)
|
||
return FALSE;
|
||
|
||
// retrieve image attributes
|
||
if (FAILED(SafeArrayGetLBound(Array, 1, &lBoundC)) || FAILED(SafeArrayGetUBound(Array, 1, &uBoundC)) ||
|
||
FAILED(SafeArrayGetLBound(Array, 2, &lBoundW)) || FAILED(SafeArrayGetUBound(Array, 2, &uBoundW)) ||
|
||
FAILED(SafeArrayGetLBound(Array, 3, &lBoundH)) || FAILED(SafeArrayGetUBound(Array, 3, &uBoundH)))
|
||
return FALSE;
|
||
|
||
// check for valid number of channels
|
||
if (1 + uBoundC - lBoundC != 4)
|
||
return FALSE;
|
||
|
||
// retrieve image data
|
||
width = 1 + uBoundW - lBoundW;
|
||
height = 1 + uBoundH - lBoundH;
|
||
data = (BYTE*)(Array->pvData);
|
||
|
||
// check for valid bitmap
|
||
if (!data || width < 2 || height < 2)
|
||
return FALSE;
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ExtractImage2(BYTE* Array, BYTE*& data, int& width, int& height)
|
||
{
|
||
// extract image data
|
||
return ExtractImage((SAFEARRAY*)Array, data, width, height);
|
||
}
|
||
|
||
BOOL ImageTransform3::ApplyTable(BYTE* Table)
|
||
{
|
||
// check for valid table
|
||
if (!Table)
|
||
return FALSE;
|
||
|
||
// variables
|
||
BYTE* pPixels = m_pPixels + 0;
|
||
int nCount = m_nSize/4;
|
||
|
||
// apply table
|
||
if (!m_bMask)
|
||
{
|
||
for (int nIndex = 0; nIndex < nCount; ++nIndex)
|
||
{
|
||
*pPixels = Table[*pPixels]; pPixels++;
|
||
*pPixels = Table[*pPixels]; pPixels++;
|
||
*pPixels = Table[*pPixels]; pPixels++;
|
||
pPixels ++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int nIndex = 0; nIndex < nCount; ++nIndex)
|
||
{
|
||
//if (*(pPixels+3))
|
||
// continue;
|
||
|
||
*pPixels = Table[*pPixels]; pPixels++;
|
||
*pPixels = Table[*pPixels]; pPixels++;
|
||
*pPixels = Table[*pPixels]; pPixels++;
|
||
pPixels ++;
|
||
}
|
||
}
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ApplyTable(BYTE* TableR, BYTE* TableG, BYTE* TableB)
|
||
{
|
||
// check for valid table
|
||
if (!TableR || !TableG || !TableB)
|
||
return FALSE;
|
||
|
||
// variables
|
||
BYTE* pPixels = m_pPixels + 0;
|
||
int nCount = m_nSize/4;
|
||
|
||
// apply table
|
||
if (!m_bMask)
|
||
{
|
||
for (int nIndex = 0; nIndex < nCount; ++nIndex)
|
||
{
|
||
*pPixels = TableB[*pPixels]; pPixels++;
|
||
*pPixels = TableG[*pPixels]; pPixels++;
|
||
*pPixels = TableR[*pPixels]; pPixels++;
|
||
pPixels ++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int nIndex = 0; nIndex < nCount; ++nIndex)
|
||
{
|
||
//if (*(pPixels+3))
|
||
// continue;
|
||
|
||
*pPixels = TableB[*pPixels]; pPixels++;
|
||
*pPixels = TableG[*pPixels]; pPixels++;
|
||
*pPixels = TableR[*pPixels]; pPixels++;
|
||
pPixels ++;
|
||
}
|
||
}
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ApplyFlip(BYTE* pPixels, int nWidth, int nHeight)
|
||
{
|
||
// variables
|
||
int nIndex = 0;
|
||
int nLineSize = 4*nWidth;
|
||
int nIndexFlip = nLineSize*(nHeight - 1);
|
||
BYTE* pLine = new BYTE[nLineSize];
|
||
|
||
// flip image vertically
|
||
for (int nY = 0; nY < nHeight/2; ++nY, nIndex += nLineSize, nIndexFlip -= nLineSize)
|
||
{
|
||
m_oMemoryUtils.memcpy(pLine, (BYTE*)(pPixels + nIndex), nLineSize);
|
||
m_oMemoryUtils.memcpy((BYTE*)(pPixels + nIndex), (BYTE*)(pPixels + nIndexFlip), nLineSize);
|
||
m_oMemoryUtils.memcpy((BYTE*)(pPixels + nIndexFlip), pLine, nLineSize);
|
||
}
|
||
|
||
// clear memory
|
||
delete[] pLine;
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ApplyClear(BYTE* pPixels, int nSize)
|
||
{
|
||
// clear 4th channel with zeroes
|
||
for (int nIndex = 0; nIndex < nSize; nIndex += 4)
|
||
pPixels[nIndex + 3] = 0;
|
||
|
||
// al ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ApplyColor(BYTE* pPixels, int nSize, int nColor, int nAlpha)
|
||
{
|
||
// variables
|
||
double dAlpha1 = nAlpha/255.0;
|
||
double dAlpha2 = 1.0 - dAlpha1;
|
||
double dRed = dAlpha1*GetRValue(nColor);
|
||
double dGreen = dAlpha1*GetGValue(nColor);
|
||
double dBlue = dAlpha1*GetBValue(nColor);
|
||
|
||
// apply coloring
|
||
for (int nIndex = 0; nIndex < nSize; nIndex += 4)
|
||
{
|
||
pPixels[nIndex + 2] = (BYTE)(dAlpha2*pPixels[nIndex + 2] + dRed);
|
||
pPixels[nIndex + 1] = (BYTE)(dAlpha2*pPixels[nIndex + 1] + dGreen);
|
||
pPixels[nIndex + 0] = (BYTE)(dAlpha2*pPixels[nIndex + 0] + dBlue);
|
||
}
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ConvertToHls(float fRed, float fGreen, float fBlue, float& fHue, float& fLightness, float& fSaturation)
|
||
{
|
||
// variables
|
||
float fMinValue, fMaxValue, fDeltaValue;
|
||
BYTE nMaxComponent = 0; // red
|
||
|
||
// compute minimal and maximal components values
|
||
if (fRed > fGreen)
|
||
{
|
||
if (fRed > fBlue) { fMaxValue = fRed; nMaxComponent = 0; }
|
||
else { fMaxValue = fBlue; nMaxComponent = 2; }
|
||
|
||
if (fGreen < fBlue) { fMinValue = fGreen; }
|
||
else { fMinValue = fBlue; }
|
||
}
|
||
else
|
||
{
|
||
if (fGreen > fBlue) { fMaxValue = fGreen; nMaxComponent = 1; }
|
||
else { fMaxValue = fBlue; nMaxComponent = 2; }
|
||
|
||
if (fRed < fBlue) { fMinValue = fRed; }
|
||
else { fMinValue = fBlue; }
|
||
}
|
||
|
||
// compute lightness value
|
||
fLightness = 0.5f*(fMaxValue + fMinValue);
|
||
|
||
// compute additional useful parameter
|
||
fDeltaValue = (fMaxValue - fMinValue);
|
||
|
||
// check for achromatic case
|
||
if (fabs(fDeltaValue) < 0.00001)
|
||
{
|
||
fSaturation = 0.0f;
|
||
fHue = 0.0f;
|
||
}
|
||
else
|
||
{
|
||
// compute saturation value
|
||
if (fLightness < 0.5f) fSaturation = fDeltaValue / (fMaxValue + fMinValue);
|
||
else fSaturation = fDeltaValue / (2.0f - fMaxValue - fMinValue);
|
||
|
||
// compute hue angle
|
||
if (nMaxComponent == 0) fHue = (fGreen - fBlue) / fDeltaValue;
|
||
else if (nMaxComponent == 1) fHue = 2.0f + (fBlue - fRed) / fDeltaValue;
|
||
else fHue = 4.0f + (fRed - fGreen) / fDeltaValue;
|
||
|
||
fHue *= 60.0f;
|
||
|
||
// clamp hue angle to 0..360 range
|
||
if (fHue < 0.0f) fHue += 360.0f;
|
||
if (fHue > 360.0f) fHue -= 360.0f;
|
||
}
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ConvertToValue(float fValue1, float fValue2, float fHue, float& fValue)
|
||
{
|
||
// clamp hue angle to 0..360 range
|
||
if (fHue > 360.0f) fHue -= 360.0f;
|
||
else if (fHue < 0.0f) fHue += 360.0f;
|
||
|
||
// compute resulting value using hue angle
|
||
if (fHue < 60.0f) fValue = (fValue1 + (fValue2 - fValue1) * (fHue / 60.0f));
|
||
else if (fHue < 180.0f) fValue = (fValue2);
|
||
else if (fHue < 240.0f) fValue = (fValue1 + (fValue2 - fValue1) * (240.0f - fHue) / 60.0f);
|
||
else fValue = (fValue1);
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL ImageTransform3::ConvertToRgb(float fHue, float fLightness, float fSaturation, float& fRed, float& fGreen, float& fBlue)
|
||
{
|
||
// variables
|
||
float fValue1, fValue2;
|
||
|
||
// check achromatic case
|
||
if (fabs(fSaturation) < 0.00001)
|
||
{
|
||
fRed = fLightness;
|
||
fGreen = fLightness;
|
||
fBlue = fLightness;
|
||
}
|
||
else
|
||
{
|
||
// compute additional values
|
||
if (fLightness < 0.5f)
|
||
fValue2 = fLightness * (1.0f + fSaturation);
|
||
else
|
||
fValue2 = fLightness + fSaturation - (fLightness * fSaturation);
|
||
|
||
fValue1 = (fLightness / 0.5f) - fValue2;
|
||
|
||
// compute RGB components
|
||
ConvertToValue(fValue1, fValue2, fHue + 120.0f, fRed);
|
||
ConvertToValue(fValue1, fValue2, fHue, fGreen);
|
||
ConvertToValue(fValue1, fValue2, fHue - 120.0f, fBlue);
|
||
}
|
||
|
||
// all ok
|
||
return TRUE;
|
||
}
|
||
|
||
BYTE ImageTransform3::GetPointNearest(double dPointX, double dPointY, BYTE* pData, int nWidth, int nHeight, int nChannel, int nChannels, BYTE nColor)
|
||
{
|
||
int nX = (int)floor(dPointX);
|
||
int nY = (int)floor(dPointY);
|
||
|
||
if (nX < 0 || nX >= nWidth || nY < 0 || nY >= nHeight)
|
||
return nColor;
|
||
|
||
return pData[nChannel + nChannels*(nX + nY*nWidth)];
|
||
}
|
||
|
||
BYTE ImageTransform3::GetPointBillinear(double dPointX, double dPointY, BYTE* pData, int nWidth, int nHeight, int nChannel, int nChannels, BYTE nColor)
|
||
{
|
||
int nX = (int)floor(dPointX);
|
||
int nY = (int)floor(dPointY);
|
||
|
||
if (nX == nWidth - 1) { dPointX -= 1; nX -= 1; }
|
||
if (nY == nHeight - 1) { dPointY -= 1; nY -= 1; }
|
||
|
||
if (nX < 0 || nX + 1 >= nWidth || nY < 0 || nY + 1 >= nHeight)
|
||
return nColor;
|
||
|
||
double dX = dPointX - nX;
|
||
double dY = dPointY - nY;
|
||
|
||
int nIndex = nChannel + nChannels*(nX + nY*nWidth);
|
||
|
||
BYTE byLT = pData[nIndex];
|
||
BYTE byRT = pData[nIndex + nChannels];
|
||
BYTE byRB = pData[nIndex + nChannels + nChannels*nWidth];
|
||
BYTE byLB = pData[nIndex + nChannels*nWidth];
|
||
|
||
return (BYTE)
|
||
(
|
||
(1 - dX)*(1 - dY)*byLT + // Left - Top corner
|
||
( dX)*(1 - dY)*byRT + // Right - Top corner
|
||
( dX)*( dY)*byRB + // Right - Bottom corner
|
||
(1 - dX)*( dY)*byLB // Left - Bottom corner
|
||
);
|
||
}
|
||
|
||
void ImageTransform3::GetRadiusAndAngle(double x, double y, double cx, double cy, double& r, double& a)
|
||
{
|
||
double dx = x - cx;
|
||
double dy = y - cy;
|
||
r = _hypot(dx, dy);
|
||
|
||
double sdy = (dy >= 0 ? 1.0 : -1.0);
|
||
a = (r ? acos(dx/r)*sdy: 0);
|
||
}
|
||
|
||
void ImageTransform3::ClearImage(BYTE* pData, int nSize)
|
||
{
|
||
IPPClearImage(pData, nSize, m_nBackColor);
|
||
|
||
//#ifdef NOT_OPTIM
|
||
//
|
||
// int* p = (int*)pData;
|
||
// int c = RGB(GetBValue(m_nBackColor), GetGValue(m_nBackColor), GetRValue(m_nBackColor));
|
||
// for (int i = 0; i < nSize; i += 4, ++p)
|
||
// *p = c;
|
||
//
|
||
//#else
|
||
//
|
||
// Ipp8u backColor[4] = { GetBValue(m_nBackColor), GetGValue(m_nBackColor), GetRValue(m_nBackColor), GetAValue(m_nBackColor) };
|
||
//
|
||
// ippiSet_8u_AC4R(backColor, (Ipp8u*)pData, m_nIppiStep, m_IppiRoiSize);
|
||
//
|
||
//#endif
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustBrightness(double Frame, long Level)
|
||
{
|
||
// check for no-action effect
|
||
if (!Level)
|
||
return S_OK;
|
||
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// compute brightness level
|
||
int nLevel = min(255, max(-255, Level));
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
BYTE Table[256];
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
Table[nIndex] = Byte(nIndex + Frame*nLevel);
|
||
|
||
// apply table
|
||
if (!ApplyTable(Table))
|
||
return S_FALSE;
|
||
|
||
#else
|
||
|
||
Ipp8u value[3];
|
||
value[0] = (Ipp8u)(Frame*abs(nLevel));
|
||
value[1] = value[0];
|
||
value[2] = value[0];
|
||
|
||
|
||
IppiSize roiSize;
|
||
roiSize.width = m_nWidth;
|
||
roiSize.height = m_nHeight;
|
||
if (nLevel>0)
|
||
ippiAddC_8u_AC4IRSfs(value, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
else
|
||
ippiSubC_8u_AC4IRSfs(value, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustBrightnessEx(double Frame, long LevelR, long LevelG, long LevelB)
|
||
{
|
||
// check for no-action effect
|
||
if (!LevelR && !LevelG && !LevelB)
|
||
return S_OK;
|
||
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// compute brightness levels
|
||
int nLevelR = min(255, max(-255, LevelR));
|
||
int nLevelG = min(255, max(-255, LevelG));
|
||
int nLevelB = min(255, max(-255, LevelB));
|
||
|
||
// non-optimized variant
|
||
// #ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
BYTE TableR[256];
|
||
BYTE TableG[256];
|
||
BYTE TableB[256];
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
TableR[nIndex] = Byte(nIndex + Frame*nLevelR);
|
||
TableG[nIndex] = Byte(nIndex + Frame*nLevelG);
|
||
TableB[nIndex] = Byte(nIndex + Frame*nLevelB);
|
||
}
|
||
|
||
// apply table
|
||
if (!ApplyTable(TableR, TableG, TableB))
|
||
return S_FALSE;
|
||
|
||
/*#else
|
||
|
||
IppiSize roiSize;
|
||
roiSize.width = m_nWidth;
|
||
roiSize.height = m_nHeight;
|
||
|
||
if ((nLevelR >= 0) && (nLevelG >= 0) && (nLevelB >= 0))
|
||
{
|
||
Ipp8u value[3];
|
||
value[0] = (Ipp8u)(Frame*abs(nLevelB));
|
||
value[1] = (Ipp8u)(Frame*abs(nLevelG));
|
||
value[2] = (Ipp8u)(Frame*abs(nLevelR));
|
||
ippiAddC_8u_AC4IRSfs(value, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
}
|
||
else if ((nLevelR <= 0) && (nLevelG <= 0) && (nLevelB <= 0))
|
||
{
|
||
Ipp8u value[3];
|
||
value[0] = (Ipp8u)(Frame*abs(nLevelB));
|
||
value[1] = (Ipp8u)(Frame*abs(nLevelG));
|
||
value[2] = (Ipp8u)(Frame*abs(nLevelR));
|
||
ippiSubC_8u_AC4IRSfs(value, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
}
|
||
else
|
||
{
|
||
Ipp8u valueR[3];
|
||
valueR[0] = 0;
|
||
valueR[1] = 0;
|
||
valueR[2] = (Ipp8u)(Frame*abs(nLevelR));
|
||
Ipp8u valueG[3];
|
||
valueG[0] = 0;
|
||
valueG[1] = (Ipp8u)(Frame*abs(nLevelG));
|
||
valueG[2] = 0;
|
||
Ipp8u valueB[3];
|
||
valueB[0] = (Ipp8u)(Frame*abs(nLevelB));
|
||
valueB[1] = 0;
|
||
valueB[2] = 0;
|
||
|
||
if (nLevelR > 0)
|
||
ippiAddC_8u_AC4IRSfs(valueR, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
else if (nLevelR < 0)
|
||
ippiSubC_8u_AC4IRSfs(valueR, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
if (nLevelG > 0)
|
||
ippiAddC_8u_AC4IRSfs(valueG, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
else if (nLevelG < 0)
|
||
ippiSubC_8u_AC4IRSfs(valueG, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
if (nLevelB > 0)
|
||
ippiAddC_8u_AC4IRSfs(valueB, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
else if (nLevelB < 0)
|
||
ippiSubC_8u_AC4IRSfs(valueB, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, 0);
|
||
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> 16s <20><><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
|
||
//Ipp16s value[3];
|
||
//value[0] = Frame*nLevelB;
|
||
//value[1] = Frame*nLevelG;
|
||
//value[2] = Frame*nLevelR;
|
||
//Ipp16s* pDst = new Ipp16s[m_nSize];
|
||
//ippiConvert_8u16s_AC4R( (Ipp8u*) m_pPixels, 4*m_nWidth,
|
||
// pDst, 4*sizeof(Ipp16s)*m_nWidth, roiSize);
|
||
//ippiAddC_16s_AC4IRSfs(value, pDst, 4*sizeof(Ipp16s)*m_nWidth, roiSize, 0);
|
||
//ippiConvert_16s8u_AC4R( pDst, 4*sizeof(Ipp16s)*m_nWidth,
|
||
// (Ipp8u*) m_pPixels, 4*m_nWidth, roiSize);
|
||
//delete pDst;
|
||
}
|
||
|
||
#endif */
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::GetAutoBrightness(double Completeness, double* Level)
|
||
{
|
||
float fRed, fGreen, fBlue;
|
||
float fHue, fLightness, fSaturation;
|
||
|
||
int cnts=0;
|
||
*Level = 0.0;
|
||
|
||
// balance each pixel
|
||
for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// retrieve pixel color components
|
||
fRed = m_pPixels[nIndex + 2]/255.0f;
|
||
fGreen = m_pPixels[nIndex + 1]/255.0f;
|
||
fBlue = m_pPixels[nIndex + 0]/255.0f;
|
||
|
||
// original color -> Hue-Saturation-Lighteness
|
||
ConvertToHls(fRed, fGreen, fBlue, fHue, fLightness, fSaturation);
|
||
|
||
*Level += fLightness;
|
||
cnts++;
|
||
}
|
||
|
||
if (cnts>0)
|
||
*Level /= cnts;
|
||
|
||
if (*Level>0.5)
|
||
*Level *= -100.0;
|
||
else
|
||
*Level *= 100.0;
|
||
|
||
return S_OK;
|
||
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustContrast(double Frame, double Level)
|
||
{
|
||
// check for no-action effect
|
||
if (fabs(Level - 1.0) < 0.001)
|
||
return S_OK;
|
||
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// variables
|
||
BYTE Table[256];
|
||
|
||
// correct contrast level value
|
||
double dLevel = min(100, max(-100, Level));
|
||
|
||
// compute contrast level
|
||
if (Level <= 0)
|
||
dLevel = 1.0 + Frame*dLevel/100.0;
|
||
else
|
||
dLevel = pow(255, Frame*dLevel/100.0);
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
Table[nIndex] = Byte(127.5 + (nIndex - 127.5)*dLevel);
|
||
|
||
// apply table
|
||
if (!ApplyTable(Table))
|
||
return S_FALSE;
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustGamma(double Frame, double Level)
|
||
{
|
||
// check for no-action effect
|
||
if (fabs(Level - 1.0) < 0.001)
|
||
return S_OK;
|
||
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// variables
|
||
BYTE Table[256];
|
||
|
||
// correct contrast level value
|
||
double dLevel = min(100, max(-100, Level));
|
||
|
||
// compute gamma level
|
||
if (Level <= 0)
|
||
{
|
||
// compute gamma values
|
||
double dPower = 1.0/max(0.0001, 1.0 + Frame*dLevel/100.0);
|
||
double dNumerator = 255.0/pow(255.0, dPower);
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
Table[nIndex] = Byte(dNumerator*pow(nIndex, dPower));
|
||
}
|
||
else
|
||
{
|
||
// compute gamma values
|
||
double dPower = 1.0/pow(255, Frame*dLevel/100.0);
|
||
double dNumerator = 255.0/pow(255.0, dPower);
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
Table[nIndex] = Byte(dNumerator*pow(nIndex, dPower));
|
||
}
|
||
|
||
// apply table
|
||
if (!ApplyTable(Table))
|
||
return S_FALSE;
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::GetAutoGamma(double Completeness, double* Level)
|
||
{
|
||
// variables
|
||
BYTE Value;
|
||
BYTE ValMax = 0;
|
||
BYTE ValMin = 255;
|
||
|
||
for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
Value = Intensity(m_pPixels[nIndex + 2], m_pPixels[nIndex + 1], m_pPixels[nIndex + 0]);
|
||
if (ValMax<Value)
|
||
ValMax = Value;
|
||
if (ValMin>Value)
|
||
ValMin = Value;
|
||
}
|
||
if (ValMax>240)
|
||
ValMax = 240;
|
||
if (ValMin<15)
|
||
ValMin = 15;
|
||
double midVal = (double)(ValMax+ValMin)/2.0;
|
||
//*Level = (128.0-midVal)/128.0*50.0;
|
||
*Level = ((double)(ValMax+ValMin))*10.0/2.0/255.0;
|
||
return S_OK;
|
||
}
|
||
STDMETHODIMP ImageTransform3::AdjustEqualize(double Frame)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
BYTE Table[256];
|
||
|
||
// compute equalize level
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
double dNumerator = 1.0/127.5;
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
Table[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(dNumerator*nIndex*nIndex));
|
||
|
||
// apply table
|
||
if (!ApplyTable(Table))
|
||
return S_FALSE;
|
||
|
||
#else
|
||
|
||
IppiSize roiSize;
|
||
roiSize.width = m_nWidth;
|
||
roiSize.height = m_nHeight;
|
||
Ipp8u* pBuffer = new Ipp8u[m_nSize];
|
||
Ipp8u* pCopy = new Ipp8u[m_nSize];
|
||
Ipp8u alpha = (Ipp8u)(Frame * 255);
|
||
|
||
if (pBuffer && pCopy)
|
||
{
|
||
// int scaleFactor = -7;//dNumerator = 1/128 = 2^(-7)
|
||
ippiSqr_8u_AC4RSfs((Ipp8u*) m_pPixels, 4*m_nWidth, pBuffer, 4*m_nWidth, roiSize, 7);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> pBuffer <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ippAlphaOver)
|
||
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> m_pPixels
|
||
|
||
m_oMemoryUtils.memcpy(pCopy, m_pPixels, m_nSize);
|
||
ippiAlphaCompC_8u_AC4R(pBuffer, 4*m_nWidth, alpha, pCopy, 4*m_nWidth, 255, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, ippAlphaOver);
|
||
}
|
||
|
||
if (pCopy)
|
||
delete[] pCopy;
|
||
if (pBuffer)
|
||
delete[] pBuffer;
|
||
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustGrayscale(double Frame, VARIANT_BOOL Desaturate)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// correct grayscaling values
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// variables
|
||
BYTE Value;
|
||
|
||
// apply table
|
||
|
||
//for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
//{
|
||
// if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
// continue;
|
||
|
||
// // compute new color
|
||
// if (Desaturate == VARIANT_TRUE)
|
||
// Value = Lightness(m_pPixels[nIndex + 2], m_pPixels[nIndex + 1], m_pPixels[nIndex + 0]);
|
||
// else
|
||
// Value = Intensity(m_pPixels[nIndex + 2], m_pPixels[nIndex + 1], m_pPixels[nIndex + 0]);
|
||
|
||
// // compute new color
|
||
// m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pPixels[nIndex + 0] + dAlpha1*Value);
|
||
// m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pPixels[nIndex + 1] + dAlpha1*Value);
|
||
// m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pPixels[nIndex + 2] + dAlpha1*Value);
|
||
//}
|
||
|
||
// variables
|
||
BYTE* pPixels = m_pPixels;
|
||
int nCount = m_nSize/4;
|
||
|
||
// compute new color
|
||
if (Desaturate == VARIANT_TRUE)
|
||
{
|
||
// apply table
|
||
for (int nIndex = 0; nIndex < nCount; ++nIndex)
|
||
{
|
||
if (m_bMask && *(pPixels + 3) != 0)
|
||
continue;
|
||
|
||
Value = Lightness(*(pPixels + 2), *(pPixels + 1), *pPixels);
|
||
|
||
// compute new color
|
||
*pPixels = (BYTE)(dAlpha2*(*pPixels) + dAlpha1*Value); pPixels++;
|
||
*pPixels = (BYTE)(dAlpha2*(*pPixels) + dAlpha1*Value); pPixels++;
|
||
*pPixels = (BYTE)(dAlpha2*(*pPixels) + dAlpha1*Value); pPixels++;
|
||
pPixels++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// apply table
|
||
for (int nIndex = 0; nIndex < nCount; nIndex ++)
|
||
{
|
||
if (m_bMask && *(pPixels + 3) != 0)
|
||
continue;
|
||
|
||
Value = Intensity(*(pPixels + 2), *(pPixels + 1), *pPixels);
|
||
|
||
// compute new color
|
||
*pPixels = (BYTE)(dAlpha2*(*pPixels) + dAlpha1*Value); pPixels++;
|
||
*pPixels = (BYTE)(dAlpha2*(*pPixels) + dAlpha1*Value); pPixels++;
|
||
*pPixels = (BYTE)(dAlpha2*(*pPixels) + dAlpha1*Value); pPixels++;
|
||
pPixels++;
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
//Lightness = (max(R,G,B) + min(R,G,B))/2
|
||
//Intensity = 0.3*R + 0.59*G + 0.11*B
|
||
|
||
IppiSize roiSize;
|
||
roiSize.width = m_nWidth;
|
||
roiSize.height = m_nHeight;
|
||
|
||
if (Desaturate == VARIANT_TRUE)
|
||
{
|
||
// variables
|
||
Ipp8u* pBuffer = new Ipp8u[m_nSize];
|
||
Ipp8u* pLightness = new Ipp8u[m_nWidth*m_nHeight];
|
||
Ipp8u* pSrc[4];
|
||
Ipp8u alpha = (Ipp8u)((1.0 - Frame) * 255);
|
||
|
||
if (pBuffer && pLightness)
|
||
{
|
||
ippiBGRToHLS_8u_AC4R((Ipp8u*)m_pPixels, 4*m_nWidth, pBuffer, 4*m_nWidth, roiSize);
|
||
ippiCopy_8u_C4C1R(pBuffer+1, 4*m_nWidth, pLightness, m_nWidth, roiSize);
|
||
|
||
pSrc[0] = pLightness;
|
||
pSrc[1] = pLightness;
|
||
pSrc[2] = pLightness;
|
||
pSrc[3] = pLightness;
|
||
|
||
ippiCopy_8u_P4C4R(pSrc, m_nWidth, pBuffer, 4*m_nWidth, roiSize);
|
||
|
||
ippiAlphaCompC_8u_AC4R((Ipp8u*)m_pPixels, 4*m_nWidth, alpha, pBuffer, 4*m_nWidth, 255, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, ippAlphaOver);
|
||
}
|
||
|
||
if (pBuffer)
|
||
delete[] pBuffer;
|
||
if (pLightness)
|
||
delete[] pLightness;
|
||
}
|
||
else
|
||
{
|
||
// variables
|
||
Ipp8u* pIntensity = new Ipp8u[m_nWidth*m_nHeight];
|
||
Ipp8u* pBuffer = new Ipp8u[m_nSize];
|
||
Ipp32f coeffs[3];
|
||
Ipp8u* pSrc[4];
|
||
Ipp8u alpha = (Ipp8u)((1.0 - Frame) * 255);
|
||
|
||
if (pBuffer && pIntensity)
|
||
{
|
||
coeffs[0] = 0.11f;
|
||
coeffs[1] = 0.59f;
|
||
coeffs[2] = 0.3f;
|
||
|
||
ippiColorToGray_8u_AC4C1R((Ipp8u*) m_pPixels , 4*m_nWidth, pIntensity, m_nWidth, roiSize, coeffs);
|
||
|
||
pSrc[0] = pIntensity;
|
||
pSrc[1] = pIntensity;
|
||
pSrc[2] = pIntensity;
|
||
pSrc[3] = pIntensity;
|
||
|
||
ippiCopy_8u_P4C4R(pSrc, m_nWidth, pBuffer, 4*m_nWidth, roiSize);
|
||
|
||
ippiAlphaCompC_8u_AC4R((Ipp8u*)m_pPixels, 4*m_nWidth, alpha, pBuffer, 4*m_nWidth, 255, (Ipp8u*)m_pPixels, 4*m_nWidth, roiSize, ippAlphaOver);
|
||
}
|
||
|
||
if (pBuffer)
|
||
delete[] pBuffer;
|
||
if (pIntensity)
|
||
delete[] pIntensity;
|
||
}
|
||
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustInvert(double Frame)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// variables
|
||
BYTE Table[256];
|
||
|
||
// compute equalize level
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
Table[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*(255 - nIndex));
|
||
|
||
// apply table
|
||
if (!ApplyTable(Table))
|
||
return S_FALSE;
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustAutocontrast(double Frame)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
//// clamp value
|
||
//Frame = Clamp(Frame);
|
||
|
||
//// variables
|
||
//int nIndex;
|
||
//int xHistogram[256]; ZeroMemory(xHistogram, 256*sizeof(int));
|
||
|
||
//// compute total histogram
|
||
//for (nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
//{
|
||
// xHistogram[m_pPixels[nIndex + 0]]++;
|
||
// xHistogram[m_pPixels[nIndex + 1]]++;
|
||
// xHistogram[m_pPixels[nIndex + 2]]++;
|
||
//}
|
||
|
||
//// variables
|
||
//int nContrastRange, nContrastLevel = MulDiv(m_nSize, 5, 1000);
|
||
//int nContrastSum, nContrastMin, nContrastMax;
|
||
|
||
//// compute minimal scaling value
|
||
//nContrastMin = 0;
|
||
//nContrastSum = 0;
|
||
//for (nIndex = 0; nIndex < 256; ++nIndex)
|
||
//{
|
||
// if (nContrastSum >= nContrastLevel)
|
||
// {
|
||
// nContrastMin = nIndex;
|
||
// break;
|
||
// }
|
||
|
||
|
||
// nContrastSum += xHistogram[nIndex];
|
||
//}
|
||
|
||
//// compute maximal scaling value
|
||
//nContrastMax = 0;
|
||
//nContrastSum = 0;
|
||
//for (nIndex = 255; nIndex >= 0; --nIndex)
|
||
//{
|
||
// if (nContrastSum >= nContrastLevel)
|
||
// {
|
||
// nContrastMax = nIndex;
|
||
// break;
|
||
// }
|
||
|
||
// nContrastSum += xHistogram[nIndex];
|
||
//}
|
||
|
||
//// clamp ranges values
|
||
//nContrastMin = min(nContrastMin, 254);
|
||
//nContrastMax = max(nContrastMax, nContrastMin + 1);
|
||
//nContrastRange = nContrastMax - nContrastMin;
|
||
|
||
//// variables
|
||
//BYTE Table[256];
|
||
|
||
//// compute koefficients
|
||
//double dAlpha1 = Frame;
|
||
//double dAlpha2 = 1.0 - Frame;
|
||
|
||
//// compose table
|
||
//for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
// Table[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(255.0*(nIndex - nContrastMin)/(double)nContrastRange));
|
||
|
||
//// apply table
|
||
//if (!ApplyTable(Table))
|
||
// return S_FALSE;
|
||
|
||
double AutoContr;
|
||
GetAutoContrast(Frame,&AutoContr);
|
||
AdjustContrast(Frame,AutoContr);
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::GetAutoContrast(double Frame, double* Level)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// variables
|
||
int nIndex;
|
||
int xHistogram[256]; ZeroMemory(xHistogram, 256*sizeof(int));
|
||
|
||
// compute total histogram
|
||
for (nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
xHistogram[m_pPixels[nIndex + 0]]++;
|
||
xHistogram[m_pPixels[nIndex + 1]]++;
|
||
xHistogram[m_pPixels[nIndex + 2]]++;
|
||
}
|
||
|
||
// variables
|
||
int nContrastRange, nContrastLevel = MulDiv(m_nSize, 5, 1000);
|
||
int nContrastSum, nContrastMin, nContrastMax;
|
||
|
||
// compute minimal scaling value
|
||
nContrastMin = 0;
|
||
nContrastSum = 0;
|
||
for (nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
if (nContrastSum >= nContrastLevel)
|
||
{
|
||
nContrastMin = nIndex;
|
||
break;
|
||
}
|
||
|
||
|
||
nContrastSum += xHistogram[nIndex];
|
||
}
|
||
|
||
// compute maximal scaling value
|
||
nContrastMax = 0;
|
||
nContrastSum = 0;
|
||
for (nIndex = 255; nIndex >= 0; --nIndex)
|
||
{
|
||
if (nContrastSum >= nContrastLevel)
|
||
{
|
||
nContrastMax = nIndex;
|
||
break;
|
||
}
|
||
|
||
nContrastSum += xHistogram[nIndex];
|
||
}
|
||
|
||
// clamp ranges values
|
||
nContrastMin = min(nContrastMin, 254);
|
||
nContrastMax = max(nContrastMax, nContrastMin + 1);
|
||
nContrastRange = nContrastMax - nContrastMin;
|
||
|
||
if (fabs(Frame)<0.000001)
|
||
Frame = 1.0;
|
||
|
||
*Level = ((double)nContrastRange)/(25.50);
|
||
|
||
// all ok
|
||
return S_OK;
|
||
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustAutolevels(double Frame)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
//// clamp value
|
||
//Frame = Clamp(Frame);
|
||
|
||
//// variables
|
||
//int nIndex;
|
||
//int xHistogram[3][256]; ZeroMemory(xHistogram, 3*256*sizeof(int));
|
||
|
||
//// compute total histogram
|
||
//for (nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
//{
|
||
// xHistogram[0][m_pPixels[nIndex + 0]]++;
|
||
// xHistogram[1][m_pPixels[nIndex + 1]]++;
|
||
// xHistogram[2][m_pPixels[nIndex + 2]]++;
|
||
//}
|
||
|
||
//// variables
|
||
//int nContrastLevel = MulDiv(m_nSize/3, 5, 1000);
|
||
//int nContrastSum[3], nContrastMin[3], nContrastMax[3];
|
||
|
||
//// compute minimal scaling value
|
||
//nContrastMin[0] = nContrastMin[1] = nContrastMin[2] = 0;
|
||
//nContrastSum[0] = nContrastSum[1] = nContrastSum[2] = 0;
|
||
//for (nIndex = 0; nIndex < 256; ++nIndex)
|
||
//{
|
||
// if (!nContrastMin[0] && nContrastSum[0] >= nContrastLevel) nContrastMin[0] = nIndex;
|
||
// if (!nContrastMin[1] && nContrastSum[1] >= nContrastLevel) nContrastMin[1] = nIndex;
|
||
// if (!nContrastMin[2] && nContrastSum[2] >= nContrastLevel) nContrastMin[2] = nIndex;
|
||
|
||
// nContrastSum[0] += xHistogram[0][nIndex];
|
||
// nContrastSum[1] += xHistogram[1][nIndex];
|
||
// nContrastSum[2] += xHistogram[2][nIndex];
|
||
//}
|
||
|
||
//// compute maximal scaling value
|
||
//nContrastMax[0] = nContrastMax[1] = nContrastMax[2] = 0;
|
||
//nContrastSum[0] = nContrastSum[1] = nContrastSum[2] = 0;
|
||
//for (nIndex = 255; nIndex >= 0; --nIndex)
|
||
//{
|
||
// if (!nContrastMax[0] && nContrastSum[0] >= nContrastLevel) nContrastMax[0] = nIndex;
|
||
// if (!nContrastMax[1] && nContrastSum[1] >= nContrastLevel) nContrastMax[1] = nIndex;
|
||
// if (!nContrastMax[2] && nContrastSum[2] >= nContrastLevel) nContrastMax[2] = nIndex;
|
||
|
||
// nContrastSum[0] += xHistogram[0][nIndex];
|
||
// nContrastSum[1] += xHistogram[1][nIndex];
|
||
// nContrastSum[2] += xHistogram[2][nIndex];
|
||
//}
|
||
|
||
//// clamp ranges values
|
||
//nContrastMin[0] = min(nContrastMin[0], 254); nContrastMax[0] = max(nContrastMax[0], nContrastMin[0] + 1);
|
||
//nContrastMin[1] = min(nContrastMin[1], 254); nContrastMax[1] = max(nContrastMax[1], nContrastMin[0] + 1);
|
||
//nContrastMin[2] = min(nContrastMin[2], 254); nContrastMax[2] = max(nContrastMax[2], nContrastMin[0] + 1);
|
||
//
|
||
//// variables
|
||
//BYTE TableR[256];
|
||
//BYTE TableG[256];
|
||
//BYTE TableB[256];
|
||
|
||
//// compute koefficients
|
||
//double dAlpha1 = Frame;
|
||
//double dAlpha2 = 1.0 - Frame;
|
||
|
||
//// compose table
|
||
//for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
//{
|
||
// TableR[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(255.0*(nIndex - nContrastMin[2])/(double)(nContrastMax[2] - nContrastMin[2])));
|
||
// TableG[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(255.0*(nIndex - nContrastMin[1])/(double)(nContrastMax[1] - nContrastMin[1])));
|
||
// TableB[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(255.0*(nIndex - nContrastMin[0])/(double)(nContrastMax[0] - nContrastMin[0])));
|
||
//}
|
||
|
||
//// apply table
|
||
//if (!ApplyTable(TableR, TableG, TableB))
|
||
// return S_FALSE;
|
||
|
||
|
||
double AutoLR,AutoLG,AutoLB;
|
||
GetAutoLevels(Frame,&AutoLR,&AutoLG,&AutoLB);
|
||
AdjustLevels(Frame,AutoLR,AutoLG,AutoLB);
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::AdjustLevels( double Frame, double LevelR, double LevelG, double LevelB)
|
||
{
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
// variables
|
||
BYTE TableR[256];
|
||
BYTE TableG[256];
|
||
BYTE TableB[256];
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
int nContrastMin[3], nContrastMax[3];
|
||
|
||
nContrastMax[0] = (int)(LevelB*5);
|
||
nContrastMin[0] = LevelB*5000.0-nContrastMax[0]*1000.0;
|
||
nContrastMax[1] = (int)(LevelG*5);
|
||
nContrastMin[1] = LevelG*5000.0-nContrastMax[1]*1000.0;
|
||
nContrastMax[2] = (int)(LevelR*5);
|
||
nContrastMin[2] = LevelR*5000.0-nContrastMax[2]*1000.0;
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
TableR[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(255.0*(nIndex - nContrastMin[2])/(double)(nContrastMax[2] - nContrastMin[2])));
|
||
TableG[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(255.0*(nIndex - nContrastMin[1])/(double)(nContrastMax[1] - nContrastMin[1])));
|
||
TableB[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*Byte(255.0*(nIndex - nContrastMin[0])/(double)(nContrastMax[0] - nContrastMin[0])));
|
||
}
|
||
|
||
// apply table
|
||
if (!ApplyTable(TableR, TableG, TableB))
|
||
return S_FALSE;
|
||
// all ok
|
||
ApplyRegister();
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::GetAutoLevels(double Frame, double* LevelR, double* LevelG, double* LevelB)
|
||
{
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// variables
|
||
int nIndex;
|
||
int xHistogram[3][256]; ZeroMemory(xHistogram, 3*256*sizeof(int));
|
||
|
||
// compute total histogram
|
||
for (nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
xHistogram[0][m_pPixels[nIndex + 0]]++;
|
||
xHistogram[1][m_pPixels[nIndex + 1]]++;
|
||
xHistogram[2][m_pPixels[nIndex + 2]]++;
|
||
}
|
||
|
||
// variables
|
||
int nContrastLevel = MulDiv(m_nSize/3, 5, 1000);
|
||
int nContrastSum[3], nContrastMin[3], nContrastMax[3];
|
||
|
||
// compute minimal scaling value
|
||
nContrastMin[0] = nContrastMin[1] = nContrastMin[2] = 0;
|
||
nContrastSum[0] = nContrastSum[1] = nContrastSum[2] = 0;
|
||
for (nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
if (!nContrastMin[0] && nContrastSum[0] >= nContrastLevel) nContrastMin[0] = nIndex;
|
||
if (!nContrastMin[1] && nContrastSum[1] >= nContrastLevel) nContrastMin[1] = nIndex;
|
||
if (!nContrastMin[2] && nContrastSum[2] >= nContrastLevel) nContrastMin[2] = nIndex;
|
||
|
||
nContrastSum[0] += xHistogram[0][nIndex];
|
||
nContrastSum[1] += xHistogram[1][nIndex];
|
||
nContrastSum[2] += xHistogram[2][nIndex];
|
||
}
|
||
|
||
// compute maximal scaling value
|
||
nContrastMax[0] = nContrastMax[1] = nContrastMax[2] = 0;
|
||
nContrastSum[0] = nContrastSum[1] = nContrastSum[2] = 0;
|
||
for (nIndex = 255; nIndex >= 0; --nIndex)
|
||
{
|
||
if (!nContrastMax[0] && nContrastSum[0] >= nContrastLevel) nContrastMax[0] = nIndex;
|
||
if (!nContrastMax[1] && nContrastSum[1] >= nContrastLevel) nContrastMax[1] = nIndex;
|
||
if (!nContrastMax[2] && nContrastSum[2] >= nContrastLevel) nContrastMax[2] = nIndex;
|
||
|
||
nContrastSum[0] += xHistogram[0][nIndex];
|
||
nContrastSum[1] += xHistogram[1][nIndex];
|
||
nContrastSum[2] += xHistogram[2][nIndex];
|
||
}
|
||
|
||
// clamp ranges values
|
||
nContrastMin[0] = min(nContrastMin[0], 254); nContrastMax[0] = max(nContrastMax[0], nContrastMin[0] + 1);
|
||
nContrastMin[1] = min(nContrastMin[1], 254); nContrastMax[1] = max(nContrastMax[1], nContrastMin[0] + 1);
|
||
nContrastMin[2] = min(nContrastMin[2], 254); nContrastMax[2] = max(nContrastMax[2], nContrastMin[0] + 1);
|
||
|
||
*LevelR = (nContrastMin[2]+1000*nContrastMax[2])/5000.0;
|
||
*LevelG = (nContrastMin[1]+1000*nContrastMax[1])/5000.0;
|
||
*LevelB = (nContrastMin[0]+1000*nContrastMax[0])/5000.0;
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustHue(double Frame, double Angle)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Angle *= Clamp(Frame);
|
||
Angle = min(max(-360, Angle), 360);
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM // TODO: disabled optimization due to ignoring completeness value
|
||
|
||
// variables
|
||
float fRed, fGreen, fBlue;
|
||
float fHue, fLightness, fSaturation;
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// balance each pixel
|
||
for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// retrieve pixel color components
|
||
fRed = m_pPixels[nIndex + 2]/255.0f;
|
||
fGreen = m_pPixels[nIndex + 1]/255.0f;
|
||
fBlue = m_pPixels[nIndex + 0]/255.0f;
|
||
|
||
// original color -> Hue-Saturation-Lighteness
|
||
ConvertToHls(fRed, fGreen, fBlue, fHue, fLightness, fSaturation);
|
||
|
||
// compute new hue value
|
||
fHue += (float)Angle;
|
||
|
||
// correct value
|
||
if (fHue < 0) fHue += 360.0f;
|
||
if (fHue > 360.0f) fHue -= 360.0f;
|
||
|
||
// clamp value
|
||
fHue = min(max(0.0f, fHue), 360.0f);
|
||
|
||
// compute new color components
|
||
ConvertToRgb(fHue, fLightness, fSaturation, fRed, fGreen, fBlue);
|
||
|
||
// save pixel color components
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pPixels[nIndex + 2] + dAlpha1*255*fRed);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pPixels[nIndex + 1] + dAlpha1*255*fGreen);
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pPixels[nIndex + 0] + dAlpha1*255*fBlue);
|
||
}
|
||
|
||
#else
|
||
|
||
// variables
|
||
IppiSize roiSize;
|
||
roiSize.width = m_nWidth;
|
||
roiSize.height = m_nHeight;
|
||
Ipp8u* pHLS = new Ipp8u[m_nSize];
|
||
int nLevels[3] = {257, 2, 2};
|
||
Ipp32s* pHValue = new Ipp32s[256];
|
||
Ipp32s* pOValue = new Ipp32s[1];
|
||
Ipp32s* pHLevel = new Ipp32s[257];
|
||
Ipp32s* pOLevel = new Ipp32s[2];
|
||
|
||
if (pHValue && pOValue && pHLevel && pOLevel)
|
||
{
|
||
ippiBGRToHLS_8u_AC4R(m_pPixels, 4*m_nWidth, pHLS, 4*m_nWidth, roiSize);
|
||
|
||
pOValue[0] = 0;
|
||
const Ipp32s* pValues[3] = {pHValue, pOValue, pOValue};
|
||
|
||
pOLevel[0] = 256;
|
||
pOLevel[1] = 257;
|
||
const Ipp32s* pLevels[3] = {pHLevel, pOLevel, pOLevel};
|
||
|
||
Ipp16s nAngle = 0;
|
||
if (Angle>0)
|
||
nAngle = 255*(Angle/360.0);
|
||
else
|
||
nAngle = 255*(1.0 + Angle/360.0);
|
||
|
||
for (int i = 0; i < 256; ++i)
|
||
{
|
||
pHLevel[i] = i;
|
||
pHValue[i] = (i + nAngle) & 0xFF;
|
||
}
|
||
|
||
pHLevel[256] = 256;
|
||
|
||
ippiLUT_8u_AC4R(pHLS, 4*m_nWidth, m_pPixels, 4*m_nWidth, roiSize, pValues, pLevels, nLevels);
|
||
ippiHLSToRGB_8u_AC4R(m_pPixels, 4*m_nWidth, pHLS, 4*m_nWidth, roiSize);
|
||
|
||
int dstOrder[3];
|
||
dstOrder[0] = 2;
|
||
dstOrder[1] = 1;
|
||
dstOrder[2] = 0;
|
||
|
||
ippiSwapChannels_8u_AC4R(pHLS, 4*m_nWidth, m_pPixels, 4*m_nWidth, roiSize, dstOrder);
|
||
}
|
||
|
||
if (pHLS)
|
||
delete[] pHLS;
|
||
if (pHValue)
|
||
delete[] pHValue;
|
||
if (pHLevel)
|
||
delete[] pHLevel;
|
||
if (pOLevel)
|
||
delete[] pOLevel;
|
||
if (pOValue)
|
||
delete[] pOValue;
|
||
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::GetAutoHue(double Completeness, double* Angle)
|
||
{
|
||
float fRed, fGreen, fBlue;
|
||
float fHue, fLightness, fSaturation;
|
||
|
||
int cnts=0;
|
||
*Angle = 0.0;
|
||
|
||
// balance each pixel
|
||
for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// retrieve pixel color components
|
||
fRed = m_pPixels[nIndex + 2]/255.0f;
|
||
fGreen = m_pPixels[nIndex + 1]/255.0f;
|
||
fBlue = m_pPixels[nIndex + 0]/255.0f;
|
||
|
||
// original color -> Hue-Saturation-Lighteness
|
||
ConvertToHls(fRed, fGreen, fBlue, fHue, fLightness, fSaturation);
|
||
|
||
// correct value
|
||
if (fHue < 0) fHue += 360.0f;
|
||
if (fHue > 360.0f) fHue -= 360.0f;
|
||
|
||
// clamp value
|
||
fHue = min(max(0.0f, fHue), 360.0f);
|
||
|
||
*Angle += fHue;
|
||
cnts++;
|
||
}
|
||
|
||
if (cnts>0)
|
||
*Angle /= cnts;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustSaturation(double Frame, double Level)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Level = min(max(-100, Level), 100)*Frame/100.0;
|
||
|
||
// non-optimized variant
|
||
#ifndef NOT_OPTIM
|
||
|
||
// variables
|
||
float fRed, fGreen, fBlue;
|
||
float fHue, fLightness, fSaturation;
|
||
|
||
// balance each pixel
|
||
for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// retrieve pixel color components
|
||
fRed = m_pPixels[nIndex + 2]/255.0f;
|
||
fGreen = m_pPixels[nIndex + 1]/255.0f;
|
||
fBlue = m_pPixels[nIndex + 0]/255.0f;
|
||
|
||
// original color -> Hue-Saturation-Lighteness
|
||
ConvertToHls(fRed, fGreen, fBlue, fHue, fLightness, fSaturation);
|
||
|
||
// compute new saturation value
|
||
fSaturation *= (float)(1.0 + Level);
|
||
|
||
// clamp value
|
||
fSaturation = min(max(0.0f, fSaturation), 1.0f);
|
||
|
||
// compute new color components
|
||
ConvertToRgb(fHue, fLightness, fSaturation, fRed, fGreen, fBlue);
|
||
|
||
// save pixel color components
|
||
m_pPixels[nIndex + 2] = (BYTE)(255*fRed);
|
||
m_pPixels[nIndex + 1] = (BYTE)(255*fGreen);
|
||
m_pPixels[nIndex + 0] = (BYTE)(255*fBlue);
|
||
}
|
||
|
||
#else
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Level
|
||
IppiSize roiSize;
|
||
roiSize.width = m_nWidth;
|
||
roiSize.height = m_nHeight;
|
||
|
||
Ipp8u* pHLS = new Ipp8u[m_nSize];
|
||
|
||
if (pHLS)
|
||
{
|
||
ippiBGRToHLS_8u_AC4R(m_pPixels, 4*m_nWidth, pHLS, 4*m_nWidth, roiSize);
|
||
|
||
Level = (1.0 + Level);
|
||
if (Level < 1.0/255.0)
|
||
{
|
||
int nLevels[3] = {2, 2, 2};
|
||
Ipp32s* pValue = new Ipp32s[1];
|
||
Ipp32s* pSLevel = new Ipp32s[2];
|
||
Ipp32s* pOLevel = new Ipp32s[2];
|
||
|
||
if (pValue && pSLevel && pOLevel)
|
||
{
|
||
pValue[0] = 0;
|
||
const Ipp32s* pValues[3] = {pValue, pValue, pValue};
|
||
|
||
pSLevel[0] = 0;
|
||
pSLevel[1] = 257;
|
||
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
pOLevel[0] = 256;
|
||
pOLevel[1] = 257;
|
||
const Ipp32s* pLevels[3] = {pOLevel, pOLevel, pSLevel};
|
||
|
||
ippiLUT_8u_AC4R(pHLS, 4*m_nWidth, m_pPixels, 4*m_nWidth, roiSize, pValues, pLevels, nLevels);
|
||
}
|
||
|
||
if (pValue)
|
||
delete[] pValue;
|
||
if (pSLevel)
|
||
delete pSLevel;
|
||
if (pOLevel)
|
||
delete pOLevel;
|
||
}
|
||
else if (Level < 1.0)
|
||
{
|
||
int nLevels[3] = {2, 2, 2};
|
||
Ipp32s* pSValue = new Ipp32s[256];
|
||
Ipp32s* pOValue = new Ipp32s[1];
|
||
Ipp32s* pSLevel = new Ipp32s[257];
|
||
Ipp32s* pOLevel = new Ipp32s[2];
|
||
|
||
if (pSValue && pOValue && pSLevel && pOLevel)
|
||
{
|
||
pOValue[0] = 0;
|
||
const Ipp32s* pValues[3] = {pOValue, pOValue, pSValue};
|
||
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
pOLevel[0] = 256;
|
||
pOLevel[1] = 257;
|
||
const Ipp32s* pLevels[3] = {pOLevel, pOLevel, pSLevel};
|
||
|
||
float fSum = 0.0;
|
||
int nLevelCount=0;
|
||
pSLevel[0] = 0;
|
||
pSValue[0] = 0;
|
||
for (int i = 0; i < 256; ++i)
|
||
{
|
||
fSum += (float)Level;
|
||
if (fSum > 0.5f)
|
||
{
|
||
nLevelCount++;
|
||
pSLevel[nLevelCount] = i;
|
||
pSValue[nLevelCount] = pSValue[nLevelCount] + 1;
|
||
fSum -= 1.0;
|
||
}
|
||
}
|
||
|
||
nLevelCount++;
|
||
pSLevel[nLevelCount] = 256;
|
||
nLevels[2] = nLevelCount + 1;
|
||
|
||
ippiLUT_8u_AC4R(pHLS, 4*m_nWidth, m_pPixels, 4*m_nWidth, roiSize, pValues, pLevels, nLevels);
|
||
}
|
||
|
||
if (pSValue)
|
||
delete[] pSValue;
|
||
if (pSLevel)
|
||
delete[] pSLevel;
|
||
if (pOLevel)
|
||
delete[] pOLevel;
|
||
if (pOValue)
|
||
delete[] pOValue;
|
||
}
|
||
else
|
||
{
|
||
int nLevels[3] = {2,2,257};
|
||
Ipp32s* pSValue = new Ipp32s[256];
|
||
Ipp32s* pOValue = new Ipp32s[1];
|
||
Ipp32s* pSLevel = new Ipp32s[257];
|
||
Ipp32s* pOLevel = new Ipp32s[2];
|
||
|
||
if (pSValue && pOValue && pSLevel && pOLevel)
|
||
{
|
||
pOValue[0] = 0;
|
||
const Ipp32s* pValues[3] = {pOValue, pOValue, pSValue};
|
||
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
pOLevel[0] = 256;
|
||
pOLevel[1] = 257;
|
||
const Ipp32s* pLevels[3] = {pOLevel, pOLevel, pSLevel};
|
||
|
||
float fSum = 0.0;
|
||
pSLevel[0] = 0;
|
||
pSValue[0] = 0;
|
||
|
||
int i=0;
|
||
for (; i < 256; ++i)
|
||
{
|
||
pSLevel[i] = i;
|
||
pSValue[i] = i*Level;
|
||
}
|
||
pSLevel[256] = 256;
|
||
|
||
ippiLUT_8u_AC4R(pHLS, 4*m_nWidth, m_pPixels, 4*m_nWidth, roiSize, pValues, pLevels, nLevels);
|
||
}
|
||
|
||
if (pSValue)
|
||
delete[] pSValue;
|
||
if (pSLevel)
|
||
delete[] pSLevel;
|
||
if (pOLevel)
|
||
delete[] pOLevel;
|
||
if (pOValue)
|
||
delete[] pOValue;
|
||
}
|
||
|
||
ippiHLSToRGB_8u_AC4R(m_pPixels, 4*m_nWidth, pHLS, 4*m_nWidth, roiSize);
|
||
|
||
int dstOrder[3];
|
||
dstOrder[0] = 2;
|
||
dstOrder[1] = 1;
|
||
dstOrder[2] = 0;
|
||
|
||
ippiSwapChannels_8u_AC4R(pHLS, 4*m_nWidth, m_pPixels, 4*m_nWidth, roiSize, dstOrder);
|
||
|
||
delete[] pHLS;
|
||
}
|
||
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::GetAutoSaturation(double Completeness, double* Level)
|
||
{
|
||
//GetAutoContrast(Completeness,Level);
|
||
// variables
|
||
float fRed, fGreen, fBlue;
|
||
float fHue, fLightness, fSaturation;
|
||
|
||
int cnts=0;
|
||
*Level = 0.0;
|
||
|
||
// balance each pixel
|
||
for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// retrieve pixel color components
|
||
fRed = m_pPixels[nIndex + 2]/255.0f;
|
||
fGreen = m_pPixels[nIndex + 1]/255.0f;
|
||
fBlue = m_pPixels[nIndex + 0]/255.0f;
|
||
|
||
// original color -> Hue-Saturation-Lighteness
|
||
ConvertToHls(fRed, fGreen, fBlue, fHue, fLightness, fSaturation);
|
||
|
||
// clamp value
|
||
fSaturation = min(max(0.0f, fSaturation), 1.0f);
|
||
|
||
*Level += fSaturation;
|
||
cnts++;
|
||
}
|
||
|
||
if (cnts>0)
|
||
*Level /= cnts;
|
||
|
||
return S_OK;
|
||
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustPosterize(double Frame, long Levels)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Levels = max(2, min(255, Levels));
|
||
|
||
// variables
|
||
BYTE Table[256];
|
||
int nValue;
|
||
double dKoef = (Levels - 1) / 255.0;
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
nValue = (int)(0.5 + dKoef*nIndex);
|
||
|
||
if (nValue < 0)
|
||
nValue = 0;
|
||
else if (nValue >= Levels)
|
||
nValue = Levels - 1;
|
||
|
||
Table[nIndex] = (BYTE)(nIndex*(1.0 - Frame) + Frame*MulDiv(255, nValue, Levels - 1));
|
||
}
|
||
|
||
// apply table
|
||
if (!ApplyTable(Table))
|
||
return S_FALSE;
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
LRESULT ImageTransform3::GetAutoPosterize(double Completeness, long* Levels)
|
||
{
|
||
double tmpVals[3];
|
||
GetAutoLevels(Completeness,&tmpVals[0],&tmpVals[1],&tmpVals[2]);
|
||
|
||
*Levels = (tmpVals[0]+tmpVals[1]+tmpVals[2])/3.0;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustTemperature(double Frame, double Level)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Level = min(100, max(-100, Level));
|
||
|
||
// variables
|
||
BYTE TableR[256];
|
||
BYTE TableG[256];
|
||
BYTE TableB[256];
|
||
|
||
// color adjustment coeffs
|
||
double dDeltaRed = 0.3;
|
||
double dDeltaGreen = 0.05;
|
||
double dDeltaBlue = -0.2;
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
TableR[nIndex] = Byte(nIndex + Frame*Level*dDeltaRed);
|
||
TableG[nIndex] = Byte(nIndex + Frame*Level*dDeltaGreen);
|
||
TableB[nIndex] = Byte(nIndex + Frame*Level*dDeltaBlue);
|
||
}
|
||
|
||
// apply table
|
||
if (!ApplyTable(TableR, TableG, TableB))
|
||
return S_FALSE;
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustColorize(double Frame, long Red, long Green, long Blue)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp value
|
||
Frame = Clamp(Frame);
|
||
|
||
// variables
|
||
BYTE Value;
|
||
BYTE TableR[256];
|
||
BYTE TableG[256];
|
||
BYTE TableB[256];
|
||
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
TableR[nIndex] = MulDiv(Red, nIndex, 255);
|
||
TableG[nIndex] = MulDiv(Green, nIndex, 255);
|
||
TableB[nIndex] = MulDiv(Blue, nIndex, 255);
|
||
}
|
||
|
||
// correct alpha values
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// apply table
|
||
for (int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// compute new color
|
||
Value = Intensity(m_pPixels[nIndex + 2], m_pPixels[nIndex + 1], m_pPixels[nIndex + 0]);
|
||
|
||
// compute new color
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pPixels[nIndex + 0] + dAlpha1*TableB[Value]);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pPixels[nIndex + 1] + dAlpha1*TableG[Value]);
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pPixels[nIndex + 2] + dAlpha1*TableR[Value]);
|
||
}
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::AdjustThreshold(double Frame, long Level, VARIANT_BOOL Grayscale)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// variables
|
||
BYTE Table[256];
|
||
|
||
// compute equalize level
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// check for grayscale image
|
||
if (Grayscale == VARIANT_TRUE)
|
||
{
|
||
AdjustGrayscale(Frame, VARIANT_FALSE);
|
||
}
|
||
// compose table
|
||
for (int nIndex = 0; nIndex < 256; ++nIndex)
|
||
{
|
||
Table[nIndex] = (BYTE)(dAlpha2*nIndex + dAlpha1*(nIndex < Level ? 0 : 255));
|
||
}
|
||
// apply table
|
||
if (!ApplyTable(Table))
|
||
{
|
||
return S_FALSE;
|
||
}
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectBlur(double Frame, double Level)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Level = min(100, max(0, Level));
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// compose matrix
|
||
double Matrix[9];
|
||
Matrix[0] = Matrix[1] = Matrix[2] = Matrix[3] = Matrix[5] = Matrix[6] = Matrix[7] = Matrix[8] = 1;
|
||
Matrix[4] = (double)(21 - 20*Frame*Level/100.0);
|
||
|
||
// matrix parameters
|
||
int nOffsetsX[] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
|
||
int nOffsetsY[] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
|
||
double dMatrixKoef = 1.0/(Matrix[4] + 8.0);
|
||
|
||
// variables
|
||
int nX, nY, nIndex, nPoint;
|
||
int nSourceX, nSourceY, nSourceIndex;
|
||
double dRed, dGreen, dBlue;
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// for each pixel - compute new color value
|
||
for (nY = 0, nIndex = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// set the default maximal values
|
||
dRed = 0;
|
||
dGreen = 0;
|
||
dBlue = 0;
|
||
|
||
// compute new pixel color
|
||
for (nPoint = 0; nPoint < 9; ++nPoint)
|
||
{
|
||
// compute source pixel
|
||
nSourceX = nX + nOffsetsX[nPoint];
|
||
nSourceY = nY + nOffsetsY[nPoint];
|
||
|
||
// clamp cordinates
|
||
if (nSourceX < 0) nSourceX = 0;
|
||
else if (nSourceX > m_nWidth - 1) nSourceX = m_nWidth - 1;
|
||
if (nSourceY < 0) nSourceY = 0;
|
||
else if (nSourceY > m_nHeight - 1) nSourceY = m_nHeight - 1;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// update color and denominator
|
||
dRed += Matrix[nPoint]*m_pBackup[nSourceIndex + 2];
|
||
dGreen += Matrix[nPoint]*m_pBackup[nSourceIndex + 1];
|
||
dBlue += Matrix[nPoint]*m_pBackup[nSourceIndex + 0];
|
||
}
|
||
|
||
// save resulting color
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pBackup[nIndex + 0] + dAlpha1*Byte(dMatrixKoef*dBlue));
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pBackup[nIndex + 1] + dAlpha1*Byte(dMatrixKoef*dGreen));
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pBackup[nIndex + 2] + dAlpha1*Byte(dMatrixKoef*dRed));
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#else
|
||
IPPEffectBlur(m_pPixels,m_nWidth,m_nHeight,Frame,Level);
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectSharpen(double Frame, double Level)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Level = min(100, max(0, Level));
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// compose matrix
|
||
double Matrix[9];
|
||
Matrix[0] = Matrix[1] = Matrix[2] = Matrix[3] = Matrix[5] = Matrix[6] = Matrix[7] = Matrix[8] = -1;
|
||
Matrix[4] = (double)(9 + 23*(1.0 - Frame*Level/100.0));
|
||
|
||
// matrix parameters
|
||
int nOffsetsX[] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
|
||
int nOffsetsY[] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
|
||
double dMatrixKoef = 1.0/(Matrix[4] - 8.0);
|
||
|
||
// variables
|
||
int nX, nY, nIndex, nPoint;
|
||
int nSourceX, nSourceY, nSourceIndex;
|
||
double dRed, dGreen, dBlue;
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// for each pixel - compute new color value
|
||
for (nY = 0, nIndex = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// set the default maximal values
|
||
dRed = 0;
|
||
dGreen = 0;
|
||
dBlue = 0;
|
||
|
||
// compute new pixel color
|
||
for (nPoint = 0; nPoint < 9; ++nPoint)
|
||
{
|
||
// compute source pixel
|
||
nSourceX = nX + nOffsetsX[nPoint];
|
||
nSourceY = nY + nOffsetsY[nPoint];
|
||
|
||
// clamp cordinates
|
||
if (nSourceX < 0) nSourceX = 0;
|
||
else if (nSourceX > m_nWidth - 1) nSourceX = m_nWidth - 1;
|
||
if (nSourceY < 0) nSourceY = 0;
|
||
else if (nSourceY > m_nHeight - 1) nSourceY = m_nHeight - 1;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// update color and denominator
|
||
dRed += Matrix[nPoint]*m_pBackup[nSourceIndex + 2];
|
||
dGreen += Matrix[nPoint]*m_pBackup[nSourceIndex + 1];
|
||
dBlue += Matrix[nPoint]*m_pBackup[nSourceIndex + 0];
|
||
}
|
||
|
||
// save resulting color
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pBackup[nIndex + 0] + dAlpha1*Byte(dMatrixKoef*dBlue));
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pBackup[nIndex + 1] + dAlpha1*Byte(dMatrixKoef*dGreen));
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pBackup[nIndex + 2] + dAlpha1*Byte(dMatrixKoef*dRed));
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#else
|
||
IPPEffectSharpen(m_pPixels,m_nWidth,m_nHeight,Frame,Level);
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectMosaic(double Frame, long Size, VARIANT_BOOL Simple)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Size = (int)(min(255, max(1, Size*Frame)));
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
int nTilesX = m_nWidth/Size + (m_nWidth % Size > 0 ? 1 : 0);
|
||
int nTilesY = m_nHeight/Size + (m_nHeight % Size > 0 ? 1 : 0);
|
||
int nX, nY, nIndex, nTX, nTY, nTLeft, nTRight, nTTop, nTBottom;
|
||
int nRed, nGreen, nBlue, nDenom;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// quadrize image
|
||
for (nTY = 0; nTY < nTilesY; ++nTY)
|
||
{
|
||
// compute tile y - ranges
|
||
nTTop = nTY*Size;
|
||
nTBottom = nTTop + Size;
|
||
|
||
// clamp tile y - range
|
||
nTBottom = min(nTBottom, m_nHeight);
|
||
|
||
for (nTX = 0; nTX < nTilesX; ++nTX)
|
||
{
|
||
// compute tile x - ranges
|
||
nTLeft = nTX*Size;
|
||
nTRight = nTLeft + Size;
|
||
|
||
// clamp tile x - range
|
||
nTRight = min(nTRight, m_nWidth);
|
||
|
||
// set tile color
|
||
if (Simple == VARIANT_TRUE)
|
||
{
|
||
// compute pixel index
|
||
nIndex = 4*(nTTop*m_nWidth + nTLeft);
|
||
|
||
// retrieve pixel color
|
||
nRed = m_pBackup[nIndex + 2];
|
||
nGreen = m_pBackup[nIndex + 1];
|
||
nBlue = m_pBackup[nIndex + 0];
|
||
|
||
// apply computed color
|
||
for (nY = nTTop; nY < nTBottom; ++nY)
|
||
{
|
||
// compute starting index
|
||
nIndex = 4*(nY*m_nWidth + nTLeft);
|
||
|
||
for (nX = nTLeft; nX < nTRight; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// update color
|
||
m_pPixels[nIndex + 2] = nRed;
|
||
m_pPixels[nIndex + 1] = nGreen;
|
||
m_pPixels[nIndex + 0] = nBlue;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// prepare color values
|
||
nRed = 0;
|
||
nGreen = 0;
|
||
nBlue = 0;
|
||
nDenom = 0;
|
||
|
||
// compute tile color and tile pixel indexes
|
||
for (nY = nTTop; nY < nTBottom; ++nY)
|
||
{
|
||
// compute starting pixel index
|
||
nIndex = 4*(nY*m_nWidth + nTLeft);
|
||
|
||
for (nX = nTLeft; nX < nTRight; ++nX, nIndex += 4)
|
||
{
|
||
// update color
|
||
nRed += m_pBackup[nIndex + 2];
|
||
nGreen += m_pBackup[nIndex + 1];
|
||
nBlue += m_pBackup[nIndex + 0];
|
||
|
||
// update denominator
|
||
nDenom += 1;
|
||
}
|
||
}
|
||
|
||
// compute average color value
|
||
nRed /= nDenom;
|
||
nGreen /= nDenom;
|
||
nBlue /= nDenom;
|
||
|
||
// apply computed color to each pixel of the tile
|
||
for (nY = nTTop; nY < nTBottom; ++nY)
|
||
{
|
||
// compute starting pixel index
|
||
nIndex = 4*(nY*m_nWidth + nTLeft);
|
||
|
||
for (nX = nTLeft; nX < nTRight; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// update color
|
||
m_pPixels[nIndex + 2] = nRed;
|
||
m_pPixels[nIndex + 1] = nGreen;
|
||
m_pPixels[nIndex + 0] = nBlue;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#else
|
||
IPPEffectMosaic(m_pPixels, m_nWidth, m_nHeight, Frame, Size, (VARIANT_TRUE == Simple));
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectGaussianBlur(double Frame, long Size)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Size = int(Size*Frame + 0.5);
|
||
Size = (min(100, max(0, Size)));
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
int nRed, nGreen, nBlue, nDenom = 2*Size + 1;
|
||
|
||
// create additional channel
|
||
BYTE* pCopy = new BYTE[4*m_nWidth*m_nHeight];
|
||
|
||
// check for allocated memory
|
||
if (!pCopy)
|
||
return S_OK;
|
||
|
||
// variables
|
||
int nX, nY, nIndex, nOffset;
|
||
int nSourceX, nSourceY, nSourceIndex;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
for (int nStep = 0; nStep < 2; ++nStep)
|
||
{
|
||
// compute starting index
|
||
nIndex = 0;
|
||
|
||
// combine several moved images
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// prepare color values
|
||
nRed = 0;
|
||
nGreen = 0;
|
||
nBlue = 0;
|
||
|
||
// compute moved pixels sum
|
||
for (nOffset = -Size; nOffset <= Size; ++nOffset)
|
||
{
|
||
// compute source y coordinate
|
||
nSourceY = nOffset + nY;
|
||
|
||
// clamp it to valid range
|
||
if (nSourceY < 0) nSourceY = 0;
|
||
else if (nSourceY >= m_nHeight) nSourceY = m_nHeight - 1;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nX + nSourceY*m_nWidth);
|
||
|
||
// update color value
|
||
nRed += m_pPixels[nSourceIndex + 2];
|
||
nGreen += m_pPixels[nSourceIndex + 1];
|
||
nBlue += m_pPixels[nSourceIndex + 0];
|
||
}
|
||
|
||
// save color
|
||
pCopy[nIndex + 2] = (BYTE)(nRed/nDenom);
|
||
pCopy[nIndex + 1] = (BYTE)(nGreen/nDenom);
|
||
pCopy[nIndex + 0] = (BYTE)(nBlue/nDenom);
|
||
}
|
||
}
|
||
|
||
// compute starting index
|
||
nIndex = 0;
|
||
|
||
// combine several moved images
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
// compute starting index
|
||
nSourceIndex = 4*(nY*m_nWidth);
|
||
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// prepare color values
|
||
nRed = 0;
|
||
nGreen = 0;
|
||
nBlue = 0;
|
||
|
||
// compute moved pixels sum
|
||
for (nOffset = -Size; nOffset <= Size; ++nOffset)
|
||
{
|
||
// compute source y coordinate
|
||
nSourceX = nOffset + nX;
|
||
|
||
// clamp it to valid range
|
||
if (nSourceX < 0) nSourceX = 0;
|
||
else if (nSourceX >= m_nWidth) nSourceX = m_nWidth - 1;
|
||
|
||
// update color value
|
||
nRed += pCopy[nSourceIndex + 4*nSourceX + 2];
|
||
nGreen += pCopy[nSourceIndex + 4*nSourceX + 1];
|
||
nBlue += pCopy[nSourceIndex + 4*nSourceX + 0];
|
||
}
|
||
|
||
// save color
|
||
m_pPixels[nIndex + 2] = (BYTE)(nRed/nDenom);
|
||
m_pPixels[nIndex + 1] = (BYTE)(nGreen/nDenom);
|
||
m_pPixels[nIndex + 0] = (BYTE)(nBlue/nDenom);
|
||
}
|
||
}
|
||
}
|
||
|
||
// clear memory
|
||
delete[] pCopy;
|
||
|
||
// restore unchanged pixels
|
||
for (nY = 0, nIndex = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] == 0)
|
||
{
|
||
// restore pixel color
|
||
m_pPixels[nIndex + 2] = m_pBackup[nIndex + 2];
|
||
m_pPixels[nIndex + 1] = m_pBackup[nIndex + 1];
|
||
m_pPixels[nIndex + 0] = m_pBackup[nIndex + 0];
|
||
}
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#else
|
||
if( Size < 10 )
|
||
{
|
||
IPPEffectGaussianBlur( m_pPixels, m_nWidth, m_nHeight, Frame, Size );
|
||
}
|
||
else
|
||
{
|
||
IPPEffectGaussianBlur2( m_pPixels, m_nWidth, m_nHeight, Frame, Size );
|
||
}
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectNoise(double Frame, double Level, VARIANT_BOOL Mono)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Level = (int)(min(1000, max(1, Level*Frame)));
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nRed, nGreen, nBlue;
|
||
int nNoiseRed, nNoiseGreen, nNoiseBlue;
|
||
|
||
// restart randomizer
|
||
srand(GetTickCount());
|
||
|
||
// compute starting index
|
||
nIndex = 0;
|
||
|
||
// add noise to image
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// retrieve pixel color
|
||
nRed = m_pPixels[nIndex + 2];
|
||
nGreen = m_pPixels[nIndex + 1];
|
||
nBlue = m_pPixels[nIndex + 0];
|
||
|
||
// add noise
|
||
if (Mono == VARIANT_TRUE)
|
||
nNoiseRed = nNoiseGreen = nNoiseBlue = (int)(Level*Random());
|
||
else
|
||
{
|
||
nNoiseRed = (int)(Level*Random());
|
||
nNoiseGreen = (int)(Level*Random());
|
||
nNoiseBlue = (int)(Level*Random());
|
||
}
|
||
|
||
// add noise to color
|
||
nRed += nNoiseRed;
|
||
nGreen += nNoiseGreen;
|
||
nBlue += nNoiseBlue;
|
||
|
||
// save color
|
||
m_pPixels[nIndex + 2] = Byte(nRed);
|
||
m_pPixels[nIndex + 1] = Byte(nGreen);
|
||
m_pPixels[nIndex + 0] = Byte(nBlue);
|
||
}
|
||
}
|
||
|
||
#else
|
||
IPPEffectNoise(m_pPixels,m_nWidth,m_nHeight,Frame,Level,(VARIANT_TRUE==Mono));
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectDiffuse(double Frame, double Distance)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Distance = min(255, max(1, Distance));
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// restart randomizer
|
||
srand(GetTickCount());
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nXSwap, nYSwap, nIndexSwap;
|
||
double dRed, dGreen, dBlue;
|
||
double dRedSwap, dGreenSwap, dBlueSwap;
|
||
|
||
// compute penetration values
|
||
double dValue1 = 1.0 - Frame;
|
||
double dValue2 = Frame;
|
||
|
||
// diffuse image
|
||
for (nY = 0, nIndex = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// compute random swap pixel
|
||
nXSwap = nX + (int)(Distance*Random());
|
||
nYSwap = nY + (int)(Distance*Random());
|
||
|
||
// check whether pixel coordinates are valid
|
||
if (nXSwap < 0 || nXSwap >= m_nWidth || nYSwap < 0 || nYSwap >= m_nHeight)
|
||
continue;
|
||
|
||
// compute swap pixel index
|
||
nIndexSwap = 4*(nXSwap + nYSwap*m_nWidth);
|
||
|
||
// compute swapped colors
|
||
dRed = dValue1*m_pPixels[nIndex + 2] + dValue2*m_pPixels[nIndexSwap + 2];
|
||
dGreen = dValue1*m_pPixels[nIndex + 1] + dValue2*m_pPixels[nIndexSwap + 1];
|
||
dBlue = dValue1*m_pPixels[nIndex + 0] + dValue2*m_pPixels[nIndexSwap + 0];
|
||
|
||
dRedSwap = dValue1*m_pPixels[nIndexSwap + 2] + dValue2*m_pPixels[nIndex + 2];
|
||
dGreenSwap = dValue1*m_pPixels[nIndexSwap + 1] + dValue2*m_pPixels[nIndex + 1];
|
||
dBlueSwap = dValue1*m_pPixels[nIndexSwap + 0] + dValue2*m_pPixels[nIndex + 0];
|
||
|
||
// swap pixels
|
||
m_pPixels[nIndex + 2] = (BYTE)dRed;
|
||
m_pPixels[nIndex + 1] = (BYTE)dGreen;
|
||
m_pPixels[nIndex + 0] = (BYTE)dBlue;
|
||
|
||
m_pPixels[nIndexSwap + 2] = (BYTE)dRedSwap;
|
||
m_pPixels[nIndexSwap + 1] = (BYTE)dGreenSwap;
|
||
m_pPixels[nIndexSwap + 0] = (BYTE)dBlueSwap;
|
||
}
|
||
}
|
||
|
||
#else
|
||
IPPEffectDiffuse(m_pPixels,m_nWidth,m_nHeight,Frame,Distance);
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectMotionBlur(double Frame, double Angle, double Distance)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// compute number of pixels to process
|
||
int nAmount = (int)(max(1, Frame*min(max(1, Distance), 255)));
|
||
|
||
// compute angle in radians
|
||
double dAngleInRadians = 3.14159265359*(Angle)/180.0;
|
||
|
||
// variables
|
||
int nSourceX, nSourceY, nSourceIndex;
|
||
int nX, nY, nIndex, nPoint;
|
||
int nRed, nGreen, nBlue, nDenom = nAmount;
|
||
|
||
// allocate memory for offsets
|
||
int* nOffsetsX = new int[nAmount];
|
||
int* nOffsetsY = new int[nAmount];
|
||
|
||
// compute offsets
|
||
for (nPoint = 0; nPoint < nAmount; ++nPoint)
|
||
{
|
||
nOffsetsX[nPoint] = (int)(0.5 + nPoint*cos(dAngleInRadians));
|
||
nOffsetsY[nPoint] = (int)(0.5 + nPoint*sin(dAngleInRadians));
|
||
}
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// initialize pixel index
|
||
nIndex = 0;
|
||
|
||
// for each pixel - compute new color value
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// initialize color values
|
||
nRed = 0;
|
||
nGreen = 0;
|
||
nBlue = 0;
|
||
|
||
// compute new pixel color
|
||
for (nPoint = 0; nPoint < nAmount; ++nPoint)
|
||
{
|
||
nSourceX = nX + nOffsetsX[nPoint];
|
||
nSourceY = nY + nOffsetsY[nPoint];
|
||
|
||
// clamp cordinates
|
||
if (nSourceX < 0) nSourceX = 0;
|
||
else if (nSourceX > m_nWidth - 1) nSourceX = m_nWidth - 1;
|
||
if (nSourceY < 0) nSourceY = 0;
|
||
else if (nSourceY > m_nHeight - 1) nSourceY = m_nHeight - 1;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// update color and denominator
|
||
nRed += m_pBackup[nSourceIndex + 2];
|
||
nGreen += m_pBackup[nSourceIndex + 1];
|
||
nBlue += m_pBackup[nSourceIndex + 0];
|
||
}
|
||
|
||
// save resulting color
|
||
m_pPixels[nIndex + 2] = (BYTE)(nRed/nDenom);
|
||
m_pPixels[nIndex + 1] = (BYTE)(nGreen/nDenom);
|
||
m_pPixels[nIndex + 0] = (BYTE)(nBlue/nDenom);
|
||
}
|
||
}
|
||
|
||
// clear memory
|
||
delete[] nOffsetsX;
|
||
delete[] nOffsetsY;
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectEmboss(double Frame, double Angle, double Distance, double Amount)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Amount = min(max(Frame*Amount, 1), 100)/10.0;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nSourceX[2], nSourceY[2], nSourceIndex[2];
|
||
int nRed[2], nGreen[2], nBlue[2];
|
||
|
||
double dRadians = 3.14159265359*Angle/180;
|
||
double dX = 0.5*Frame*Distance*cos(dRadians);
|
||
double dY = 0.5*Frame*Distance*sin(dRadians);
|
||
|
||
dX += dX > 0 ? 0.5 : -0.5;
|
||
dY += dY > 0 ? 0.5 : -0.5;
|
||
|
||
int nDeltaX = int(dX);
|
||
int nDeltaY = int(dY);
|
||
|
||
if( !nDeltaX && !nDeltaY )
|
||
{
|
||
nDeltaX = 1;
|
||
}
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// initialize pixel index
|
||
nIndex = 0;
|
||
|
||
// for each pixel - compute new color value
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// compute source pixels coordinates
|
||
nSourceX[0] = nX + nDeltaX;
|
||
nSourceY[0] = nY + nDeltaY;
|
||
nSourceX[1] = nX - nDeltaX;
|
||
nSourceY[1] = nY - nDeltaY;
|
||
|
||
// correct coordinates and compute pixel indexes
|
||
for (int nPoint = 0; nPoint < 2; ++nPoint)
|
||
{
|
||
// check whether source coordinates are valid
|
||
if (nSourceX[nPoint] < 0) nSourceX[nPoint] = 0;
|
||
if (nSourceX[nPoint] >= m_nWidth) nSourceX[nPoint] = m_nWidth - 1;
|
||
if (nSourceY[nPoint] < 0) nSourceY[nPoint] = 0;
|
||
if (nSourceY[nPoint] >= m_nHeight) nSourceY[nPoint] = m_nHeight - 1;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex[nPoint] = 4*(nSourceX[nPoint] + nSourceY[nPoint]*m_nWidth);
|
||
|
||
// retrieve current pixel color
|
||
nRed[nPoint] = m_pBackup[nSourceIndex[nPoint] + 2];
|
||
nGreen[nPoint] = m_pBackup[nSourceIndex[nPoint] + 1];
|
||
nBlue[nPoint] = m_pBackup[nSourceIndex[nPoint] + 0];
|
||
}
|
||
|
||
// compute result color
|
||
nRed[0] = (nRed[0] + (255 - nRed[1])) >>1;
|
||
nGreen[0] = (nGreen[0] + (255 - nGreen[1]))>>1;
|
||
nBlue[0] = (nBlue[0] + (255 - nBlue[1])) >>1;
|
||
|
||
// save pixel color
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pBackup[nIndex + 2] + dAlpha1*Byte(127 + (nRed[0] - 127)*Amount));
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pBackup[nIndex + 1] + dAlpha1*Byte(127 + (nGreen[0] - 127)*Amount));
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pBackup[nIndex + 0] + dAlpha1*Byte(127 + (nBlue[0] - 127)*Amount));
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectMinimal(double Frame, long Size)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Size = min(max(Size, 1), 255);
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nSourceX, nSourceY, nSourceIndex;
|
||
int nMinRed, nMinGreen, nMinBlue;
|
||
int nDX, nDY;
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// initialize pixel index
|
||
nIndex = 0;
|
||
|
||
// for each pixel - compute new color value
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// set the default minimal values
|
||
nMinRed = 255;
|
||
nMinGreen = 255;
|
||
nMinBlue = 255;
|
||
|
||
// compute new pixel color
|
||
for (nDY = -Size; nDY <= Size; ++nDY)
|
||
{
|
||
for (nDX = -Size; nDX <= Size; ++nDX)
|
||
{
|
||
nSourceX = nX + nDX;
|
||
nSourceY = nY + nDY;
|
||
|
||
// clamp cordinates
|
||
if (nSourceX < 0 || nSourceX > m_nWidth - 1 || nSourceY < 0 || nSourceY > m_nHeight - 1)
|
||
continue;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// update color
|
||
nMinRed = min(nMinRed, m_pBackup[nSourceIndex + 2]);
|
||
nMinGreen = min(nMinGreen, m_pBackup[nSourceIndex + 1]);
|
||
nMinBlue = min(nMinBlue, m_pBackup[nSourceIndex + 0]);
|
||
}
|
||
}
|
||
|
||
// save resulting color
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pBackup[nIndex + 2] + dAlpha1*nMinRed);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pBackup[nIndex + 1] + dAlpha1*nMinGreen);
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pBackup[nIndex + 0] + dAlpha1*nMinBlue);
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#else
|
||
IPPEffectMinimal(m_pPixels,m_nWidth,m_nHeight,Frame,Size);
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectMaximal(double Frame, long Size)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Size = min(max(Size, 1), 255);
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nSourceX, nSourceY, nSourceIndex;
|
||
int nMaxRed, nMaxGreen, nMaxBlue;
|
||
int nDX, nDY;
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
|
||
// initialize pixel index
|
||
nIndex = 0;
|
||
|
||
// for each pixel - compute new color value
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// set the default maximal values
|
||
nMaxRed = 0;
|
||
nMaxGreen = 0;
|
||
nMaxBlue = 0;
|
||
|
||
// compute new pixel color
|
||
for (nDY = -Size; nDY <= Size; ++nDY)
|
||
{
|
||
for (nDX = -Size; nDX <= Size; ++nDX)
|
||
{
|
||
nSourceX = nX + nDX;
|
||
nSourceY = nY + nDY;
|
||
|
||
// clamp cordinates
|
||
if (nSourceX < 0 || nSourceX > m_nWidth - 1 || nSourceY < 0 || nSourceY > m_nHeight - 1)
|
||
continue;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// update color
|
||
nMaxRed = max(nMaxRed, m_pBackup[nSourceIndex + 2]);
|
||
nMaxGreen = max(nMaxGreen, m_pBackup[nSourceIndex + 1]);
|
||
nMaxBlue = max(nMaxBlue, m_pBackup[nSourceIndex + 0]);
|
||
}
|
||
}
|
||
|
||
// save resulting color
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pBackup[nIndex + 2] + dAlpha1*nMaxRed);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pBackup[nIndex + 1] + dAlpha1*nMaxGreen);
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pBackup[nIndex + 0] + dAlpha1*nMaxBlue);
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#else
|
||
IPPEffectMaximal(m_pPixels,m_nWidth,m_nHeight,Frame,Size);
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectDeinterlace(double Frame, VARIANT_BOOL Even, VARIANT_BOOL Interpolate)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// non-optimized variant
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
int nX, nY, nIndex1, nIndex2, nIndex3;
|
||
int nStartLine = (Even == VARIANT_TRUE) ? 0 : 1;
|
||
|
||
// compute koefficients
|
||
double dAlpha1 = Frame;
|
||
double dAlpha2 = 1.0 - Frame;
|
||
double dAlpha3 = 0.5*dAlpha1;
|
||
|
||
// for each pixel - compute new color value
|
||
for (nY = nStartLine; nY < m_nHeight; nY += 2)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX)
|
||
{
|
||
// compute index of pixel to process
|
||
nIndex2 = 4*(nX + nY*m_nWidth);
|
||
|
||
// check for pixel mask
|
||
if (m_bMask && m_pPixels[nIndex2 + 3] != 0)
|
||
continue;
|
||
|
||
// compute index of pixel in previous and next lines
|
||
nIndex1 = nIndex2 - 4*m_nWidth;
|
||
nIndex3 = nIndex2 + 4*m_nWidth;
|
||
|
||
// check for interpolation type
|
||
if (nY == 0)
|
||
{
|
||
m_pPixels[nIndex2 + 2] = (BYTE)(dAlpha1*m_pPixels[nIndex3 + 2] + dAlpha2*m_pPixels[nIndex2 + 2]);
|
||
m_pPixels[nIndex2 + 1] = (BYTE)(dAlpha1*m_pPixels[nIndex3 + 1] + dAlpha2*m_pPixels[nIndex2 + 1]);
|
||
m_pPixels[nIndex2 + 0] = (BYTE)(dAlpha1*m_pPixels[nIndex3 + 0] + dAlpha2*m_pPixels[nIndex2 + 0]);
|
||
}
|
||
else if (nY == m_nHeight - 1)
|
||
{
|
||
m_pPixels[nIndex2 + 2] = (BYTE)(dAlpha1*m_pPixels[nIndex1 + 2] + dAlpha2*m_pPixels[nIndex2 + 2]);
|
||
m_pPixels[nIndex2 + 1] = (BYTE)(dAlpha1*m_pPixels[nIndex1 + 1] + dAlpha2*m_pPixels[nIndex2 + 1]);
|
||
m_pPixels[nIndex2 + 0] = (BYTE)(dAlpha1*m_pPixels[nIndex1 + 0] + dAlpha2*m_pPixels[nIndex2 + 0]);
|
||
}
|
||
else
|
||
{
|
||
if (Interpolate == VARIANT_FALSE)
|
||
{
|
||
m_pPixels[nIndex2 + 2] = (BYTE)(dAlpha1*m_pPixels[nIndex3 + 2] + dAlpha2*m_pPixels[nIndex2 + 2]);
|
||
m_pPixels[nIndex2 + 1] = (BYTE)(dAlpha1*m_pPixels[nIndex3 + 1] + dAlpha2*m_pPixels[nIndex2 + 1]);
|
||
m_pPixels[nIndex2 + 0] = (BYTE)(dAlpha1*m_pPixels[nIndex3 + 0] + dAlpha2*m_pPixels[nIndex2 + 0]);
|
||
}
|
||
else
|
||
{
|
||
m_pPixels[nIndex2 + 2] = (BYTE)(dAlpha3*m_pPixels[nIndex1 + 2] + dAlpha3*m_pPixels[nIndex3 + 2] + dAlpha2*m_pPixels[nIndex2 + 2]);
|
||
m_pPixels[nIndex2 + 1] = (BYTE)(dAlpha3*m_pPixels[nIndex1 + 1] + dAlpha3*m_pPixels[nIndex3 + 1] + dAlpha2*m_pPixels[nIndex2 + 1]);
|
||
m_pPixels[nIndex2 + 0] = (BYTE)(dAlpha3*m_pPixels[nIndex1 + 0] + dAlpha3*m_pPixels[nIndex3 + 0] + dAlpha2*m_pPixels[nIndex2 + 0]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#else
|
||
IPPEffectDeinterlace(m_pPixels, m_nWidth, m_nHeight, Frame, (VARIANT_TRUE == Even), (VARIANT_TRUE == Interpolate));
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::EffectMedian(double Frame, long MedianType)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
IPPEffectMedian(m_pPixels,m_nWidth,m_nHeight,Frame,MedianType);
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
STDMETHODIMP ImageTransform3::EffectChromoKey(double Frame, long Color1, long Color2)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
Color col;
|
||
float r, g, b;
|
||
float fLightness, fSaturation;
|
||
float fHue1;
|
||
col.SetValue(Color1);
|
||
r = (float)col.GetB();
|
||
r /= 255.0f;
|
||
g = (float)col.GetG();
|
||
g /= 255.0f;
|
||
b = (float)col.GetR();
|
||
b /= 255.0f;
|
||
|
||
ConvertToHls(r, g, b, fHue1, fLightness, fSaturation);
|
||
|
||
float fHue2;
|
||
col.SetValue(Color2);
|
||
r = (float)col.GetB();
|
||
r /= 255.0f;
|
||
g = (float)col.GetG();
|
||
g /= 255.0f;
|
||
b = (float)col.GetR();
|
||
b /= 255.0f;
|
||
|
||
ConvertToHls(r, g, b, fHue2, fLightness, fSaturation);
|
||
|
||
int nHComponent1 = fHue1*255.0f/360.0f;
|
||
int nHComponent2 = fHue2*255.0f/360.0f;
|
||
|
||
CChromoKey oChromo;
|
||
oChromo.SetImage(m_pPixels, m_nWidth, m_nHeight);
|
||
oChromo.DoChromoKey(Frame, nHComponent1, m_nAdvancedChromaThreshold1, nHComponent2, m_nAdvancedChromaThreshold2);
|
||
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
STDMETHODIMP ImageTransform3::EffectChromoKey2(double Frame, long color, long Threshold)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
Color col;
|
||
float r, g, b;
|
||
float fHue, fLightness, fSaturation;
|
||
float koef1 = 0, koef2 = 0;
|
||
col.SetValue(color);
|
||
r = (float)col.GetB();
|
||
r /= 255.0f;
|
||
g = (float)col.GetG();
|
||
g /= 255.0f;
|
||
b = (float)col.GetR();
|
||
b /= 255.0f;
|
||
|
||
ConvertToHls(r, g, b, fHue, fLightness, fSaturation);
|
||
|
||
if(Threshold > 100)
|
||
Threshold = 100;
|
||
if(Threshold < 0)
|
||
Threshold = 0;
|
||
|
||
int nHComponent = fHue*255.0f/360.0f;
|
||
CChromoKey oChromo;
|
||
oChromo.SetImage(m_pPixels, m_nWidth, m_nHeight);
|
||
oChromo.DoChromoKey(Frame, nHComponent, Threshold);
|
||
|
||
ApplyRegister();
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformFlip(double Frame, VARIANT_BOOL Vertical)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
#ifndef NOT_OPTIM // TODO: disabled optimization due to access violation
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nDestX, nDestY, nDestIndex;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
// flip image
|
||
for (nY = 0, nIndex = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_bMask && m_pBackup[nIndex + 3] != 0)
|
||
continue;
|
||
|
||
// compute random swap pixel
|
||
if (Vertical == VARIANT_TRUE)
|
||
{
|
||
nDestX = nX;
|
||
nDestY = (int)((1.0 - Frame)*nY + Frame*(m_nHeight - 1 - nY));
|
||
}
|
||
else
|
||
{
|
||
nDestX = (int)((1.0 - Frame)*nX + Frame*(m_nWidth - 1 - nX));
|
||
nDestY = nY;
|
||
}
|
||
|
||
// compute swap pixel index
|
||
nDestIndex = 4*(nDestX + nDestY*m_nWidth);
|
||
|
||
// swap pixels
|
||
m_pPixels[nDestIndex + 2] = m_pBackup[nIndex + 2];
|
||
m_pPixels[nDestIndex + 1] = m_pBackup[nIndex + 1];
|
||
m_pPixels[nDestIndex + 0] = m_pBackup[nIndex + 0];
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
if (fabs(Frame) < 0.001)
|
||
return S_OK;
|
||
|
||
Ipp8u* pDst = (Ipp8u*)m_pPixels;
|
||
|
||
if (fabs(Frame) > 0.999)
|
||
{
|
||
if (Vertical == VARIANT_TRUE)
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, m_IppiRoiSize, ippAxsHorizontal);
|
||
else
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, m_IppiRoiSize, ippAxsVertical);
|
||
return S_OK;
|
||
}
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
Ipp8u* pSrc = (Ipp8u*)m_pBackup;
|
||
IppiRect srcRoi = {0, 0, m_IppiRoiSize.width , m_IppiRoiSize.height};
|
||
double dResizeX = 1, dResizeY = 1;
|
||
double dfCenterX = 0.5*m_nWidth;
|
||
double dfCenterY = 0.5*m_nHeight;
|
||
|
||
// apply transform
|
||
if (Vertical == VARIANT_TRUE)
|
||
{
|
||
dResizeY = 1 - 2 * ((Frame < 0.5) ? Frame : (1 - Frame));
|
||
ippiResizeCenter_8u_AC4R(pSrc, m_IppiRoiSize, m_nIppiStep , srcRoi, pDst, m_nIppiStep, m_IppiRoiSize, dResizeX, dResizeY, dfCenterX, dfCenterY, IPPI_INTER_NN);
|
||
if (Frame > 0.5)
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, m_IppiRoiSize, ippAxsHorizontal);
|
||
}
|
||
else
|
||
{
|
||
dResizeX = 1 - 2 * ((Frame < 0.5) ? Frame : (1 - Frame));
|
||
ippiResizeCenter_8u_AC4R(pSrc, m_IppiRoiSize, m_nIppiStep , srcRoi, pDst, m_nIppiStep, m_IppiRoiSize, dResizeX, dResizeY, dfCenterX, dfCenterY, IPPI_INTER_NN);
|
||
if ( Frame > 0.5 )
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, m_IppiRoiSize, ippAxsVertical);
|
||
}
|
||
|
||
// restore masked pixels
|
||
if (m_bMask)
|
||
{
|
||
for ( int nIndex = 0; nIndex < m_nSize; nIndex += 4)
|
||
{
|
||
// check for pixel mask
|
||
if (m_pBackup[nIndex + 3])
|
||
{
|
||
// swap pixels
|
||
m_pPixels[nIndex + 2] = m_pBackup[nIndex + 2];
|
||
m_pPixels[nIndex + 1] = m_pBackup[nIndex + 1];
|
||
m_pPixels[nIndex + 0] = m_pBackup[nIndex + 0];
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformPerspective(double Frame, VARIANT_BOOL Vertical, double Angle)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Angle = Frame*min(max(-90, Angle), 90);
|
||
|
||
// check for simpliest case
|
||
if (fabs(Angle) < 0.001)
|
||
return S_OK;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
#ifdef NOT_OPTIM
|
||
|
||
// check for transform center line (vertical or horizontal)
|
||
if (Vertical == VARIANT_TRUE)
|
||
{
|
||
// variables
|
||
int nY1, nY2, nX1, nX2;
|
||
int nRY1, nRY2;
|
||
|
||
// compute resulting x coordinates
|
||
nX1 = (int)(0.5*m_nWidth*fabs(Angle)/90);
|
||
nX2 = m_nWidth - 1 - nX1;
|
||
|
||
// compute resulting y coordinates
|
||
nY1 = (int)(0.25*m_nHeight*fabs(Angle)/90);
|
||
nY2 = m_nHeight - 1 - nY1;
|
||
|
||
// clamp to image ranges
|
||
nX1 = min(max(nX1, 0), m_nWidth - 2);
|
||
nX2 = min(max(nX2, nX1 + 1), m_nWidth - 1);
|
||
nY1 = min(max(nY1, 0), m_nHeight - 2);
|
||
nY2 = min(max(nY2, nY1 + 1), m_nHeight - 1);
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nResultX, nResultY, nResultIndex;
|
||
|
||
// transform image
|
||
for (nX = 0; nX < m_nWidth; ++nX)
|
||
{
|
||
// compute resulting x coordinate
|
||
nResultX = nX1 + (nX2 - nX1)*nX/(m_nWidth - 1);
|
||
|
||
// compute y coordinates ranges
|
||
if (Angle < 0)
|
||
{
|
||
nRY1 = nY1*nX/(m_nWidth - 1);
|
||
nRY2 = m_nHeight - 1 - nRY1;
|
||
}
|
||
else
|
||
{
|
||
nRY1 = nY1*(m_nWidth - 1 - nX)/(m_nWidth - 1);
|
||
nRY2 = m_nHeight - 1 - nRY1;
|
||
}
|
||
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
// compute resulting y coordinate
|
||
nResultY = nRY1 + (nRY2 - nRY1)*nY/(m_nHeight - 1);
|
||
|
||
// compute source pixel index
|
||
nIndex = 4*(nX + nY*m_nWidth);
|
||
|
||
// compute resulting pixel index
|
||
nResultIndex = 4*(nResultX + nResultY*m_nWidth);
|
||
|
||
// copy pixel info
|
||
m_pPixels[nResultIndex + 0] = m_pBackup[nIndex + 0];
|
||
m_pPixels[nResultIndex + 1] = m_pBackup[nIndex + 1];
|
||
m_pPixels[nResultIndex + 2] = m_pBackup[nIndex + 2];
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// variables
|
||
int nY1, nY2, nX1, nX2;
|
||
int nRX1, nRX2;
|
||
|
||
// compute resulting x coordinates
|
||
nX1 = (int)(0.25*m_nWidth*fabs(Angle)/90);
|
||
nX2 = m_nWidth - 1 - nX1;
|
||
|
||
// compute resulting y coordinates
|
||
nY1 = (int)(0.5*m_nHeight*fabs(Angle)/90);
|
||
nY2 = m_nHeight - 1 - nY1;
|
||
|
||
// clamp to image ranges
|
||
nX1 = min(max(nX1, 0), m_nWidth - 2);
|
||
nX2 = min(max(nX2, nX1 + 1), m_nWidth - 1);
|
||
nY1 = min(max(nY1, 0), m_nHeight - 2);
|
||
nY2 = min(max(nY2, nY1 + 1), m_nHeight - 1);
|
||
|
||
// variables
|
||
int nX, nY, nIndex = 0;
|
||
int nResultX, nResultY, nResultIndex;
|
||
|
||
// transform image
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
// compute resulting y coordinate
|
||
nResultY = nY1 + (nY2 - nY1)*nY/(m_nHeight - 1);
|
||
|
||
// compute x coordinates ranges
|
||
if (Angle < 0)
|
||
{
|
||
nRX1 = nX1*nY/(m_nHeight - 1);
|
||
nRX2 = m_nWidth - 1 - nRX1;
|
||
}
|
||
else
|
||
{
|
||
nRX1 = nX1*(m_nHeight - 1 - nY)/(m_nHeight - 1);
|
||
nRX2 = m_nWidth - 1 - nRX1;
|
||
}
|
||
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// compute resulting x coordinate
|
||
nResultX = nRX1 + (nRX2 - nRX1)*nX/(m_nWidth - 1);
|
||
|
||
// compute resulting pixel index
|
||
nResultIndex = 4*(nResultX + nResultY*m_nWidth);
|
||
|
||
// copy pixel info
|
||
m_pPixels[nResultIndex + 0] = m_pBackup[nIndex + 0];
|
||
m_pPixels[nResultIndex + 1] = m_pBackup[nIndex + 1];
|
||
m_pPixels[nResultIndex + 2] = m_pBackup[nIndex + 2];
|
||
}
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
// variables
|
||
int nY1, nY2, nX1, nX2;
|
||
Ipp8u* pSrc = (Ipp8u*)m_pBackup;
|
||
Ipp8u* pDst = (Ipp8u*)m_pPixels;
|
||
IppiRect srcRoi = {0, 0, m_IppiRoiSize.width, m_IppiRoiSize.height};
|
||
double quadSrc[4][2], quadDst[4][2];
|
||
quadSrc[0][0] = quadSrc[3][0] = 0;
|
||
quadSrc[1][0] = quadSrc[2][0] = m_nWidth - 1;
|
||
quadSrc[0][1] = quadSrc[1][1] = 0;
|
||
quadSrc[2][1] = quadSrc[3][1] = m_nHeight - 1;
|
||
|
||
// check for transform center line (vertical or horizontal)
|
||
if (Vertical == VARIANT_TRUE)
|
||
{
|
||
// compute resulting x coordinates
|
||
nX1 = (int)(0.5*m_nWidth*fabs(Angle)/90);
|
||
nX2 = m_nWidth - 1 - nX1;
|
||
|
||
// compute resulting y coordinates
|
||
nY1 = (int)(0.25*m_nHeight*fabs(Angle)/90);
|
||
nY2 = m_nHeight - 1 - nY1;
|
||
|
||
quadDst[0][0] = quadDst[3][0] = nX1;
|
||
quadDst[1][0] = quadDst[2][0] = nX2;
|
||
|
||
if (Angle < 0)
|
||
{
|
||
quadDst[0][1] = 0;
|
||
quadDst[3][1] = m_nHeight - 1;
|
||
quadDst[1][1] = nY1;
|
||
quadDst[2][1] = nY2;
|
||
}
|
||
else
|
||
{
|
||
quadDst[0][1] = nY1;
|
||
quadDst[3][1] = nY2;
|
||
quadDst[1][1] = 0;
|
||
quadDst[2][1] = m_nHeight - 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// compute resulting x coordinates
|
||
nX1 = (int)(0.25*m_nWidth*fabs(Angle)/90);
|
||
nX2 = m_nWidth - 1 - nX1;
|
||
|
||
// compute resulting y coordinates
|
||
nY1 = (int)(0.5*m_nHeight*fabs(Angle)/90);
|
||
nY2 = m_nHeight - 1 - nY1;
|
||
|
||
quadDst[0][1] = quadDst[1][1] = nY1;
|
||
quadDst[2][1] = quadDst[3][1] = nY2;
|
||
|
||
if (Angle > 0)
|
||
{
|
||
quadDst[0][0] = nX1;
|
||
quadDst[1][0] = nX2;
|
||
quadDst[2][0] = m_nWidth - 1;
|
||
quadDst[3][0] = 0;
|
||
}
|
||
else
|
||
{
|
||
quadDst[0][0] = 0;
|
||
quadDst[1][0] = m_nWidth - 1;
|
||
quadDst[2][0] = nX2;
|
||
quadDst[3][0] = nX1;
|
||
}
|
||
}
|
||
|
||
// apply perspective correction
|
||
ippiWarpPerspectiveQuad_8u_AC4R(pSrc, m_IppiRoiSize, m_nIppiStep, srcRoi, quadSrc, pDst, m_nIppiStep, srcRoi, quadDst, IPPI_INTER_NN);
|
||
|
||
#endif
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformSkew(double Frame, VARIANT_BOOL Vertical, double Angle)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Angle = Frame*min(max(-90, Angle), 90);
|
||
|
||
// check for simpliest case
|
||
if (fabs(Angle) < 0.001)
|
||
return S_OK;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
#ifdef NOT_OPTIM
|
||
|
||
// check for transform direction
|
||
if (Vertical == VARIANT_TRUE)
|
||
{
|
||
// variables
|
||
int nY1, nY2, nX1, nX2;
|
||
int nRY1, nRY2;
|
||
|
||
// compute resulting x coordinates
|
||
nX1 = (int)(0.5*m_nWidth*fabs(Angle)/90);
|
||
nX2 = m_nWidth - 1 - nX1;
|
||
|
||
// compute resulting y coordinates
|
||
nY1 = (int)(0.5*m_nHeight*fabs(Angle)/90);
|
||
nY2 = m_nHeight - 1 - nY1;
|
||
|
||
// clamp to image ranges
|
||
nX1 = min(max(nX1, 0), m_nWidth - 2);
|
||
nX2 = min(max(nX2, nX1 + 1), m_nWidth - 1);
|
||
nY1 = min(max(nY1, 0), m_nHeight - 2);
|
||
nY2 = min(max(nY2, nY1 + 1), m_nHeight - 1);
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nResultX, nResultY, nResultIndex;
|
||
|
||
// transform image
|
||
for (nX = 0; nX < m_nWidth; ++nX)
|
||
{
|
||
// compute resulting x coordinate
|
||
nResultX = nX1 + (nX2 - nX1)*nX/(m_nWidth - 1);
|
||
|
||
// compute x coordinates ranges
|
||
if (Angle < 0)
|
||
{
|
||
nRY1 = nY1*nX/(m_nWidth - 1);
|
||
nRY2 = m_nHeight - 1 - nY1*(m_nWidth - 1 - nX)/(m_nWidth - 1);
|
||
}
|
||
else
|
||
{
|
||
nRY1 = nY1*(m_nWidth - 1 - nX)/(m_nWidth - 1);
|
||
nRY2 = m_nHeight - 1 - nY1*nX/(m_nWidth - 1);
|
||
}
|
||
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
// compute resulting y coordinate
|
||
nResultY = nRY1 + (nRY2 - nRY1)*nY/(m_nHeight - 1);
|
||
|
||
// compute source pixel index
|
||
nIndex = 4*(nX + nY*m_nWidth);
|
||
|
||
// compute resulting pixel index
|
||
nResultIndex = 4*(nResultX + nResultY*m_nWidth);
|
||
|
||
// copy pixel info
|
||
m_pPixels[nResultIndex + 0] = m_pBackup[nIndex + 0];
|
||
m_pPixels[nResultIndex + 1] = m_pBackup[nIndex + 1];
|
||
m_pPixels[nResultIndex + 2] = m_pBackup[nIndex + 2];
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// variables
|
||
int nY1, nY2, nX1, nX2;
|
||
int nRX1, nRX2;
|
||
|
||
// compute resulting x coordinates
|
||
nX1 = (int)(0.5*m_nWidth*fabs(Angle)/90);
|
||
nX2 = m_nWidth - 1 - nX1;
|
||
|
||
// compute resulting y coordinates
|
||
nY1 = (int)(0.5*m_nHeight*fabs(Angle)/90);
|
||
nY2 = m_nHeight - 1 - nY1;
|
||
|
||
// clamp to image ranges
|
||
nX1 = min(max(nX1, 0), m_nWidth - 2);
|
||
nX2 = min(max(nX2, nX1 + 1), m_nWidth - 1);
|
||
nY1 = min(max(nY1, 0), m_nHeight - 2);
|
||
nY2 = min(max(nY2, nY1 + 1), m_nHeight - 1);
|
||
|
||
// variables
|
||
int nX, nY, nIndex = 0;
|
||
int nResultX, nResultY, nResultIndex;
|
||
|
||
// transform image
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
// compute resulting y coordinate
|
||
nResultY = nY1 + (nY2 - nY1)*nY/(m_nHeight - 1);
|
||
|
||
// compute x coordinates ranges
|
||
if (Angle < 0)
|
||
{
|
||
nRX1 = nX1*nY/(m_nHeight - 1);
|
||
nRX2 = m_nWidth - 1 - nX1*(m_nHeight - 1 - nY)/(m_nHeight - 1);
|
||
}
|
||
else
|
||
{
|
||
nRX1 = nX1*(m_nHeight - 1 - nY)/(m_nHeight - 1);
|
||
nRX2 = m_nWidth - 1 - nX1*nY/(m_nHeight - 1);
|
||
}
|
||
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// compute resulting x coordinate
|
||
nResultX = nRX1 + (nRX2 - nRX1)*nX/(m_nWidth - 1);
|
||
|
||
// compute resulting pixel index
|
||
nResultIndex = 4*(nResultX + nResultY*m_nWidth);
|
||
|
||
// copy pixel info
|
||
m_pPixels[nResultIndex + 0] = m_pBackup[nIndex + 0];
|
||
m_pPixels[nResultIndex + 1] = m_pBackup[nIndex + 1];
|
||
m_pPixels[nResultIndex + 2] = m_pBackup[nIndex + 2];
|
||
}
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
// variables
|
||
int nY1, nY2, nX1, nX2;
|
||
Ipp8u* pSrc = (Ipp8u*)m_pBackup;
|
||
Ipp8u* pDst = (Ipp8u*)m_pPixels;
|
||
IppiRect srcRoi = {0, 0, m_IppiRoiSize.width, m_IppiRoiSize.height};
|
||
double quadSrc[4][2], quadDst[4][2];
|
||
quadSrc[0][0] = quadSrc[3][0] = 0;
|
||
quadSrc[1][0] = quadSrc[2][0] = m_nWidth - 1;
|
||
quadSrc[0][1] = quadSrc[1][1] = 0;
|
||
quadSrc[2][1] = quadSrc[3][1] = m_nHeight - 1;
|
||
|
||
// compute resulting x coordinates
|
||
nX1 = (int)(0.5*m_nWidth*fabs(Angle)/90);
|
||
nX2 = m_nWidth - 1 - nX1;
|
||
|
||
// compute resulting y coordinates
|
||
nY1 = (int)(0.5*m_nHeight*fabs(Angle)/90);
|
||
nY2 = m_nHeight - 1 - nY1;
|
||
|
||
// check for transform direction
|
||
if (Vertical == VARIANT_TRUE)
|
||
{
|
||
quadDst[0][0] = quadDst[3][0] = nX1;
|
||
quadDst[1][0] = quadDst[2][0] = nX2;
|
||
|
||
if (Angle > 0)
|
||
{
|
||
quadDst[0][1] = nY1;
|
||
quadDst[1][1] = 0;
|
||
quadDst[2][1] = nY2;
|
||
quadDst[3][1] = m_nHeight - 1;
|
||
}
|
||
else
|
||
{
|
||
quadDst[0][1] = 0;
|
||
quadDst[1][1] = nY1;
|
||
quadDst[2][1] = m_nHeight - 1;
|
||
quadDst[3][1] = nY2;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
quadDst[0][1] = quadDst[1][1] = nY1;
|
||
quadDst[2][1] = quadDst[3][1] = nY2;
|
||
|
||
if (Angle > 0)
|
||
{
|
||
quadDst[0][0] = nX1;
|
||
quadDst[1][0] = m_nWidth - 1;
|
||
quadDst[2][0] = nX2;
|
||
quadDst[3][0] = 0;
|
||
}
|
||
else
|
||
{
|
||
quadDst[0][0] = 0;
|
||
quadDst[1][0] = nX2;
|
||
quadDst[2][0] = m_nWidth - 1;
|
||
quadDst[3][0] = nX1;
|
||
}
|
||
}
|
||
|
||
// apply skew correction
|
||
ippiWarpAffineQuad_8u_AC4R(pSrc, m_IppiRoiSize, m_nIppiStep, srcRoi, quadSrc, pDst, m_nIppiStep, srcRoi, quadDst, IPPI_INTER_NN);
|
||
|
||
#endif
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformShift(double Frame, long X, long Y)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
X = (int)(X*Frame);
|
||
Y = (int)(-Y*Frame);
|
||
|
||
// check for simpliest case
|
||
if (X == 0 && Y == 0)
|
||
return S_OK;
|
||
if (X >= m_nWidth || Y >= m_nHeight || X + m_nWidth - 1 < 0 || Y + m_nHeight - 1 < 0)
|
||
{
|
||
ClearImage(m_pPixels, m_nSize);
|
||
return S_OK;
|
||
}
|
||
|
||
#ifdef NOT_OPTIM
|
||
|
||
// compose background color
|
||
BYTE ColorR = GetRValue(m_nBackColor);
|
||
BYTE ColorG = GetGValue(m_nBackColor);
|
||
BYTE ColorB = GetBValue(m_nBackColor);
|
||
BYTE ColorA = GetAValue(m_nBackColor);
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
int nSourceX, nSourceY, nSourceIndex;
|
||
|
||
// offset image
|
||
if (X >= 0 && Y >= 0)
|
||
{
|
||
for (nY = m_nHeight - 1; nY >= 0; --nY)
|
||
{
|
||
// compute y coodrinate
|
||
nSourceY = nY - Y;
|
||
|
||
for (nX = m_nWidth - 1; nX >= 0; --nX)
|
||
{
|
||
// compute x coordinate
|
||
nSourceX = nX - X;
|
||
|
||
// comute current pixel index
|
||
nIndex = 4*(nX + nY*m_nWidth);
|
||
|
||
// clear pixel
|
||
m_pPixels[nIndex + 3] = ColorA;
|
||
m_pPixels[nIndex + 2] = ColorR;
|
||
m_pPixels[nIndex + 1] = ColorG;
|
||
m_pPixels[nIndex + 0] = ColorB;
|
||
|
||
// check for valid pixel index
|
||
if (nSourceX < 0 || nSourceX >= m_nWidth || nSourceY < 0 || nSourceY >= m_nHeight)
|
||
continue;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// copy pixel
|
||
m_pPixels[nIndex + 2] = m_pPixels[nSourceIndex + 2];
|
||
m_pPixels[nIndex + 1] = m_pPixels[nSourceIndex + 1];
|
||
m_pPixels[nIndex + 0] = m_pPixels[nSourceIndex + 0];
|
||
}
|
||
}
|
||
}
|
||
else if (X < 0 && Y >= 0)
|
||
{
|
||
for (nY = m_nHeight - 1; nY >= 0; --nY)
|
||
{
|
||
// compute y coodrinate
|
||
nSourceY = nY - Y;
|
||
|
||
for (nX = 0; nX < m_nWidth; ++nX)
|
||
{
|
||
// compute x coordinate
|
||
nSourceX = nX - X;
|
||
|
||
// comute current pixel index
|
||
nIndex = 4*(nX + nY*m_nWidth);
|
||
|
||
// clear pixel
|
||
m_pPixels[nIndex + 2] = ColorR;
|
||
m_pPixels[nIndex + 1] = ColorG;
|
||
m_pPixels[nIndex + 0] = ColorB;
|
||
|
||
// check for valid pixel index
|
||
if (nSourceX < 0 || nSourceX >= m_nWidth || nSourceY < 0 || nSourceY >= m_nHeight)
|
||
continue;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// copy pixel
|
||
m_pPixels[nIndex + 2] = m_pPixels[nSourceIndex + 2];
|
||
m_pPixels[nIndex + 1] = m_pPixels[nSourceIndex + 1];
|
||
m_pPixels[nIndex + 0] = m_pPixels[nSourceIndex + 0];
|
||
}
|
||
}
|
||
}
|
||
if (X >= 0 && Y < 0)
|
||
{
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
// compute y coodrinate
|
||
nSourceY = nY - Y;
|
||
|
||
for (nX = m_nWidth - 1; nX >= 0; --nX)
|
||
{
|
||
// compute x coordinate
|
||
nSourceX = nX - X;
|
||
|
||
// comute current pixel index
|
||
nIndex = 4*(nX + nY*m_nWidth);
|
||
|
||
// clear pixel
|
||
m_pPixels[nIndex + 2] = ColorR;
|
||
m_pPixels[nIndex + 1] = ColorG;
|
||
m_pPixels[nIndex + 0] = ColorB;
|
||
|
||
// check for valid pixel index
|
||
if (nSourceX < 0 || nSourceX >= m_nWidth || nSourceY < 0 || nSourceY >= m_nHeight)
|
||
continue;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// copy pixel
|
||
m_pPixels[nIndex + 2] = m_pPixels[nSourceIndex + 2];
|
||
m_pPixels[nIndex + 1] = m_pPixels[nSourceIndex + 1];
|
||
m_pPixels[nIndex + 0] = m_pPixels[nSourceIndex + 0];
|
||
}
|
||
}
|
||
}
|
||
else if (X < 0 && Y < 0)
|
||
{
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
// compute y coodrinate
|
||
nSourceY = nY - Y;
|
||
|
||
for (nX = 0; nX < m_nWidth; ++nX)
|
||
{
|
||
// compute x coordinate
|
||
nSourceX = nX - X;
|
||
|
||
// comute current pixel index
|
||
nIndex = 4*(nX + nY*m_nWidth);
|
||
|
||
// clear pixel
|
||
m_pPixels[nIndex + 2] = ColorR;
|
||
m_pPixels[nIndex + 1] = ColorG;
|
||
m_pPixels[nIndex + 0] = ColorB;
|
||
|
||
// check for valid pixel index
|
||
if (nSourceX < 0 || nSourceX >= m_nWidth || nSourceY < 0 || nSourceY >= m_nHeight)
|
||
continue;
|
||
|
||
// compute source pixel index
|
||
nSourceIndex = 4*(nSourceX + nSourceY*m_nWidth);
|
||
|
||
// copy pixel
|
||
m_pPixels[nIndex + 2] = m_pPixels[nSourceIndex + 2];
|
||
m_pPixels[nIndex + 1] = m_pPixels[nSourceIndex + 1];
|
||
m_pPixels[nIndex + 0] = m_pPixels[nSourceIndex + 0];
|
||
}
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
Ipp8u* pSrc = (Ipp8u*)m_pBackup;
|
||
Ipp8u* pDst = (Ipp8u*)m_pPixels;
|
||
IppiSize dstRoi = {m_IppiRoiSize.width - abs(X), m_IppiRoiSize.height - abs(Y)};
|
||
|
||
if (X >= 0 && Y >= 0)
|
||
ippiCopy_8u_AC4R(pSrc, m_nIppiStep, pDst + m_nIppiStep*Y + X*4, m_nIppiStep, dstRoi);
|
||
else if (X < 0 && Y >= 0)
|
||
ippiCopy_8u_AC4R(pSrc + abs(X)*4, m_nIppiStep, pDst + m_nIppiStep*Y, m_nIppiStep, dstRoi);
|
||
else if (X >= 0 && Y < 0)
|
||
ippiCopy_8u_AC4R(pSrc + m_nIppiStep*abs(Y), m_nIppiStep, pDst + abs(X)*4, m_nIppiStep, dstRoi);
|
||
else if (X < 0 && Y < 0)
|
||
ippiCopy_8u_AC4R(pSrc + m_nIppiStep*abs(Y) + abs(X)*4, m_nIppiStep, pDst, m_nIppiStep, dstRoi);
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformRotate(double Frame, double Angle)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Angle = Frame*min(max(-360, Angle), 360);
|
||
|
||
// check for simpliest case
|
||
if (fabs(Angle) < 0.001 || Angle > 359.999 || Angle < -359.999)
|
||
return S_OK;
|
||
|
||
#ifdef NOT_OPTIM
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
// compute rotational angle in radians
|
||
double dNormalAngle = 3.14159265359*Frame*Angle/180.0;
|
||
|
||
// variables
|
||
double dCenterX = 0.5*m_nWidth;
|
||
double dCenterY = 0.5*m_nHeight;
|
||
double dOldAngle, dOldRadius;
|
||
double dLTx, dLTy, dRTx, dRTy, dLBx, dLBy, dRBx, dRBy;
|
||
|
||
// compute size of the image after rotation
|
||
GetRadiusAndAngle(0, 0, dCenterX, dCenterY, dOldRadius, dOldAngle);
|
||
dLTx = dCenterX + dOldRadius*cos(dNormalAngle + dOldAngle);
|
||
dLTy = dCenterY + dOldRadius*sin(dNormalAngle + dOldAngle);
|
||
GetRadiusAndAngle(m_nWidth - 1, 0, dCenterX, dCenterY, dOldRadius, dOldAngle);
|
||
dRTx = dCenterX + dOldRadius*cos(dNormalAngle + dOldAngle);
|
||
dRTy = dCenterY + dOldRadius*sin(dNormalAngle + dOldAngle);
|
||
GetRadiusAndAngle(m_nWidth - 1, m_nHeight - 1, dCenterX, dCenterY, dOldRadius, dOldAngle);
|
||
dRBx = dCenterX + dOldRadius*cos(dNormalAngle + dOldAngle);
|
||
dRBy = dCenterY + dOldRadius*sin(dNormalAngle + dOldAngle);
|
||
GetRadiusAndAngle(0, m_nHeight - 1, dCenterX, dCenterY, dOldRadius, dOldAngle);
|
||
dLBx = dCenterX + dOldRadius*cos(dNormalAngle + dOldAngle);
|
||
dLBy = dCenterY + dOldRadius*sin(dNormalAngle + dOldAngle);
|
||
|
||
double dLeft = min(min(dLTx, dRTx), min(dLBx, dRBx));
|
||
double dRight = max(max(dLTx, dRTx), max(dLBx, dRBx));
|
||
double dTop = min(min(dLTy, dRTy), min(dLBy, dRBy));
|
||
double dBottom = max(max(dLTy, dRTy), max(dLBy, dRBy));
|
||
|
||
int nNewWidth = (int)(dRight - dLeft);
|
||
int nNewHeight = (int)(dBottom - dTop);
|
||
|
||
// compute normalization koefficient
|
||
double dNormalize = max((double)nNewWidth/m_nWidth, (double)nNewHeight/m_nHeight);
|
||
|
||
// variables
|
||
int nX, nY, nIndex = 0;
|
||
double dSourceX, dSourceY;
|
||
|
||
// compose background color
|
||
BYTE ColorR = GetRValue(m_nBackColor);
|
||
BYTE ColorG = GetGValue(m_nBackColor);
|
||
BYTE ColorB = GetBValue(m_nBackColor);
|
||
BYTE ColorA = GetAValue(m_nBackColor);
|
||
|
||
// process image
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// compute pixel angle and radius
|
||
GetRadiusAndAngle(nX, nY, dCenterX, dCenterY, dOldRadius, dOldAngle);
|
||
|
||
// compute old pixel angle and radius
|
||
dSourceX = dCenterX + dNormalize*dOldRadius*cos(dNormalAngle + dOldAngle);
|
||
dSourceY = dCenterY + dNormalize*dOldRadius*sin(dNormalAngle + dOldAngle);
|
||
|
||
// compute pixel color
|
||
m_pPixels[nIndex + 0] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 0, 4, ColorB);
|
||
m_pPixels[nIndex + 1] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 1, 4, ColorG);
|
||
m_pPixels[nIndex + 2] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 2, 4, ColorR);
|
||
m_pPixels[nIndex + 3] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 3, 4, ColorA);
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
Ipp8u* pDst = (Ipp8u*)m_pPixels;
|
||
|
||
// check whether we flip image on 180 degrees
|
||
if (fabs(fabs(Angle) - 180) < 0.001)
|
||
{
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, m_IppiRoiSize, ippAxsBoth);
|
||
return S_OK;
|
||
}
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
// variables
|
||
Ipp8u* pSrc = (Ipp8u*)m_pBackup;
|
||
IppiRect srcRoi = {0, 0, m_IppiRoiSize.width , m_IppiRoiSize.height};
|
||
double dfCenterX = 0.5 * m_nWidth;
|
||
double dfCenterY = 0.5 * m_nHeight;
|
||
double quad[4][2];
|
||
|
||
ippiGetRotateQuad(srcRoi, quad, Angle, 0, 0);
|
||
|
||
double dLeft = min(min(quad[0][0], quad[1][0]), min(quad[2][0], quad[3][0]));
|
||
double dRight = max(max(quad[0][0], quad[1][0]), max(quad[2][0], quad[3][0]));
|
||
double dTop = min(min(quad[0][1], quad[1][1]), min(quad[2][1], quad[3][1]));
|
||
double dBottom = max(max(quad[0][1], quad[1][1]), max(quad[2][1], quad[3][1]));
|
||
|
||
double dResize = 1.0/max((int)(dRight - dLeft)/(double)m_nWidth, (int)(dBottom - dTop)/(double)m_nHeight);
|
||
|
||
int nStep = 4*m_nWidth;
|
||
Ipp8u* pTmp = new Ipp8u[4*m_nWidth*m_nHeight];
|
||
|
||
if (pTmp)
|
||
{
|
||
ClearImage((BYTE*)pTmp, 4*m_nWidth*m_nHeight);
|
||
|
||
ippiResizeCenter_8u_AC4R(pSrc, m_IppiRoiSize, m_nIppiStep, srcRoi, pTmp, nStep, m_IppiRoiSize, dResize, dResize, dfCenterX, dfCenterY, IPPI_INTER_LINEAR);
|
||
ippiRotateCenter_8u_AC4R(pTmp, m_IppiRoiSize, nStep, srcRoi, pDst, m_nIppiStep, srcRoi, Angle, dfCenterX, dfCenterY, IPPI_INTER_LINEAR);
|
||
|
||
delete[] pTmp;
|
||
}
|
||
|
||
#endif
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformResample(double Frame, long Times)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Times = min(max(1, Times), max(1, min(m_nWidth, m_nHeight)));
|
||
|
||
if (fabs(Frame) < 0.001 || Times < 2)
|
||
return S_OK;
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// compute koeff
|
||
double dKoef = 1.0 + Frame*(Times - 1);
|
||
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
double dCenterX = 0.5*m_nWidth;
|
||
double dCenterY = 0.5*m_nHeight;
|
||
|
||
// variables
|
||
int nX, nY, nIndex = 0;
|
||
double dSourceX, dSourceY;
|
||
|
||
// process image
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// compute source pixel coordinates
|
||
dSourceX = dCenterX + (nX - dCenterX)*dKoef;
|
||
dSourceY = dCenterY + (nY - dCenterY)*dKoef;
|
||
|
||
// correct coordinates
|
||
if (dSourceX < 0)
|
||
{
|
||
while (dSourceX < 0)
|
||
dSourceX += m_nWidth - 1;
|
||
}
|
||
if (dSourceX > m_nWidth - 1)
|
||
{
|
||
while (dSourceX > m_nWidth - 1)
|
||
dSourceX -= m_nWidth - 1;
|
||
}
|
||
if (dSourceY < 0)
|
||
{
|
||
while (dSourceY < 0)
|
||
dSourceY += m_nHeight - 1;
|
||
}
|
||
if (dSourceY > m_nHeight - 1)
|
||
{
|
||
while (dSourceY > m_nHeight - 1)
|
||
dSourceY -= m_nHeight - 1;
|
||
}
|
||
|
||
// compute pixel color
|
||
m_pPixels[nIndex + 0] = GetPointNearest(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 0, 4, 0);
|
||
m_pPixels[nIndex + 1] = GetPointNearest(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 1, 4, 0);
|
||
m_pPixels[nIndex + 2] = GetPointNearest(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 2, 4, 0);
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
// variables
|
||
double dResize = 1.0 / dKoef;
|
||
IppiSize ResizedRoi = {(int)(m_IppiRoiSize.width * dResize) , (int)(m_IppiRoiSize.height * dResize)};
|
||
Ipp8u* pSrc = (Ipp8u*)m_pBackup;
|
||
Ipp8u* pDst = (Ipp8u*)m_pPixels;
|
||
IppiRect srcRoi = {0, 0, m_IppiRoiSize.width, m_IppiRoiSize.height};
|
||
int nSrcOffset, nDstOffset;
|
||
int nTileStep = ResizedRoi.width * 4;
|
||
int nFullTilesX = 2 * ((m_nWidth - ResizedRoi.width)/(2 * ResizedRoi.width)) + 1;
|
||
int nFullTilesY = 2 * ((m_nHeight - ResizedRoi.height)/(2 * ResizedRoi.height)) + 1;
|
||
int nXBottom, nXTop, nYBottom, nYTop;
|
||
|
||
nXBottom = nXTop = (m_nWidth - nFullTilesX * ResizedRoi.width);
|
||
nYBottom = nYTop = (m_nHeight - nFullTilesY * ResizedRoi.height);
|
||
nXTop /= 2; nYTop /= 2;
|
||
nXBottom -= nXTop; nYBottom -= nYTop;
|
||
|
||
nDstOffset = nYTop * m_nIppiStep + 4 * nXTop;
|
||
|
||
ippiResize_8u_AC4R(pSrc, m_IppiRoiSize, m_nIppiStep , srcRoi, pDst+nDstOffset, m_nIppiStep, ResizedRoi, dResize, dResize, IPPI_INTER_NN);
|
||
nSrcOffset = nDstOffset;
|
||
|
||
for (int i = 1; i < nFullTilesX; ++i)
|
||
{
|
||
nDstOffset += nTileStep;
|
||
ippiCopy_8u_AC4R(pDst + nSrcOffset, m_nIppiStep, pDst + nDstOffset, m_nIppiStep, ResizedRoi);
|
||
}
|
||
|
||
if (nXBottom > 0)
|
||
{
|
||
nDstOffset += nTileStep;
|
||
ResizedRoi.width = nXBottom;
|
||
ippiCopy_8u_AC4R(pDst + nSrcOffset, m_nIppiStep, pDst + nDstOffset, m_nIppiStep, ResizedRoi);
|
||
}
|
||
if (nXTop > 0)
|
||
{
|
||
nDstOffset = nSrcOffset - 4 * nXTop;
|
||
nSrcOffset = nSrcOffset + nTileStep - 4 * nXTop;
|
||
ResizedRoi.width = nXTop;
|
||
ippiCopy_8u_AC4R(pDst + nSrcOffset, m_nIppiStep, pDst + nDstOffset, m_nIppiStep, ResizedRoi);
|
||
}
|
||
else
|
||
nDstOffset = nSrcOffset;
|
||
|
||
nTileStep = ResizedRoi.height * m_nIppiStep;
|
||
nSrcOffset = nDstOffset;
|
||
ResizedRoi.width = m_IppiRoiSize.width;
|
||
|
||
for (int i = 1; i < nFullTilesY; ++i)
|
||
{
|
||
nDstOffset += nTileStep;
|
||
ippiCopy_8u_AC4R(pDst + nSrcOffset, m_nIppiStep, pDst + nDstOffset, m_nIppiStep, ResizedRoi);
|
||
}
|
||
|
||
if (nYBottom > 0)
|
||
{
|
||
nDstOffset += nTileStep;
|
||
ResizedRoi.height = nYBottom;
|
||
ippiCopy_8u_AC4R(pDst + nSrcOffset, m_nIppiStep, pDst + nDstOffset, m_nIppiStep, ResizedRoi);
|
||
}
|
||
if (nYTop > 0)
|
||
{
|
||
nDstOffset = 0;
|
||
ResizedRoi.height = nYTop;
|
||
nSrcOffset = nSrcOffset + nTileStep - m_nIppiStep * nYTop;
|
||
ippiCopy_8u_AC4R(pDst + nSrcOffset, m_nIppiStep, pDst + nDstOffset, m_nIppiStep, ResizedRoi);
|
||
}
|
||
|
||
#endif
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformZoom(double Frame, long Zoom)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Zoom = min(max(-100, Zoom), 100);
|
||
|
||
//// compute koeff
|
||
//double dKoef = 1;
|
||
|
||
// compute zooming koefficient
|
||
//if (Zoom == 0 || fabs(Frame) < 0.001)
|
||
// return S_OK;
|
||
//else if (Zoom < 0)
|
||
// dKoef = 1.0 - min(0.999, fabs(Frame*Zoom/100.0));
|
||
//else
|
||
// dKoef = 1.0 + 0.5*min(m_nWidth, m_nHeight)*pow(Frame*Zoom/100.0, 2);
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
#ifdef NOT_OPTIM
|
||
|
||
// variables
|
||
double dCenterX = 0.5*m_nWidth;
|
||
double dCenterY = 0.5*m_nHeight;
|
||
|
||
// variables
|
||
int nX, nY, nIndex = 0;
|
||
double dSourceX, dSourceY;
|
||
|
||
// compose background color
|
||
BYTE ColorR = GetRValue(m_nBackColor);
|
||
BYTE ColorG = GetGValue(m_nBackColor);
|
||
BYTE ColorB = GetBValue(m_nBackColor);
|
||
|
||
// process image
|
||
for (nY = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
// compute source pixel coordinates
|
||
dSourceX = dCenterX + (nX - dCenterX)/dKoef;
|
||
dSourceY = dCenterY + (nY - dCenterY)/dKoef;
|
||
|
||
// compute pixel color
|
||
m_pPixels[nIndex + 0] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 0, 4, ColorB);
|
||
m_pPixels[nIndex + 1] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 1, 4, ColorG);
|
||
m_pPixels[nIndex + 2] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 2, 4, ColorR);
|
||
}
|
||
}
|
||
|
||
#else
|
||
|
||
// clear image
|
||
ClearImage(m_pPixels, m_nSize);
|
||
|
||
double dScale = Zoom * Frame / 100;
|
||
if( Zoom > 0 )
|
||
dScale *= 10 * Frame; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
dScale += 1;
|
||
|
||
if( dScale < 0.00001 )
|
||
{
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
// !!! <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ippiResizeCenter(). <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!
|
||
|
||
double dOffsetX = m_dAdvancedZoomOffsetX;
|
||
double dOffsetY = m_dAdvancedZoomOffsetY;
|
||
int nWidth = m_nWidth;
|
||
int nHeight = m_nHeight;
|
||
|
||
Ipp32f* pxMap = new Ipp32f[nWidth*nHeight];
|
||
Ipp32f* pyMap = new Ipp32f[nWidth*nHeight];
|
||
|
||
if( pxMap && pyMap )
|
||
{
|
||
dOffsetX = nWidth / 2.0 * (dScale - 1) - dOffsetX;
|
||
dOffsetY = nHeight / 2.0 * (dScale - 1) - dOffsetY;
|
||
dScale = 1 / dScale;
|
||
|
||
Ipp32f* pMapCurX = pxMap;
|
||
Ipp32f* pMapCurY = pyMap;
|
||
|
||
for( int nRow = 0; nRow < nHeight; ++nRow )
|
||
{
|
||
for( int nPos = 0; nPos < nWidth; ++nPos )
|
||
{
|
||
*pMapCurX++ = Ipp32f((nPos + dOffsetX) * dScale);
|
||
*pMapCurY++ = Ipp32f((nRow + dOffsetY) * dScale);
|
||
}
|
||
}
|
||
|
||
IppiSize ImageSize = {nWidth, nHeight};
|
||
IppiRect ImageRect = {0, 0, nWidth, nHeight};
|
||
|
||
ippiRemap_8u_AC4R( m_pBackup, ImageSize, 4*nWidth, ImageRect,
|
||
pxMap, sizeof(Ipp32f)*nWidth,
|
||
pyMap, sizeof(Ipp32f)*nWidth,
|
||
m_pPixels, 4*nWidth, ImageSize, IPPI_INTER_LINEAR);
|
||
}
|
||
|
||
if( pxMap )
|
||
delete [] pxMap;
|
||
|
||
if( pyMap )
|
||
delete [] pyMap;
|
||
|
||
#endif
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformMirror(double Frame, double Level, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Level = min(max(0, Level), 100);
|
||
|
||
if (fabs(Frame) < 0.001 || fabs(Level) < 0.001 )
|
||
return S_OK;
|
||
|
||
#ifdef NOT_OPTIM // TODO: disabled optimization due to access violation
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// mirror image
|
||
if (Type == c_nMirrorVerticalBottom || Type == c_nMirrorVerticalTop)
|
||
MirrorVertical(Frame, Type, Level);
|
||
else if (Type == c_nMirrorHorizontalLeft || Type == c_nMirrorHorizontalRight)
|
||
MirrorHorizontal(Frame, Type, Level);
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
#else
|
||
|
||
// variables
|
||
Ipp8u* pDst = (Ipp8u*)m_pPixels;
|
||
IppiRect srcRoi = {0, 0, m_IppiRoiSize.width, m_IppiRoiSize.height};
|
||
IppiSize dstRoiSize = m_IppiRoiSize;
|
||
int nMirror;
|
||
double dResize = 0.01*Level*Frame;
|
||
|
||
if (Type == c_nMirrorVerticalTop)
|
||
{
|
||
nMirror = (int)(dResize*(m_nHeight - 2));
|
||
srcRoi.height -= nMirror;
|
||
dstRoiSize.height = nMirror;
|
||
dResize = (double)dstRoiSize.height/srcRoi.height;
|
||
|
||
ippiResize_8u_AC4R(pDst, m_IppiRoiSize, m_nIppiStep, srcRoi, pDst + srcRoi.height * m_nIppiStep, m_nIppiStep, dstRoiSize, 1, dResize, IPPI_INTER_LINEAR);
|
||
|
||
pDst = pDst + srcRoi.height * m_nIppiStep;
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, dstRoiSize, ippAxsHorizontal);
|
||
|
||
IppiSize MaskSize = {10, 3};
|
||
IppiPoint anchor = {MaskSize.width/2, 1};
|
||
dstRoiSize.width -= (MaskSize.width - 1);
|
||
dstRoiSize.height -= (MaskSize.height - 1);
|
||
ippiFilterBox_8u_AC4IR(pDst + anchor.y*m_nIppiStep + anchor.x*4 , m_nIppiStep, dstRoiSize, MaskSize, anchor);
|
||
}
|
||
else if (Type == c_nMirrorVerticalBottom)
|
||
{
|
||
nMirror = (int)(dResize*(m_nHeight - 2));
|
||
srcRoi.height -= nMirror;
|
||
srcRoi.y = nMirror;
|
||
dstRoiSize.height = nMirror;
|
||
dResize = (double)dstRoiSize.height/srcRoi.height;
|
||
|
||
ippiResize_8u_AC4R(pDst, m_IppiRoiSize, m_nIppiStep, srcRoi, pDst, m_nIppiStep, dstRoiSize, 1, dResize, IPPI_INTER_LINEAR);
|
||
|
||
ippiMirror_8u_AC4IR( pDst, m_nIppiStep, dstRoiSize, ippAxsHorizontal );
|
||
|
||
IppiSize MaskSize = {10, 3};
|
||
IppiPoint anchor = {MaskSize.width/2, 1};
|
||
dstRoiSize.width -= (MaskSize.width - 1);
|
||
dstRoiSize.height -= (MaskSize.height - 1);
|
||
ippiFilterBox_8u_AC4IR(pDst + anchor.y*m_nIppiStep + anchor.x*4 , m_nIppiStep, dstRoiSize, MaskSize, anchor);
|
||
}
|
||
if (Type == c_nMirrorHorizontalRight)
|
||
{
|
||
nMirror = (int)(dResize*(m_nWidth - 2));
|
||
srcRoi.width -= nMirror;
|
||
dstRoiSize.width = nMirror;
|
||
dResize = (double)dstRoiSize.width/srcRoi.width;
|
||
|
||
ippiResize_8u_AC4R(pDst, m_IppiRoiSize, m_nIppiStep, srcRoi, pDst + srcRoi.width * 4, m_nIppiStep, dstRoiSize, dResize, 1, IPPI_INTER_LINEAR);
|
||
|
||
pDst += srcRoi.width * 4;
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, dstRoiSize, ippAxsVertical);
|
||
|
||
IppiSize MaskSize = {3, 10};
|
||
IppiPoint anchor= {1, MaskSize.height / 2};
|
||
dstRoiSize.width -= (MaskSize.width - 1);
|
||
dstRoiSize.height -= (MaskSize.height - 1);
|
||
ippiFilterBox_8u_AC4IR(pDst + anchor.y*m_nIppiStep + anchor.x*4, m_nIppiStep, dstRoiSize, MaskSize, anchor);
|
||
}
|
||
else if (Type == c_nMirrorHorizontalLeft)
|
||
{
|
||
nMirror = (int)(dResize*(m_nWidth - 2));
|
||
srcRoi.width -= nMirror;
|
||
srcRoi.x = nMirror;
|
||
dstRoiSize.width = nMirror;
|
||
dResize = (double)dstRoiSize.width/srcRoi.width;
|
||
|
||
ippiResize_8u_AC4R(pDst, m_IppiRoiSize, m_nIppiStep , srcRoi, pDst, m_nIppiStep, dstRoiSize, dResize, 1, IPPI_INTER_LINEAR);
|
||
|
||
ippiMirror_8u_AC4IR(pDst, m_nIppiStep, dstRoiSize, ippAxsVertical);
|
||
|
||
IppiSize MaskSize = {3, 10};
|
||
IppiPoint anchor= {1, MaskSize.height/2};
|
||
dstRoiSize.width -= (MaskSize.width - 1);
|
||
dstRoiSize.height -= (MaskSize.height - 1);
|
||
ippiFilterBox_8u_AC4IR(pDst + anchor.y*m_nIppiStep + anchor.x*4, m_nIppiStep, dstRoiSize, MaskSize, anchor);
|
||
}
|
||
|
||
#endif
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformResize(BYTE* pData, long lWidth, long lHeight, long Color, long Type)
|
||
{
|
||
int NewHeight = lHeight;
|
||
int NewWidth = lWidth;
|
||
|
||
if (NewHeight < 2 || NewWidth < 2)
|
||
return S_FALSE;
|
||
if (m_nWidth == NewWidth && m_nHeight == NewHeight)
|
||
{
|
||
m_oMemoryUtils.memcpy(pData, m_pPixels, 4*NewWidth*NewHeight);
|
||
return S_OK;
|
||
}
|
||
|
||
#ifdef NOT_OPTIM
|
||
|
||
return S_FALSE;
|
||
|
||
#else
|
||
|
||
// variables
|
||
BYTE* pResized = pData;
|
||
double dScaleX = 1.0;
|
||
double dScaleY = 1.0;
|
||
IppiRect srcRect = {0, 0, m_nWidth, m_nHeight};
|
||
|
||
if (Type == c_nResizeStretchNearest || Type == c_nResizeStretchBillinear || Type == c_nResizeStretchBicubic)
|
||
{
|
||
IppiSize dstRoi = {NewWidth, NewHeight};
|
||
|
||
dScaleX = NewWidth/(double)m_nWidth;
|
||
dScaleY = NewHeight/(double)m_nHeight;
|
||
|
||
if (Type == c_nResizeStretchNearest)
|
||
ippiResize_8u_AC4R(m_pPixels, m_IppiRoiSize, m_nIppiStep, srcRect, pResized, 4*NewWidth, dstRoi, dScaleX, dScaleY, IPPI_INTER_NN);
|
||
else
|
||
ippiResize_8u_AC4R(m_pPixels, m_IppiRoiSize, m_nIppiStep, srcRect, pResized, 4*NewWidth, dstRoi, dScaleX, dScaleY, IPPI_INTER_LINEAR);
|
||
|
||
int x, y;
|
||
double dSourceX, dSourceY;
|
||
|
||
for (y = 0; y < NewHeight; ++y)
|
||
{
|
||
for (x = 0; x < NewWidth; ++x, pResized += 4)
|
||
{
|
||
// compute old pixel angle and radius
|
||
dSourceX = 0.5*m_nWidth - (0.5*NewWidth - x)/dScaleX;
|
||
dSourceY = 0.5*m_nHeight - (0.5*NewHeight - y)/dScaleY;
|
||
|
||
// compute pixel color
|
||
if (Type == c_nResizeStretchNearest)
|
||
{
|
||
pResized[3] = GetPointNearest(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 3, 4, 255);
|
||
}
|
||
else
|
||
{
|
||
pResized[3] = GetPointBillinear(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 3, 4, 255);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (Type == c_nResizeShrinkNearest || Type == c_nResizeShrinkBillinear || Type == c_nResizeShrinkBicubic)
|
||
{
|
||
IppiSize dstRoi = {NewWidth, NewHeight};
|
||
|
||
// clear output image first
|
||
ClearImage((BYTE*)pResized, 4*NewWidth*NewHeight);
|
||
|
||
// TODO: variables
|
||
dScaleX = NewWidth/(double)m_nWidth;
|
||
dScaleY = NewHeight/(double)m_nHeight;
|
||
|
||
double dZoom = min(1.0, min(dScaleX, dScaleY));
|
||
|
||
dScaleX = dZoom;
|
||
dScaleY = dZoom;
|
||
|
||
if (m_dAspect != 1)
|
||
{
|
||
double dW = m_dAspect * m_nHeight;
|
||
dScaleX *= (dW / m_nWidth);
|
||
|
||
int nNewWidthAsp = dScaleX * m_nWidth;
|
||
if (nNewWidthAsp > NewWidth)
|
||
{
|
||
double dCorrect = (double)NewWidth / nNewWidthAsp;
|
||
dScaleX *= dCorrect;
|
||
dScaleY *= dCorrect;
|
||
}
|
||
}
|
||
|
||
Ipp8u *pDst = pResized;
|
||
if (NewHeight > dScaleY*m_nHeight)
|
||
pDst += 4*NewWidth*(int)((NewHeight - dScaleY*m_nHeight)/2);
|
||
if (NewWidth > dScaleX*m_nWidth)
|
||
pDst += 4*(int)((NewWidth - dScaleX*m_nWidth)/2);
|
||
|
||
// resize image from center simulating zooming effect
|
||
if (Type == c_nResizeShrinkNearest)
|
||
ippiResize_8u_AC4R((Ipp8u*)m_pPixels, m_IppiRoiSize, m_nIppiStep, srcRect, pDst, 4*NewWidth, dstRoi, dScaleX, dScaleY, IPPI_INTER_NN);
|
||
else
|
||
ippiResize_8u_AC4R((Ipp8u*)m_pPixels, m_IppiRoiSize, m_nIppiStep, srcRect, pDst, 4*NewWidth, dstRoi, dScaleX, dScaleY, IPPI_INTER_LINEAR);
|
||
|
||
int x, y;
|
||
double dSourceX, dSourceY;
|
||
// AlphaChannel
|
||
for (y = 0; y < NewHeight; ++y)
|
||
{
|
||
for (x = 0; x < NewWidth; ++x, pResized += 4)
|
||
{
|
||
// compute old pixel angle and radius
|
||
dSourceX = 0.5*m_nWidth - (0.5*NewWidth - x)/dScaleX;
|
||
dSourceY = 0.5*m_nHeight - (0.5*NewHeight - y)/dScaleY;
|
||
|
||
// compute pixel color
|
||
if (Type == c_nResizeShrinkNearest)
|
||
{
|
||
pResized[3] = GetPointNearest(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 3, 4, 255);
|
||
}
|
||
else
|
||
{
|
||
pResized[3] = GetPointBillinear(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 3, 4, 255);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (Type == c_nResizeCropNearest || Type == c_nResizeCropBillinear || Type == c_nResizeCropBicubic)
|
||
{
|
||
// variables
|
||
dScaleX = NewWidth/(double)m_nWidth;
|
||
dScaleY = NewHeight/(double)m_nHeight;
|
||
|
||
double dZoom1 = min(dScaleX, dScaleY);
|
||
double dZoom2 = max(dScaleX, dScaleY);
|
||
double dZoom = dZoom1 + (dZoom2 - dZoom1)*m_nAdvancedCropZoom/100.0;
|
||
|
||
// compose background color
|
||
BYTE ColorR = GetRValue(m_nBackColor);
|
||
BYTE ColorG = GetGValue(m_nBackColor);
|
||
BYTE ColorB = GetBValue(m_nBackColor);
|
||
BYTE ColorA = GetBValue(m_nBackColor);
|
||
|
||
int x, y;
|
||
double dSourceX, dSourceY;
|
||
|
||
for (y = 0; y < NewHeight; ++y)
|
||
{
|
||
for (x = 0; x < NewWidth; ++x, pResized += 4)
|
||
{
|
||
// compute old pixel angle and radius
|
||
dSourceX = 0.5*m_nWidth - (0.5*NewWidth - x)/dZoom;
|
||
dSourceY = 0.5*m_nHeight - (0.5*NewHeight - y)/dZoom;
|
||
|
||
// compute pixel color
|
||
if (Type == c_nResizeCropNearest)
|
||
{
|
||
pResized[0] = GetPointNearest(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 0, 4, ColorB);
|
||
pResized[1] = GetPointNearest(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 1, 4, ColorG);
|
||
pResized[2] = GetPointNearest(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 2, 4, ColorR);
|
||
pResized[3] = GetPointNearest(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 3, 4, ColorA);
|
||
}
|
||
else
|
||
{
|
||
pResized[0] = GetPointBillinear(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 0, 4, ColorB);
|
||
pResized[1] = GetPointBillinear(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 1, 4, ColorG);
|
||
pResized[2] = GetPointBillinear(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 2, 4, ColorR);
|
||
pResized[3] = GetPointBillinear(dSourceX, dSourceY, m_pPixels, m_nWidth, m_nHeight, 3, 4, ColorA);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformResize(SAFEARRAY** Output, long Color, long Type)
|
||
{
|
||
if (!Output || !*Output || !m_nWidth || !m_nHeight)
|
||
return S_FALSE;
|
||
|
||
return TransformResize((BYTE*)((*Output)->pvData), (*Output)->rgsabound[1].cElements, (*Output)->rgsabound[0].cElements, Color, Type);
|
||
}
|
||
STDMETHODIMP ImageTransform3::TransformResizeMedia(IUnknown** pInterface, long Color, long Type)
|
||
{
|
||
if (!pInterface || !*pInterface || !m_nWidth || !m_nHeight)
|
||
return S_FALSE;
|
||
|
||
ImageStudio::Core::MediaData oMediaData;
|
||
|
||
if (!oMediaData.Create(*pInterface, FALSE) || !oMediaData.IsValidBGRA())
|
||
return S_FALSE;
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>", <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ))
|
||
*pInterface = oMediaData.GetMediaData(TRUE);
|
||
|
||
return TransformResize(oMediaData.GetBuffer(), oMediaData.GetWidth(), oMediaData.GetHeight(), Color, Type);
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformResizeMedia2(long nNewWidth, long nNewHeight, IUnknown** pMediaData, long Color, long Type)
|
||
{
|
||
if (!ImageStudioUtils::ByteArrayToMediaData(NULL, nNewWidth, nNewHeight, pMediaData))
|
||
return S_FALSE;
|
||
IUnknown* pCreatedMediaData = *pMediaData;
|
||
|
||
TransformResizeMedia(pMediaData, Color, Type);
|
||
|
||
if (*pMediaData != pCreatedMediaData)
|
||
pCreatedMediaData->Release();
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformRotateMedia(double Frame, double Angle, IUnknown** pMediaData)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Angle = Frame*min(max(-360, Angle), 360);
|
||
|
||
// check for simpliest case
|
||
if (fabs(Angle) < 0.001 || Angle > 359.999 || Angle < -359.999)
|
||
return S_OK;
|
||
|
||
// check whether we flip image on 180 degrees
|
||
// if (fabs(fabs(Angle) - 180) < 0.001)
|
||
// {
|
||
// // TODO: special case
|
||
// ippiMirror_8u_AC4IR(pDst, m_nIppiStep, m_IppiRoiSize, ippAxsBoth);
|
||
// return S_OK;
|
||
// }
|
||
|
||
if (fabs(Angle - 90) < 0.001 || fabs(Angle + 270) < 0.001 || fabs(Angle + 90) < 0.001 || fabs(Angle - 270) < 0.001)
|
||
{
|
||
int nNewWidth = m_nHeight;
|
||
int nNewHeight = m_nWidth;
|
||
|
||
if (!ImageStudioUtils::ByteArrayToMediaData(NULL, nNewWidth, nNewHeight, pMediaData))
|
||
return S_FALSE;
|
||
IUnknown* pCreatedMediaData = *pMediaData;
|
||
ImageStudio::Core::MediaData oMediaData;
|
||
if (!oMediaData.Create(*pMediaData, FALSE) || !oMediaData.IsValidBGRA())
|
||
return S_FALSE;
|
||
*pMediaData = oMediaData.GetMediaData(TRUE);
|
||
if (*pMediaData != pCreatedMediaData)
|
||
pCreatedMediaData->Release();
|
||
|
||
BYTE* pDst = oMediaData.GetBuffer();
|
||
|
||
ClearImage(pDst, 4*nNewWidth*nNewHeight);
|
||
|
||
//int x, y;
|
||
int index_src = 0;
|
||
int index_dst = 0;
|
||
|
||
BOOL b90 = (fabs(Angle - 90) < 0.001 || fabs(Angle + 270) < 0.001);
|
||
BOOL b270 = (fabs(Angle + 90) < 0.001 || fabs(Angle - 270) < 0.001);
|
||
|
||
for (int y = 0; y < nNewHeight; ++y)
|
||
{
|
||
for (int x = 0; x < nNewWidth; ++x, pDst += 4)
|
||
{
|
||
if (b90)
|
||
index_src = 4*(x*nNewHeight + (nNewHeight - 1 - y));
|
||
else if (b270)
|
||
index_src = 4*((nNewWidth - 1 - x)*nNewHeight + y);
|
||
|
||
memcpy(pDst, m_pPixels + index_src, 4);
|
||
}
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
else if (fabs(Angle - 180) < 0.001 || fabs(Angle + 180) < 0.001)
|
||
{
|
||
int nNewWidth = m_nWidth;
|
||
int nNewHeight = m_nHeight;
|
||
|
||
if (!ImageStudioUtils::ByteArrayToMediaData(NULL, nNewWidth, nNewHeight, pMediaData))
|
||
return S_FALSE;
|
||
IUnknown* pCreatedMediaData = *pMediaData;
|
||
ImageStudio::Core::MediaData oMediaData;
|
||
if (!oMediaData.Create(*pMediaData, FALSE) || !oMediaData.IsValidBGRA())
|
||
return S_FALSE;
|
||
*pMediaData = oMediaData.GetMediaData(TRUE);
|
||
if (*pMediaData != pCreatedMediaData)
|
||
pCreatedMediaData->Release();
|
||
|
||
BYTE* pDst = oMediaData.GetBuffer();
|
||
|
||
ClearImage(pDst, 4*nNewWidth*nNewHeight);
|
||
|
||
//int x, y;
|
||
int index_src = 0;
|
||
int index_dst = 0;
|
||
|
||
for (int y = 0; y < nNewHeight; ++y)
|
||
{
|
||
for (int x = 0; x < nNewWidth; ++x, pDst += 4)
|
||
{
|
||
index_src = 4*((nNewHeight - 1 - y)*nNewWidth + (nNewWidth - 1 - x));
|
||
|
||
memcpy(pDst, m_pPixels + index_src, 4);
|
||
}
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
else
|
||
{
|
||
// variables
|
||
Ipp8u* pSrc = (Ipp8u*)m_pPixels;
|
||
IppiRect srcRoi = {0, 0, m_IppiRoiSize.width , m_IppiRoiSize.height};
|
||
double quad[4][2];
|
||
|
||
ippiGetRotateQuad(srcRoi, quad, Angle, 0, 0);
|
||
|
||
double dLeft = min(min(quad[0][0], quad[1][0]), min(quad[2][0], quad[3][0]));
|
||
double dRight = max(max(quad[0][0], quad[1][0]), max(quad[2][0], quad[3][0]));
|
||
double dTop = min(min(quad[0][1], quad[1][1]), min(quad[2][1], quad[3][1]));
|
||
double dBottom = max(max(quad[0][1], quad[1][1]), max(quad[2][1], quad[3][1]));
|
||
|
||
int nNewWidth = (int)ceil(dRight - dLeft);
|
||
int nNewHeight = (int)ceil(dBottom - dTop);
|
||
|
||
if (!ImageStudioUtils::ByteArrayToMediaData(NULL, nNewWidth, nNewHeight, pMediaData))
|
||
return S_FALSE;
|
||
IUnknown* pCreatedMediaData = *pMediaData;
|
||
ImageStudio::Core::MediaData oMediaData;
|
||
if (!oMediaData.Create(*pMediaData, FALSE) || !oMediaData.IsValidBGRA())
|
||
return S_FALSE;
|
||
*pMediaData = oMediaData.GetMediaData(TRUE);
|
||
if (*pMediaData != pCreatedMediaData)
|
||
pCreatedMediaData->Release();
|
||
|
||
Ipp8u* pDst = (Ipp8u*)oMediaData.GetBuffer();
|
||
IppiSize dstSize = {nNewWidth, nNewHeight};
|
||
IppiRect dstRoi = {0, 0, nNewWidth, nNewHeight};
|
||
|
||
ClearImage((BYTE*)pDst, 4*nNewWidth*nNewHeight);
|
||
|
||
double xShift = 0, yShift = 0;
|
||
ippiGetRotateShift(0.5*m_nWidth, 0.5*m_nHeight, Angle, &xShift, &yShift);
|
||
xShift += 0.5*nNewWidth - 0.5*m_nWidth;
|
||
yShift += 0.5*nNewHeight - 0.5*m_nHeight;
|
||
|
||
ippiRotate_8u_AC4R(pSrc, m_IppiRoiSize, 4*m_nWidth, srcRoi, pDst, 4*nNewWidth, dstRoi, Angle, xShift, yShift, IPPI_INTER_LINEAR);
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::TransformTwirl(double Frame, double Angle, long Degree)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPTransformTwirl(m_pPixels, m_nWidth, m_nHeight, Frame, Angle, Degree, m_nBackColor))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
STDMETHODIMP ImageTransform3::TransformSphere(double Frame, long CenterX, long CenterY, long RadiusX, long RadiusY, double Degree)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
if (Degree < -1.0)
|
||
Degree = -1.0;
|
||
else if (Degree > 10.0)
|
||
Degree = 10.0;
|
||
|
||
if (IPPTransformSphere(m_pPixels, m_nWidth, m_nHeight, Frame, CenterX, m_nHeight - 1 - CenterY, RadiusX, RadiusY, Degree, m_nBackColor))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
STDMETHODIMP ImageTransform3::TransformCylinder(double Frame, long Center, long Radius, double Degree, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
if (Degree < -1.0)
|
||
Degree = -1.0;
|
||
else if (Degree > 10.0)
|
||
Degree = 10.0;
|
||
|
||
if (IPPTransformCylinder(m_pPixels, m_nWidth, m_nHeight, Frame, Center, Radius, Degree, Type, m_nBackColor))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterPrewitt(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterPrewitt(m_pPixels,m_nWidth,m_nHeight, Frame, Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterScharr(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterScharr(m_pPixels,m_nWidth,m_nHeight, Frame, Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterSobel(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterSobel(m_pPixels,m_nWidth,m_nHeight,Frame,Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterSobelExt(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterSobelExt(m_pPixels,m_nWidth,m_nHeight,Frame,Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterRoberts(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterRoberts(m_pPixels,m_nWidth,m_nHeight,Frame,Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterLaplace(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterLaplace(m_pPixels,m_nWidth,m_nHeight,Frame, Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterHipass(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterHipass(m_pPixels,m_nWidth,m_nHeight,Frame, Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterLowpass(double Frame, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterLowpass(m_pPixels,m_nWidth,m_nHeight,Frame, Type))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterBlur(double Frame, long Size)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterBlur(m_pPixels,m_nWidth,m_nHeight,Frame, Size))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::FilterCanny(double Frame, double LowThresh, double HighThresh)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
if (IPPFilterCanny(m_pPixels,m_nWidth,m_nHeight, Frame, LowThresh, HighThresh))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
}
|
||
|
||
|
||
STDMETHODIMP ImageTransform3::UtilitySwapChannels(BYTE nChannel0, BYTE nChannel1, BYTE nChannel2)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
if (IPPUtilitySwapChannels(m_pPixels, m_nWidth, m_nHeight, nChannel0, nChannel1, nChannel2))
|
||
return S_OK;
|
||
else
|
||
return S_FALSE;
|
||
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawLine(double Frame, long X1, long Y1, long X2, long Y2, long Color, long Alpha, long Size)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// prepare drawing
|
||
BeginDraw();
|
||
|
||
// create drawing graphics
|
||
Graphics* graphics = Graphics::FromImage(m_pBitmap);
|
||
|
||
// create color
|
||
Gdiplus::Color color((BYTE)(Frame*Alpha), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
|
||
// create pen
|
||
Pen pen(color, (REAL)Size);
|
||
|
||
// draw line
|
||
graphics->DrawLine(&pen, X1, Y1, X2, Y2);
|
||
|
||
// stop painting
|
||
graphics->Flush();
|
||
|
||
// delete objects
|
||
delete graphics;
|
||
|
||
// finalize drawing
|
||
EndDraw();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawRectangle(double Frame, long X1, long Y1, long X2, long Y2, long Color, long Alpha, VARIANT_BOOL Solid)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// compose alpha valies
|
||
double dAlpha2 = (1.0 - Frame*Alpha/255.0);
|
||
double dAlpha1 = Frame*Alpha/255.0;
|
||
|
||
// retrieve color components
|
||
double dRed = dAlpha1*GetRValue(Color);
|
||
double dGreen = dAlpha1*GetGValue(Color);
|
||
double dBlue = dAlpha1*GetBValue(Color);
|
||
|
||
// compute sizes
|
||
int nLeft = min(X1, X2);
|
||
int nTop = min(Y1, Y2);
|
||
int nRight = max(X1, X2);
|
||
int nBottom = max(Y1, Y2);
|
||
|
||
// variables
|
||
int nX, nY, nIndex;
|
||
|
||
// draw image
|
||
for (nY = nTop; nY < nBottom; ++nY)
|
||
{
|
||
// check for valid coordinates
|
||
if (nY < 0 || nY >= m_nHeight)
|
||
continue;
|
||
|
||
for (nX = nLeft; nX < nRight; ++nX)
|
||
{
|
||
// check for valid coordinates
|
||
if (nX < 0 || nX >= m_nWidth)
|
||
continue;
|
||
|
||
// compute index
|
||
nIndex = 4*(nX + (m_nHeight - 1 - nY)*m_nWidth);
|
||
|
||
// draw rectangle
|
||
if ((Solid == VARIANT_TRUE) || ((Solid == VARIANT_FALSE) && (nY == nTop || nY == nBottom - 1 || nX == nLeft || nX == nRight - 1)))
|
||
{
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha2*m_pPixels[nIndex + 0] + dBlue);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha2*m_pPixels[nIndex + 1] + dGreen);
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha2*m_pPixels[nIndex + 2] + dRed);
|
||
}
|
||
}
|
||
}
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawEllipse(double Frame, long X1, long Y1, long X2, long Y2, long Color, long Alpha, VARIANT_BOOL Solid)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// prepare drawing
|
||
BeginDraw();
|
||
|
||
// create drawing graphics
|
||
Graphics* graphics = Graphics::FromImage(m_pBitmap); graphics->SetSmoothingMode(SmoothingModeAntiAlias);
|
||
|
||
// create color
|
||
Gdiplus::Color color((BYTE)(Frame*Alpha), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
|
||
// create pen and brush
|
||
Pen pen(color, 1.0);
|
||
SolidBrush brush(color);
|
||
|
||
// compute rectangle coordinates
|
||
int Left = min(X1, X2);
|
||
int Right = max(X1, X2);
|
||
int Top = min(Y1, Y2);
|
||
int Bottom = max(Y1, Y2);
|
||
|
||
// draw solid ellipse
|
||
if (Solid == VARIANT_TRUE)
|
||
graphics->FillEllipse(&brush, Left, Top, Right - Left, Bottom - Top);
|
||
|
||
// draw bounding ellipse
|
||
graphics->DrawEllipse(&pen, Left, Top, Right - Left, Bottom - Top);
|
||
|
||
// stop painting
|
||
graphics->Flush();
|
||
|
||
// delete objects
|
||
delete graphics;
|
||
|
||
// finalize drawing
|
||
EndDraw();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawInvRectangle(double Frame, long X1, long Y1, long X2, long Y2, long Color, long Alpha)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// prepare drawing
|
||
BeginDraw();
|
||
|
||
// create drawing graphics
|
||
Graphics* graphics = Graphics::FromImage(m_pBitmap);
|
||
|
||
// create color
|
||
Gdiplus::Color color((BYTE)(Frame*Alpha), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
|
||
// create pen and brush
|
||
SolidBrush brush(color);
|
||
|
||
// compute rectangle coordinates
|
||
int Left = min(X1, X2);
|
||
int Right = max(X1, X2);
|
||
int Top = min(Y1, Y2);
|
||
int Bottom = max(Y1, Y2);
|
||
|
||
// compose region to fill
|
||
Rect rect1(0, 0, m_nWidth, m_nHeight);
|
||
Rect rect2(Left, Top, Right - Left - 1, Bottom - Top - 1);
|
||
Region region(rect1); region.Xor(rect2);
|
||
|
||
// draw region
|
||
graphics->FillRegion(&brush, ®ion);
|
||
|
||
// stop painting
|
||
graphics->Flush();
|
||
|
||
// delete objects
|
||
delete graphics;
|
||
|
||
// finalize drawing
|
||
EndDraw();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawInvEllipse(double Frame, long X1, long Y1, long X2, long Y2, long Color, long Alpha)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// prepare drawing
|
||
BeginDraw();
|
||
|
||
// create drawing graphics
|
||
Graphics* graphics = Graphics::FromImage(m_pBitmap);
|
||
|
||
// create color
|
||
Gdiplus::Color color((BYTE)(Frame*Alpha), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
|
||
// create pen and brush
|
||
SolidBrush brush(color);
|
||
|
||
// compute rectangle coordinates
|
||
int Left = min(X1, X2);
|
||
int Right = max(X1, X2);
|
||
int Top = min(Y1, Y2);
|
||
int Bottom = max(Y1, Y2);
|
||
|
||
// compose region to fill
|
||
Rect rect(0, 0, m_nWidth, m_nHeight);
|
||
GraphicsPath path; path.AddEllipse(Left, Top, Right - Left - 1, Bottom - Top - 1);
|
||
Region region(rect); region.Xor(&path);
|
||
|
||
// draw region
|
||
graphics->FillRegion(&brush, ®ion);
|
||
|
||
// stop painting
|
||
graphics->Flush();
|
||
|
||
// delete objects
|
||
delete graphics;
|
||
|
||
// finalize drawing
|
||
EndDraw();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawImagePtr(double Frame, long X1, long Y1, BYTE* Image, long Color, long Alpha)
|
||
{
|
||
// variables
|
||
SAFEARRAY* Array = (SAFEARRAY*)Image;
|
||
|
||
// draw image
|
||
return DrawImage(Frame, X1, Y1, &Array, Color, Alpha);
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawImage(double Frame, long X1, long Y1, SAFEARRAY** Image, long color, long Alpha)
|
||
{
|
||
int nWidth = 0;
|
||
int nHeight = 0;
|
||
int nChannels = 0;
|
||
|
||
BYTE* pData = ImageStudioUtils::ExtractImage(Image, nWidth, nHeight, nChannels);
|
||
|
||
if (!pData || nChannels != 4)
|
||
return S_FALSE;
|
||
|
||
return DrawImage(Frame, X1, Y1, pData, nWidth, nHeight, color, Alpha);
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawImageMedia(double Frame, long X1, long Y1, IUnknown* pInterface, long Color, long Alpha)
|
||
{
|
||
ImageStudio::Core::MediaData oMediaData;
|
||
|
||
if (!oMediaData.Create(pInterface, FALSE) || !oMediaData.IsValidBGRA())
|
||
return S_FALSE;
|
||
|
||
return DrawImage(Frame, X1, Y1, oMediaData.GetBuffer(), oMediaData.GetWidth(), oMediaData.GetHeight(), Color, Alpha);
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawImageKey(double Frame, long X1, long Y1, SAFEARRAY** Image, long Color1, long Color2)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
Color col;
|
||
float r, g, b;
|
||
float fLightness, fSaturation;
|
||
float fHue1;
|
||
col.SetValue(Color1);
|
||
r = (float)col.GetB();
|
||
r /= 255.0f;
|
||
g = (float)col.GetG();
|
||
g /= 255.0f;
|
||
b = (float)col.GetR();
|
||
b /= 255.0f;
|
||
|
||
ConvertToHls(r, g, b, fHue1, fLightness, fSaturation);
|
||
|
||
float fHue2;
|
||
col.SetValue(Color2);
|
||
r = (float)col.GetB();
|
||
r /= 255.0f;
|
||
g = (float)col.GetG();
|
||
g /= 255.0f;
|
||
b = (float)col.GetR();
|
||
b /= 255.0f;
|
||
|
||
ConvertToHls(r, g, b, fHue2, fLightness, fSaturation);
|
||
|
||
long bound;
|
||
// m_pPixels
|
||
BITMAPINFO videoBitmapInfo;
|
||
videoBitmapInfo.bmiHeader.biPlanes = 1;
|
||
videoBitmapInfo.bmiHeader.biBitCount = 32;
|
||
videoBitmapInfo.bmiHeader.biCompression = 0;
|
||
videoBitmapInfo.bmiHeader.biSizeImage = 0;
|
||
videoBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
|
||
videoBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
|
||
videoBitmapInfo.bmiHeader.biClrUsed = 0;
|
||
videoBitmapInfo.bmiHeader.biClrImportant = 0;
|
||
videoBitmapInfo.bmiHeader.biSize = 40;
|
||
videoBitmapInfo.bmiHeader.biWidth = m_nWidth;
|
||
videoBitmapInfo.bmiHeader.biHeight = m_nHeight;
|
||
|
||
Bitmap videoBitmap(&videoBitmapInfo, m_pPixels);
|
||
|
||
// Image
|
||
SafeArrayGetUBound((*Image), 2, &bound);
|
||
int nImageWidth = bound + 1;
|
||
|
||
SafeArrayGetUBound((*Image), 3, &bound);
|
||
int nImageHeight = bound + 1;
|
||
|
||
int nHComponent1 = fHue1*255.0f/360.0f;
|
||
int nHComponent2 = fHue2*255.0f/360.0f;
|
||
|
||
CChromoKey oChromo;
|
||
oChromo.SetImage((LPBYTE)(*Image)->pvData, nImageWidth, nImageHeight);
|
||
oChromo.DoChromoKey(Frame, nHComponent1, m_nAdvancedChromaThreshold1, nHComponent2, m_nAdvancedChromaThreshold2);
|
||
|
||
Graphics graphics(&videoBitmap);
|
||
oChromo.DrawToGraphics(&graphics, TRUE, X1, Y1);
|
||
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
STDMETHODIMP ImageTransform3::DrawImageKey2(double Frame, long X1, long Y1, SAFEARRAY** Image, long color, long Threshold)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
Color col;
|
||
float r, g, b;
|
||
float fHue, fLightness, fSaturation;
|
||
float koef1 = 0, koef2 = 0;
|
||
col.SetValue(color);
|
||
r = (float)col.GetB();
|
||
r /= 255.0f;
|
||
g = (float)col.GetG();
|
||
g /= 255.0f;
|
||
b = (float)col.GetR();
|
||
b /= 255.0f;
|
||
|
||
ConvertToHls(r, g, b, fHue, fLightness, fSaturation);
|
||
|
||
if(Threshold > 100)
|
||
Threshold = 100;
|
||
if(Threshold < 0)
|
||
Threshold = 0;
|
||
|
||
long bound;
|
||
// m_pPixels
|
||
BITMAPINFO videoBitmapInfo;
|
||
videoBitmapInfo.bmiHeader.biPlanes = 1;
|
||
videoBitmapInfo.bmiHeader.biBitCount = 32;
|
||
videoBitmapInfo.bmiHeader.biCompression = 0;
|
||
videoBitmapInfo.bmiHeader.biSizeImage = 0;
|
||
videoBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
|
||
videoBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
|
||
videoBitmapInfo.bmiHeader.biClrUsed = 0;
|
||
videoBitmapInfo.bmiHeader.biClrImportant = 0;
|
||
videoBitmapInfo.bmiHeader.biSize = 40;
|
||
videoBitmapInfo.bmiHeader.biWidth = m_nWidth;
|
||
videoBitmapInfo.bmiHeader.biHeight = m_nHeight;
|
||
|
||
Bitmap videoBitmap(&videoBitmapInfo, m_pPixels);
|
||
|
||
// Image
|
||
SafeArrayGetUBound((*Image), 2, &bound);
|
||
int nImageWidth = bound + 1;
|
||
|
||
SafeArrayGetUBound((*Image), 3, &bound);
|
||
int nImageHeight = bound + 1;
|
||
|
||
int nHComponent = fHue*255.0f/360.0f;
|
||
CChromoKey oChromo;
|
||
oChromo.SetImage((LPBYTE)(*Image)->pvData, nImageWidth, nImageHeight);
|
||
oChromo.DoChromoKey(Frame, nHComponent, Threshold);
|
||
|
||
Graphics graphics(&videoBitmap); graphics.SetSmoothingMode(SmoothingModeAntiAlias);
|
||
oChromo.DrawToGraphics(&graphics, TRUE, X1, Y1);
|
||
|
||
ApplyRegister();
|
||
|
||
return S_OK;
|
||
}
|
||
STDMETHODIMP ImageTransform3::DrawText(double Frame, long X1, long Y1, BSTR Text, IUnknown* Font, long Color, long Alpha)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// prepare drawing
|
||
BeginDraw();
|
||
|
||
// create drawing graphics
|
||
Graphics* graphics = Graphics::FromImage(m_pBitmap); graphics->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
|
||
|
||
// create color
|
||
Gdiplus::Color color((BYTE)(Frame*Alpha), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
|
||
// create pen and brush
|
||
PointF point((REAL)X1, (REAL)Y1);
|
||
SolidBrush brush(color);
|
||
|
||
// retrieve screen dc
|
||
HDC dc = GetDC(0);
|
||
|
||
// variables
|
||
Gdiplus::Font* font = 0;
|
||
|
||
// check for valid array
|
||
if (Font)
|
||
{
|
||
// compose font object
|
||
IFont* pFont = 0; Font->QueryInterface(IID_IFont, (void**)&pFont);
|
||
|
||
// check for valid font
|
||
if (!pFont)
|
||
return S_FALSE;
|
||
|
||
// retrieve font handle
|
||
HFONT hfont = 0; pFont->get_hFont(&hfont);
|
||
|
||
// create gdi+ font
|
||
font = new Gdiplus::Font(dc, hfont);
|
||
}
|
||
else
|
||
{
|
||
// create gdi+ font
|
||
font = new Gdiplus::Font(dc);
|
||
}
|
||
|
||
// draw text string
|
||
graphics->DrawString(Text, SysStringLen(Text), font, point, &brush);
|
||
|
||
// stop painting
|
||
graphics->Flush();
|
||
|
||
// release desktop device context
|
||
ReleaseDC(0, dc);
|
||
|
||
// delete objects
|
||
delete graphics;
|
||
delete font;
|
||
|
||
// finalize drawing
|
||
EndDraw();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawText2(double Frame, long X1, long Y1, long X2, long Y2, BSTR Text, IUnknown* Font, long Color, long Alpha)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// chck for very thin rect
|
||
if (abs(X1 - X2) < 2 || abs(Y1 - Y2) < 2)
|
||
{
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// prepare drawing
|
||
BeginDraw();
|
||
|
||
// create drawing graphics
|
||
Graphics* graphics = Graphics::FromImage(m_pBitmap); graphics->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
|
||
|
||
// create color
|
||
Gdiplus::Color color((BYTE)(Frame*Alpha), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
|
||
// create pen and brush
|
||
PointF point((REAL)X1, (REAL)Y1);
|
||
RectF rect((REAL)X1, (REAL)Y1, (REAL)(X2 - X1), (REAL)(Y2 - Y1));
|
||
SolidBrush brush(color);
|
||
StringFormat format;
|
||
|
||
// setup painting format
|
||
format.SetFormatFlags(StringFormatFlagsNoWrap);
|
||
format.SetAlignment(StringAlignmentCenter);
|
||
format.SetLineAlignment(StringAlignmentCenter);
|
||
format.SetTrimming(StringTrimmingNone);
|
||
|
||
// retrieve screen dc
|
||
HDC dc = GetDC(0);
|
||
|
||
// variables
|
||
Gdiplus::Font* font = 0;
|
||
|
||
// check for valid array
|
||
if (Font)
|
||
{
|
||
// compose font object
|
||
IFont* pFont = 0; Font->QueryInterface(IID_IFont, (void**)&pFont);
|
||
|
||
// check for valid font
|
||
if (!pFont)
|
||
return S_FALSE;
|
||
|
||
// retrieve font handle
|
||
HFONT hfont = 0; pFont->get_hFont(&hfont);
|
||
|
||
// create gdi+ font
|
||
font = new Gdiplus::Font(dc, hfont);
|
||
}
|
||
else
|
||
{
|
||
// create gdi+ font
|
||
font = new Gdiplus::Font(dc);
|
||
}
|
||
|
||
// retrieve current logfont
|
||
RectF fontRect;
|
||
|
||
// measure the string
|
||
graphics->MeasureString(Text, SysStringLen(Text), font, point, &fontRect);
|
||
|
||
// update font size
|
||
double scaleX = rect.Width/(double)fontRect.Width;
|
||
double scaleY = rect.Height/(double)fontRect.Height;
|
||
|
||
// apply translation to the device context
|
||
graphics->TranslateTransform(point.X, point.Y);
|
||
graphics->ScaleTransform(scaleX, scaleY);
|
||
|
||
// draw text at start
|
||
point.X = 0;
|
||
point.Y = 0;
|
||
|
||
// draw text string
|
||
graphics->DrawString(Text, SysStringLen(Text), font, point, &brush);
|
||
|
||
// stop painting
|
||
graphics->Flush();
|
||
|
||
// release desktop device context
|
||
ReleaseDC(0, dc);
|
||
|
||
// delete objects
|
||
delete graphics;
|
||
delete font;
|
||
|
||
// finalize drawing
|
||
EndDraw();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawCredits(double Frame, BSTR Text, IUnknown* Font, long Color, long Alpha, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// prepare drawing
|
||
BeginDraw();
|
||
|
||
// create drawing graphics
|
||
Graphics* graphics = Graphics::FromImage(m_pBitmap); graphics->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
|
||
|
||
// retrieve screen dc
|
||
HDC dc = GetDC(0);
|
||
|
||
// variables
|
||
Gdiplus::Font* font = 0;
|
||
|
||
// check for valid array
|
||
if (Font)
|
||
{
|
||
// compose font object
|
||
IFont* pFont = 0; Font->QueryInterface(IID_IFont, (void**)&pFont);
|
||
|
||
// check for valid font
|
||
if (!pFont)
|
||
return S_FALSE;
|
||
|
||
// retrieve font handle
|
||
HFONT hfont = 0; pFont->get_hFont(&hfont);
|
||
|
||
// create gdi+ font
|
||
font = new Gdiplus::Font(dc, hfont);
|
||
}
|
||
else
|
||
{
|
||
// create gdi+ font
|
||
font = new Gdiplus::Font(dc);
|
||
}
|
||
|
||
// compute text size
|
||
PointF start(0, 0);
|
||
RectF layout(0, 0, 0, 0);
|
||
SizeF size; graphics->MeasureString(Text, SysStringLen(Text), font, start, &layout);
|
||
|
||
// variables
|
||
PointF point;
|
||
|
||
// create color
|
||
Gdiplus::Color color((BYTE)Alpha, GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
|
||
// compute advanced colors and positions
|
||
if (Type == c_nCreditsHMWBottom || Type == c_nCreditsHMWCenter || Type == c_nCreditsHMWTop ||
|
||
Type == c_nCreditsVMWLeft || Type == c_nCreditsVMWCenter || Type == c_nCreditsVMWRight)
|
||
{
|
||
if (Frame < 0.25)
|
||
Frame = 2*Frame;
|
||
else if (Frame > 0.75)
|
||
Frame = 0.5 + 2*(Frame - 0.75);
|
||
else
|
||
Frame = 0.5;
|
||
}
|
||
else if (Type == c_nCreditsHMHBottom || Type == c_nCreditsHMHCenter || Type == c_nCreditsHMHTop ||
|
||
Type == c_nCreditsVMHLeft || Type == c_nCreditsVMHCenter || Type == c_nCreditsVMHRight)
|
||
{
|
||
if (Frame > 0.5)
|
||
{
|
||
if (Frame > 0.75)
|
||
color = Gdiplus::Color((BYTE)(Alpha*(1.0 - Frame)/0.25), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
Frame = 0.5;
|
||
}
|
||
}
|
||
else if (Type == c_nCreditsHMSBottom || Type == c_nCreditsHMSCenter || Type == c_nCreditsHMSTop ||
|
||
Type == c_nCreditsVMSLeft || Type == c_nCreditsVMSCenter || Type == c_nCreditsVMSRight)
|
||
{
|
||
Frame *= 0.5;
|
||
}
|
||
else if (Type == c_nCreditsHHMBottom || Type == c_nCreditsHHMCenter || Type == c_nCreditsHHMTop ||
|
||
Type == c_nCreditsVHMLeft || Type == c_nCreditsVHMCenter || Type == c_nCreditsVHMRight)
|
||
{
|
||
if (Frame < 0.5)
|
||
{
|
||
if (Frame < 0.25)
|
||
color = Gdiplus::Color((BYTE)(Alpha*Frame/0.25), GetRValue(Color), GetGValue(Color), GetBValue(Color));
|
||
Frame = 0.5;
|
||
}
|
||
}
|
||
|
||
// create pen and brush
|
||
SolidBrush brush(color);
|
||
|
||
// compute points
|
||
if (Type == c_nCreditsHMMBottom || Type == c_nCreditsHMWBottom || Type == c_nCreditsHMHBottom || Type == c_nCreditsHMSBottom || Type == c_nCreditsHHMBottom)
|
||
{
|
||
point.X = (REAL)((m_nWidth + 1)*(1.0 - Frame) + Frame*(-layout.GetRight() - 1));
|
||
point.Y = (REAL)(m_nHeight - 1 - layout.Height);
|
||
}
|
||
if (Type == c_nCreditsHMMCenter || Type == c_nCreditsHMWCenter || Type == c_nCreditsHMHCenter || Type == c_nCreditsHMSCenter || Type == c_nCreditsHHMCenter)
|
||
{
|
||
point.X = (REAL)((m_nWidth + 1)*(1.0 - Frame) + Frame*(-layout.GetRight() - 1));
|
||
point.Y = (REAL)(0.5*m_nHeight - 0.5*layout.Height);
|
||
}
|
||
if (Type == c_nCreditsHMMTop || Type == c_nCreditsHMWTop || Type == c_nCreditsHMHTop || Type == c_nCreditsHMSTop || Type == c_nCreditsHHMTop)
|
||
{
|
||
point.X = (REAL)((m_nWidth + 1)*(1.0 - Frame) + Frame*(-layout.GetRight() - 1));
|
||
point.Y = (REAL)1;
|
||
}
|
||
if (Type == c_nCreditsVMMLeft || Type == c_nCreditsVMWLeft || Type == c_nCreditsVMHLeft || Type == c_nCreditsVMSLeft || Type == c_nCreditsVHMLeft)
|
||
{
|
||
point.X = (REAL)(1);
|
||
point.Y = (REAL)((m_nHeight + 1)*(1.0 - Frame) + Frame*(-layout.GetBottom() - 1));
|
||
}
|
||
if (Type == c_nCreditsVMMCenter || Type == c_nCreditsVMWCenter || Type == c_nCreditsVMHCenter || Type == c_nCreditsVMSCenter || Type == c_nCreditsVHMCenter)
|
||
{
|
||
point.X = (REAL)(0.5*(m_nWidth - 1) - 0.5*layout.Width);
|
||
point.Y = (REAL)((m_nHeight + 1)*(1.0 - Frame) + Frame*(-layout.GetBottom() - 1));
|
||
}
|
||
if (Type == c_nCreditsVMMRight || Type == c_nCreditsVMWRight || Type == c_nCreditsVMHRight || Type == c_nCreditsVMSRight || Type == c_nCreditsVHMRight)
|
||
{
|
||
point.X = (REAL)(m_nWidth - 1 - layout.Width - 1);
|
||
point.Y = (REAL)((m_nHeight + 1)*(1.0 - Frame) + Frame*(-layout.GetBottom() - 1));
|
||
}
|
||
// draw text string
|
||
graphics->DrawString(Text, SysStringLen(Text), font, point, &brush);
|
||
|
||
// stop painting
|
||
graphics->Flush();
|
||
|
||
// release desktop device context
|
||
ReleaseDC(0, dc);
|
||
|
||
// delete objects
|
||
delete graphics;
|
||
delete font;
|
||
|
||
// finalize drawing
|
||
EndDraw();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP ImageTransform3::DrawBorder(double Frame, long Color, long Size, long Type)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
Size = (int)(Frame*max(0, min(Size, min(m_nHeight/2 - 1, m_nWidth/2 - 1))));
|
||
|
||
// check for simpliest case
|
||
if (Size == 0)
|
||
return S_OK;
|
||
|
||
// variables
|
||
int nImageLeft = 0;
|
||
int nImageTop = 0;
|
||
int nImageRight = m_nWidth - 1;
|
||
int nImageBottom = m_nHeight - 1;
|
||
|
||
// compute image rectangle
|
||
if (Type == c_nBorderSolidAll || Type == c_nBorderGradientLightAll || Type == c_nBorderGradientDarkAll || Type == c_nBorderTransparentAll)
|
||
{
|
||
nImageLeft = Size;
|
||
nImageTop = Size;
|
||
nImageRight = m_nWidth - 1 - Size;
|
||
nImageBottom = m_nHeight - 1 - Size;
|
||
}
|
||
else if (Type == c_nBorderSolidLeft || Type == c_nBorderGradientLightLeft || Type == c_nBorderGradientDarkLeft || Type == c_nBorderTransparentLeft)
|
||
{
|
||
nImageLeft = Size;
|
||
nImageTop = 0;
|
||
nImageRight = m_nWidth - 1;
|
||
nImageBottom = m_nHeight - 1;
|
||
}
|
||
else if (Type == c_nBorderSolidBottom || Type == c_nBorderGradientLightBottom || Type == c_nBorderGradientDarkBottom || Type == c_nBorderTransparentBottom)
|
||
{
|
||
nImageLeft = 0;
|
||
nImageTop = Size;
|
||
nImageRight = m_nWidth - 1;
|
||
nImageBottom = m_nHeight - 1;
|
||
}
|
||
else if (Type == c_nBorderSolidRight || Type == c_nBorderGradientLightRight || Type == c_nBorderGradientDarkRight || Type == c_nBorderTransparentRight)
|
||
{
|
||
nImageLeft = 0;
|
||
nImageTop = 0;
|
||
nImageRight = m_nWidth - 1 - Size;
|
||
nImageBottom = m_nHeight - 1;
|
||
}
|
||
else if (Type == c_nBorderSolidTop || Type == c_nBorderGradientLightTop || Type == c_nBorderGradientDarkTop || Type == c_nBorderTransparentTop)
|
||
{
|
||
nImageLeft = 0;
|
||
nImageTop = 0;
|
||
nImageRight = m_nWidth - 1;
|
||
nImageBottom = m_nHeight - 1 - Size;
|
||
}
|
||
else if (Type == c_nBorderSolidLeftRight || Type == c_nBorderGradientLightLeftRight || Type == c_nBorderGradientDarkLeftRight || Type == c_nBorderTransparentLeftRight)
|
||
{
|
||
nImageLeft = Size;
|
||
nImageTop = 0;
|
||
nImageRight = m_nWidth - 1 - Size;
|
||
nImageBottom = m_nHeight - 1;
|
||
}
|
||
else if (Type == c_nBorderSolidTopBottom || Type == c_nBorderGradientLightTopBottom || Type == c_nBorderGradientDarkTopBottom || Type == c_nBorderTransparentTopBottom)
|
||
{
|
||
nImageLeft = 0;
|
||
nImageTop = Size;
|
||
nImageRight = m_nWidth - 1;
|
||
nImageBottom = m_nHeight - 1 - Size;
|
||
}
|
||
|
||
// variables
|
||
int nX, nY, nIndex = 0;
|
||
double dSourceX, dSourceY, dAlpha;
|
||
BYTE nR1, nG1, nB1, nR2, nG2, nB2, nR3, nG3, nB3;
|
||
|
||
// compute border color components
|
||
BYTE nBR = GetRValue(Color);
|
||
BYTE nBG = GetGValue(Color);
|
||
BYTE nBB = GetBValue(Color);
|
||
BYTE nBLR = Byte(nBR + 128);
|
||
BYTE nBLG = Byte(nBG + 128);
|
||
BYTE nBLB = Byte(nBB + 128);
|
||
BYTE nBDR = Byte(nBR - 128);
|
||
BYTE nBDG = Byte(nBG - 128);
|
||
BYTE nBDB = Byte(nBB - 128);
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// check for simpliest case
|
||
if (Type < c_nBorderTransparentAll || Type > c_nBorderTransparentTopBottom)
|
||
{
|
||
// draw one image inside another
|
||
for (nY = nImageTop; nY <= nImageBottom; ++nY)
|
||
{
|
||
// compute y coordinate
|
||
dSourceY = min(m_nHeight - 0.001, m_nHeight*(nY - nImageTop)/(double)(nImageBottom - nImageTop));
|
||
|
||
for (nX = nImageLeft; nX <= nImageRight; ++nX)
|
||
{
|
||
// compute x coordinate
|
||
dSourceX = min(m_nWidth - 0.001, m_nWidth*(nX - nImageLeft)/(double)(nImageRight - nImageLeft));
|
||
|
||
// check for valid destination coordinates
|
||
if (nX < 0 || nX >= m_nWidth || nY < 0 || nY >= m_nHeight)
|
||
continue;
|
||
|
||
// compute source pixel index
|
||
nIndex = 4*(nX + nY*m_nWidth);
|
||
|
||
// copy pixels
|
||
m_pPixels[nIndex + 0] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 0, 4, 0);
|
||
m_pPixels[nIndex + 1] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 1, 4, 0);
|
||
m_pPixels[nIndex + 2] = GetPointBillinear(dSourceX, dSourceY, m_pBackup, m_nWidth, m_nHeight, 2, 4, 0);
|
||
}
|
||
}
|
||
}
|
||
|
||
// draw border
|
||
for (nY = 0, nIndex = 0; nY < m_nHeight; ++nY)
|
||
{
|
||
for (nX = 0; nX < m_nWidth; ++nX, nIndex += 4)
|
||
{
|
||
if (nX >= nImageLeft && nY >= nImageTop && nX <= nImageRight && nY <= nImageBottom)
|
||
continue;
|
||
|
||
// solid
|
||
if (Type == c_nBorderSolidAll || Type == c_nBorderSolidLeft || Type == c_nBorderSolidTop || Type == c_nBorderSolidRight || Type == c_nBorderSolidBottom || Type == c_nBorderSolidLeftRight || Type == c_nBorderSolidTopBottom)
|
||
{
|
||
m_pPixels[nIndex + 0] = nBB;
|
||
m_pPixels[nIndex + 1] = nBG;
|
||
m_pPixels[nIndex + 2] = nBR;
|
||
}
|
||
|
||
// gradients
|
||
if (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightLeft || Type == c_nBorderGradientLightLeftRight || Type == c_nBorderGradientDarkAll || Type == c_nBorderGradientDarkLeft || Type == c_nBorderGradientDarkLeftRight)
|
||
{
|
||
nR3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightLeft || Type == c_nBorderGradientLightLeftRight) ? nBLR : nBDR;
|
||
nG3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightLeft || Type == c_nBorderGradientLightLeftRight) ? nBLG : nBDG;
|
||
nB3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightLeft || Type == c_nBorderGradientLightLeftRight) ? nBLB : nBDB;
|
||
|
||
if (nX < nImageLeft)
|
||
{
|
||
nR1 = Byte(nBR + (nR3 - nBR)*nX/(double)Size);
|
||
nG1 = Byte(nBG + (nG3 - nBG)*nX/(double)Size);
|
||
nB1 = Byte(nBB + (nB3 - nBB)*nX/(double)Size);
|
||
|
||
if (nY < nImageTop)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*nY/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*nY/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*nY/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = (nX < nY) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = (nX < nY) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = (nX < nY) ? nB1 : nB2;
|
||
}
|
||
else if (nY > nImageBottom)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*(m_nHeight - 1 - nY)/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*(m_nHeight - 1 - nY)/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*(m_nHeight - 1 - nY)/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = (nX < (m_nHeight - 1 - nY)) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = (nX < (m_nHeight - 1 - nY)) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = (nX < (m_nHeight - 1 - nY)) ? nB1 : nB2;
|
||
}
|
||
else
|
||
{
|
||
m_pPixels[nIndex + 2] = nR1;
|
||
m_pPixels[nIndex + 1] = nG1;
|
||
m_pPixels[nIndex + 0] = nB1;
|
||
}
|
||
}
|
||
}
|
||
if (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightRight || Type == c_nBorderGradientLightLeftRight || Type == c_nBorderGradientDarkAll || Type == c_nBorderGradientDarkRight || Type == c_nBorderGradientDarkLeftRight)
|
||
{
|
||
nR3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightRight || Type == c_nBorderGradientLightLeftRight) ? nBLR : nBDR;
|
||
nG3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightRight || Type == c_nBorderGradientLightLeftRight) ? nBLG : nBDG;
|
||
nB3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightRight || Type == c_nBorderGradientLightLeftRight) ? nBLB : nBDB;
|
||
|
||
if (nX > nImageRight)
|
||
{
|
||
nR1 = Byte(nBR + (nR3 - nBR)*(m_nWidth - 1 - nX)/(double)Size);
|
||
nG1 = Byte(nBG + (nG3 - nBG)*(m_nWidth - 1 - nX)/(double)Size);
|
||
nB1 = Byte(nBB + (nB3 - nBB)*(m_nWidth - 1 - nX)/(double)Size);
|
||
|
||
if (nY < nImageTop)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*nY/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*nY/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*nY/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = ((m_nWidth - 1 - nX) < nY) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = ((m_nWidth - 1 - nX) < nY) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = ((m_nWidth - 1 - nX) < nY) ? nB1 : nB2;
|
||
}
|
||
else if (nY > nImageBottom)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*(m_nHeight - 1 - nY)/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*(m_nHeight - 1 - nY)/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*(m_nHeight - 1 - nY)/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = ((m_nWidth - 1 - nX) < (m_nHeight - 1 - nY)) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = ((m_nWidth - 1 - nX) < (m_nHeight - 1 - nY)) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = ((m_nWidth - 1 - nX) < (m_nHeight - 1 - nY)) ? nB1 : nB2;
|
||
}
|
||
else
|
||
{
|
||
m_pPixels[nIndex + 2] = nR1;
|
||
m_pPixels[nIndex + 1] = nG1;
|
||
m_pPixels[nIndex + 0] = nB1;
|
||
}
|
||
}
|
||
}
|
||
if (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightBottom || Type == c_nBorderGradientLightTopBottom || Type == c_nBorderGradientDarkAll || Type == c_nBorderGradientDarkBottom || Type == c_nBorderGradientDarkTopBottom)
|
||
{
|
||
nR3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightBottom || Type == c_nBorderGradientLightTopBottom) ? nBLR : nBDR;
|
||
nG3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightBottom || Type == c_nBorderGradientLightTopBottom) ? nBLG : nBDG;
|
||
nB3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightBottom || Type == c_nBorderGradientLightTopBottom) ? nBLB : nBDB;
|
||
|
||
if (nY < nImageTop)
|
||
{
|
||
nR1 = Byte(nBR + (nR3 - nBR)*nY/(double)Size);
|
||
nG1 = Byte(nBG + (nG3 - nBG)*nY/(double)Size);
|
||
nB1 = Byte(nBB + (nB3 - nBB)*nY/(double)Size);
|
||
|
||
if (nX < nImageLeft)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*nX/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*nX/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*nX/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = (nY < nX) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = (nY < nX) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = (nY < nX) ? nB1 : nB2;
|
||
}
|
||
else if (nX > nImageRight)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*(m_nWidth - 1 - nX)/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*(m_nWidth - 1 - nX)/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*(m_nWidth - 1 - nX)/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = (nY < (m_nWidth - 1 - nX)) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = (nY < (m_nWidth - 1 - nX)) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = (nY < (m_nWidth - 1 - nX)) ? nB1 : nB2;
|
||
}
|
||
else
|
||
{
|
||
m_pPixels[nIndex + 2] = nR1;
|
||
m_pPixels[nIndex + 1] = nG1;
|
||
m_pPixels[nIndex + 0] = nB1;
|
||
}
|
||
}
|
||
}
|
||
if (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightTop || Type == c_nBorderGradientLightTopBottom || Type == c_nBorderGradientDarkAll || Type == c_nBorderGradientDarkTop || Type == c_nBorderGradientDarkTopBottom)
|
||
{
|
||
nR3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightTop || Type == c_nBorderGradientLightTopBottom) ? nBLR : nBDR;
|
||
nG3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightTop || Type == c_nBorderGradientLightTopBottom) ? nBLG : nBDG;
|
||
nB3 = (Type == c_nBorderGradientLightAll || Type == c_nBorderGradientLightTop || Type == c_nBorderGradientLightTopBottom) ? nBLB : nBDB;
|
||
|
||
if (nY > nImageBottom)
|
||
{
|
||
nR1 = Byte(nBR + (nR3 - nBR)*(m_nHeight - 1 - nY)/(double)Size);
|
||
nG1 = Byte(nBG + (nG3 - nBG)*(m_nHeight - 1 - nY)/(double)Size);
|
||
nB1 = Byte(nBB + (nB3 - nBB)*(m_nHeight - 1 - nY)/(double)Size);
|
||
|
||
if (nX < nImageLeft)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*nX/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*nX/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*nX/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = ((m_nHeight - 1 - nY) < nX) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = ((m_nHeight - 1 - nY) < nX) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = ((m_nHeight - 1 - nY) < nX) ? nB1 : nB2;
|
||
}
|
||
else if (nX > nImageRight)
|
||
{
|
||
nR2 = Byte(nBR + (nR3 - nBR)*(m_nWidth - 1 - nX)/(double)Size);
|
||
nG2 = Byte(nBG + (nG3 - nBG)*(m_nWidth - 1 - nX)/(double)Size);
|
||
nB2 = Byte(nBB + (nB3 - nBB)*(m_nWidth - 1 - nX)/(double)Size);
|
||
|
||
m_pPixels[nIndex + 2] = ((m_nHeight - 1 - nY) < (m_nWidth - 1 - nX)) ? nR1 : nR2;
|
||
m_pPixels[nIndex + 1] = ((m_nHeight - 1 - nY) < (m_nWidth - 1 - nX)) ? nG1 : nG2;
|
||
m_pPixels[nIndex + 0] = ((m_nHeight - 1 - nY) < (m_nWidth - 1 - nX)) ? nB1 : nB2;
|
||
}
|
||
else
|
||
{
|
||
m_pPixels[nIndex + 2] = nR1;
|
||
m_pPixels[nIndex + 1] = nG1;
|
||
m_pPixels[nIndex + 0] = nB1;
|
||
}
|
||
}
|
||
}
|
||
|
||
// transparency
|
||
if (Type == c_nBorderTransparentAll || Type == c_nBorderTransparentLeft || Type == c_nBorderTransparentLeftRight)
|
||
{
|
||
if (nX < nImageLeft)
|
||
{
|
||
if (nY < nImageTop && nX >= nY)
|
||
{
|
||
if (nY > 0.5*Size)
|
||
{
|
||
dAlpha = (nY - 0.5*Size)/(0.5*Size);
|
||
}
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else if (nY > nImageBottom && nX >= (m_nHeight - 1 - nY))
|
||
{
|
||
if ((m_nHeight - 1 - nY) > 0.5*Size)
|
||
dAlpha = (m_nHeight - 1 - nY - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else
|
||
{
|
||
if (nX > 0.5*Size)
|
||
dAlpha = (nX - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha*m_pBackup[nIndex + 0] + (1.0 - dAlpha)*nBB);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha*m_pBackup[nIndex + 1] + (1.0 - dAlpha)*nBG);
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha*m_pBackup[nIndex + 2] + (1.0 - dAlpha)*nBR);
|
||
}
|
||
}
|
||
if (Type == c_nBorderTransparentAll || Type == c_nBorderTransparentRight || Type == c_nBorderTransparentLeftRight)
|
||
{
|
||
if (nX > nImageRight)
|
||
{
|
||
if (nY < nImageTop && (m_nWidth - 1 - nX) >= nY)
|
||
{
|
||
if (nY > 0.5*Size)
|
||
{
|
||
dAlpha = (nY - 0.5*Size)/(0.5*Size);
|
||
}
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else if (nY > nImageBottom && (m_nWidth - 1 - nX) >= (m_nHeight - 1 - nY))
|
||
{
|
||
if ((m_nHeight - 1 - nY) > 0.5*Size)
|
||
dAlpha = (m_nHeight - 1 - nY - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else
|
||
{
|
||
if ((m_nWidth - 1 - nX) > 0.5*Size)
|
||
dAlpha = ((m_nWidth - 1 - nX) - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha*m_pBackup[nIndex + 0] + (1.0 - dAlpha)*nBB);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha*m_pBackup[nIndex + 1] + (1.0 - dAlpha)*nBG);
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha*m_pBackup[nIndex + 2] + (1.0 - dAlpha)*nBR);
|
||
}
|
||
}
|
||
if (Type == c_nBorderTransparentAll || Type == c_nBorderTransparentTop || Type == c_nBorderTransparentTopBottom)
|
||
{
|
||
if (nY > nImageBottom)
|
||
{
|
||
if (nX < nImageLeft && (m_nHeight - 1 - nY) >= nX)
|
||
{
|
||
if (nX > 0.5*Size)
|
||
{
|
||
dAlpha = (nX - 0.5*Size)/(0.5*Size);
|
||
}
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else if (nX > nImageRight && (m_nHeight - 1 - nY) >= (m_nWidth - 1 - nX))
|
||
{
|
||
if ((m_nWidth - 1 - nX) > 0.5*Size)
|
||
dAlpha = (m_nWidth - 1 - nX - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else
|
||
{
|
||
if ((m_nHeight - 1 - nY) > 0.5*Size)
|
||
dAlpha = ((m_nHeight - 1 - nY) - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha*m_pBackup[nIndex + 0] + (1.0 - dAlpha)*nBB);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha*m_pBackup[nIndex + 1] + (1.0 - dAlpha)*nBG);
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha*m_pBackup[nIndex + 2] + (1.0 - dAlpha)*nBR);
|
||
}
|
||
}
|
||
if (Type == c_nBorderTransparentAll || Type == c_nBorderTransparentBottom || Type == c_nBorderTransparentTopBottom)
|
||
{
|
||
if (nY < nImageTop)
|
||
{
|
||
if (nX < nImageLeft && nY >= nX)
|
||
{
|
||
if (nX > 0.5*Size)
|
||
{
|
||
dAlpha = (nX - 0.5*Size)/(0.5*Size);
|
||
}
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else if (nX > nImageRight && nY >= (m_nWidth - 1 - nX))
|
||
{
|
||
if ((m_nWidth - 1 - nX) > 0.5*Size)
|
||
dAlpha = (m_nWidth - 1 - nX - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
else
|
||
{
|
||
if (nY > 0.5*Size)
|
||
dAlpha = (nY - 0.5*Size)/(0.5*Size);
|
||
else
|
||
dAlpha = 0;
|
||
}
|
||
|
||
m_pPixels[nIndex + 0] = (BYTE)(dAlpha*m_pBackup[nIndex + 0] + (1.0 - dAlpha)*nBB);
|
||
m_pPixels[nIndex + 1] = (BYTE)(dAlpha*m_pBackup[nIndex + 1] + (1.0 - dAlpha)*nBG);
|
||
m_pPixels[nIndex + 2] = (BYTE)(dAlpha*m_pBackup[nIndex + 2] + (1.0 - dAlpha)*nBR);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
STDMETHODIMP ImageTransform3::DrawMovObject(double Frame, long Type, long Divisions, long Color, long Alpha)
|
||
{
|
||
// check for valid image
|
||
if (!IsValid())
|
||
return S_FALSE;
|
||
|
||
// clamp values
|
||
Frame = Clamp(Frame);
|
||
|
||
// begin effect
|
||
BeginEffect();
|
||
|
||
// compose size
|
||
m_nSizeX = m_nWidth/max(1, min(m_nWidth/4, Divisions));
|
||
m_nSizeY = m_nHeight/max(1, min(m_nHeight/4, Divisions));
|
||
|
||
// apply effect
|
||
ApplyCompose(Frame, Type, Color, Alpha);
|
||
|
||
// finalize effect
|
||
EndEffect();
|
||
|
||
// apply registration
|
||
ApplyRegister();
|
||
|
||
// all ok
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|