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 kTop, bTop;
double kBottom, bBottom;
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;
}
}
}
}
}
}