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 newHeightM1 = newHeight - 1;
// invert circle 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 maximum 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;
}
}
}