protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData)
{
// get source and destination images size
int srcWidth = sourceData.Width;
int srcHeight = sourceData.Height;
int dstWidth = destinationData.Width;
int dstHeight = destinationData.Height;
int pixelSize = Image.GetPixelFormatSize(sourceData.PixelFormat) / 8;
int srcStride = sourceData.Stride;
int dstStride = destinationData.Stride;
// find equations of four quadrilateral's edges ( f(x) = k*x + b )
double kLeft, bLeft;
double kRight, bRight;
/*
// top edge
if (sourceQuadrilateral[1].X == sourceQuadrilateral[0].X)
{
kTop = 0;
bTop = sourceQuadrilateral[1].X;
}
else
{
kTop = (double)(sourceQuadrilateral[1].Y - sourceQuadrilateral[0].Y) /
(sourceQuadrilateral[1].X - sourceQuadrilateral[0].X);
bTop = (double) sourceQuadrilateral[0].Y - kTop * sourceQuadrilateral[0].X;
}
// bottom edge
if (sourceQuadrilateral[2].X == sourceQuadrilateral[3].X)
{
kBottom = 0;
bBottom = sourceQuadrilateral[2].X;
}
else
{
kBottom = (double)(sourceQuadrilateral[2].Y - sourceQuadrilateral[3].Y) /
(sourceQuadrilateral[2].X - sourceQuadrilateral[3].X);
bBottom = (double) sourceQuadrilateral[3].Y - kBottom * sourceQuadrilateral[3].X;
}
*/
// left edge
if (sourceQuadrilateral[3].X == sourceQuadrilateral[0].X)
{
kLeft = 0;
bLeft = sourceQuadrilateral[3].X;
}
else
{
kLeft = (double)(sourceQuadrilateral[3].Y - sourceQuadrilateral[0].Y) /
(sourceQuadrilateral[3].X - sourceQuadrilateral[0].X);
bLeft = (double)sourceQuadrilateral[0].Y - kLeft * sourceQuadrilateral[0].X;
}
// right edge
if (sourceQuadrilateral[2].X == sourceQuadrilateral[1].X)
{
kRight = 0;
bRight = sourceQuadrilateral[2].X;
}
else
{
kRight = (double)(sourceQuadrilateral[2].Y - sourceQuadrilateral[1].Y) /
(sourceQuadrilateral[2].X - sourceQuadrilateral[1].X);
bRight = (double)sourceQuadrilateral[1].Y - kRight * sourceQuadrilateral[1].X;
}
// some precalculated values
double leftFactor = (double)(sourceQuadrilateral[3].Y - sourceQuadrilateral[0].Y) / dstHeight;
double rightFactor = (double)(sourceQuadrilateral[2].Y - sourceQuadrilateral[1].Y) / dstHeight;
int srcY0 = sourceQuadrilateral[0].Y;
int srcY1 = sourceQuadrilateral[1].Y;
// do the job
byte* baseSrc = (byte*)sourceData.ImageData.ToPointer();
byte* baseDst = (byte*)destinationData.ImageData.ToPointer();
// source width and height decreased by 1
int ymax = srcHeight - 1;
int xmax = srcWidth - 1;
// coordinates of source points
double dx1, dy1, dx2, dy2;
int sx1, sy1, sx2, sy2;
// temporary pointers
byte* p1, p2, p3, p4, p;
// for each line
for (int y = 0; y < dstHeight; y++)
{
byte* dst = baseDst + dstStride * y;
// find corresponding Y on the left edge of the quadrilateral
double yHorizLeft = leftFactor * y + srcY0;
// find corresponding X on the left edge of the quadrilateral
double xHorizLeft = (kLeft == 0) ? bLeft : (yHorizLeft - bLeft) / kLeft;
// find corresponding Y on the right edge of the quadrilateral
double yHorizRight = rightFactor * y + srcY1;
// find corresponding X on the left edge of the quadrilateral
double xHorizRight = (kRight == 0) ? bRight : (yHorizRight - bRight) / kRight;
// find equation of the line joining points on the left and right edges
double kHoriz, bHoriz;
if (xHorizLeft == xHorizRight)
{
kHoriz = 0;
bHoriz = xHorizRight;
}
else
{
kHoriz = (yHorizRight - yHorizLeft) / (xHorizRight - xHorizLeft);
bHoriz = yHorizLeft - kHoriz * xHorizLeft;
}
double horizFactor = (xHorizRight - xHorizLeft) / dstWidth;
if (!useInterpolation)
{
for (int x = 0; x < dstWidth; x++)
{
double xs = horizFactor * x + xHorizLeft;
double ys = kHoriz * xs + bHoriz;
if ((xs >= 0) && (ys >= 0) && (xs < srcWidth) && (ys < srcHeight))
{
// get pointer to the pixel in the source image
p = baseSrc + ((int)ys * srcStride + (int)xs * pixelSize);
// copy pixel's values
for (int i = 0; i < pixelSize; i++, dst++, p++)
{
*dst = *p;
}
}
else
{
dst += pixelSize;
}
}
}
else
{
for (int x = 0; x < dstWidth; x++)
{
double xs = horizFactor * x + xHorizLeft;
double ys = kHoriz * xs + bHoriz;
if ((xs >= 0) && (ys >= 0) && (xs < srcWidth) && (ys < srcHeight))
{
sx1 = (int)xs;
sx2 = (sx1 == xmax) ? sx1 : sx1 + 1;
dx1 = xs - sx1;
dx2 = 1.0 - dx1;
sy1 = (int)ys;
sy2 = (sy1 == ymax) ? sy1 : sy1 + 1;
dy1 = ys - sy1;
dy2 = 1.0 - dy1;
// get four points
p1 = p2 = baseSrc + sy1 * srcStride;
p1 += sx1 * pixelSize;
p2 += sx2 * pixelSize;
p3 = p4 = baseSrc + sy2 * srcStride;
p3 += sx1 * pixelSize;
p4 += sx2 * pixelSize;
// interpolate using 4 points
for (int i = 0; i < pixelSize; i++, dst++, p1++, p2++, p3++, p4++)
{
*dst = (byte)(
dy2 * (dx2 * (*p1) + dx1 * (*p2)) +
dy1 * (dx2 * (*p3) + dx1 * (*p4)));
}
}
else
{
dst += pixelSize;
}
}
}
}
}
}