protected override unsafe void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData )
{
int pixelSize = Bitmap.GetPixelFormatSize( destinationData.PixelFormat ) / 8;
// get source image size
int width = sourceData.Width;
int height = sourceData.Height;
int widthM1 = width - 1;
int heightM1 = height - 1;
// get destination image size
int newWidth = destinationData.Width;
int newHeight = destinationData.Height;
int newWidthM1 = newWidth - 1;
int newHeightM1 = newHeight - 1;
// invert cirlce depth
double circleDisform = 1 - circleDepth;
// get position of center pixel
double cx = (double) widthM1 / 2;
double cy = (double) heightM1 / 2;
double radius = ( cx < cy ) ? cx : cy;
radius -= radius * circleDisform;
// angle of the diagonal
double diagonalAngle = Math.Atan2( cy, cx );
// offset angle in radians
double offsetAngleR = ( ( mapBackwards ) ? offsetAngle : -offsetAngle ) / 180 * Math.PI + PiHalf;
// do the job
byte* baseSrc = (byte*) sourceData.ImageData.ToPointer( );
byte* dst = (byte*) destinationData.ImageData.ToPointer( );
int srcStride = sourceData.Stride;
int dstOffset = destinationData.Stride - newWidth * pixelSize;
// coordinates of source points
int sx1, sy1, sx2, sy2;
double dx1, dy1, dx2, dy2;
// temporary pointers
byte* p1, p2, p3, p4;
// precalculate Sin/Cos values and distances from center to edge in the source image
double[] angleCos = new double[newWidth];
double[] angleSin = new double[newWidth];
double[] maxDistance = new double[newWidth];
for ( int x = 0; x < newWidth; x++ )
{
double angle = -Pi2 * x / newWidth + offsetAngleR;
angleCos[x] = Math.Cos( angle );
angleSin[x] = Math.Sin( angle );
// calculate minimum angle between X axis and the
// line with the above calculated angle
double oxAngle = ( ( angle > 0 ) ? angle : -angle ) % Math.PI;
if ( oxAngle > PiHalf )
{
oxAngle = Math.PI - oxAngle;
}
// calculate maximm distance from center for this angle - distance to image's edge
maxDistance[x] = circleDisform * ( ( oxAngle > diagonalAngle ) ? ( cy / Math.Sin( oxAngle ) ) : ( cx / Math.Cos( oxAngle ) ) );
}
for ( int y = 0; y < newHeight; y++ )
{
double yPart = (double) y / newHeightM1;
if ( !mapFromTop )
{
yPart = 1 - yPart;
}
for ( int x = 0; x < newWidth; x++ )
{
// calculate maximum allowed distance within wich we need to map Y axis of the destination image
double maxAllowedDistance = radius + maxDistance[x];
// source pixel's distance from the center of the source image
double distance = yPart * maxAllowedDistance;
// calculate pixel coordinates in the source image
double sx = cx + distance * ( ( mapBackwards ) ? -angleCos[x] : angleCos[x] );
double sy = cy - distance * angleSin[x];
sx1 = (int) sx;
sy1 = (int) sy;
sx2 = ( sx1 == widthM1 ) ? sx1 : sx1 + 1;
dx1 = sx - sx1;
dx2 = 1.0 - dx1;
sy2 = ( sy1 == heightM1 ) ? sy1 : sy1 + 1;
dy1 = sy - 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 ) ) );
}
}
dst += dstOffset;
}
}
}