private unsafe void ProcessFilter8bpc(UnmanagedImage sourceData, UnmanagedImage destinationData)
{
// get source image size
int width = sourceData.Width;
int height = sourceData.Height;
double oldXradius = (double)(width - 1) / 2;
double oldYradius = (double)(height - 1) / 2;
// get destination image size
int newWidth = destinationData.Width;
int newHeight = destinationData.Height;
double newXradius = (double)(newWidth - 1) / 2;
double newYradius = (double)(newHeight - 1) / 2;
// angle's sine and cosine
double angleRad = -angle * Math.PI / 180;
double angleCos = Math.Cos(angleRad);
double angleSin = Math.Sin(angleRad);
int srcStride = sourceData.Stride;
int dstOffset = destinationData.Stride -
((destinationData.PixelFormat == PixelFormat.Format8bppIndexed) ? newWidth : newWidth * 3);
// fill values
byte fillA = fillColor.A;
byte fillR = fillColor.R;
byte fillG = fillColor.G;
byte fillB = fillColor.B;
// do the job
byte* src = (byte*)sourceData.ImageData.ToPointer();
byte* dst = (byte*)destinationData.ImageData.ToPointer();
// destination pixel's coordinate relative to image center
double cx, cy;
// source pixel's coordinates
int ox, oy;
// temporary pointer
byte* p;
// check pixel format
if (destinationData.PixelFormat == PixelFormat.Format8bppIndexed)
{
// grayscale
cy = -newYradius;
for (int y = 0; y < newHeight; y++)
{
cx = -newXradius;
for (int x = 0; x < newWidth; x++, dst++)
{
// coordinate of the nearest point
ox = (int)(angleCos * cx + angleSin * cy + oldXradius);
oy = (int)(-angleSin * cx + angleCos * cy + oldYradius);
// validate source pixel's coordinates
if ((ox < 0) || (oy < 0) || (ox >= width) || (oy >= height))
{
// fill destination image with filler
*dst = fillG;
}
else
{
// fill destination image with pixel from source image
*dst = src[oy * srcStride + ox];
}
cx++;
}
cy++;
dst += dstOffset;
}
}
else if (destinationData.PixelFormat == PixelFormat.Format24bppRgb
|| destinationData.PixelFormat == PixelFormat.Format32bppRgb)
{
// RGB
cy = -newYradius;
for (int y = 0; y < newHeight; y++)
{
cx = -newXradius;
for (int x = 0; x < newWidth; x++, dst += 3)
{
// coordinate of the nearest point
ox = (int)(angleCos * cx + angleSin * cy + oldXradius);
oy = (int)(-angleSin * cx + angleCos * cy + oldYradius);
// validate source pixel's coordinates
if ((ox < 0) || (oy < 0) || (ox >= width) || (oy >= height))
{
// fill destination image with filler
dst[RGB.R] = fillR;
dst[RGB.G] = fillG;
dst[RGB.B] = fillB;
}
else
{
// fill destination image with pixel from source image
p = src + oy * srcStride + ox * 3;
dst[RGB.R] = p[RGB.R];
dst[RGB.G] = p[RGB.G];
dst[RGB.B] = p[RGB.B];
}
cx++;
}
cy++;
dst += dstOffset;
}
}
else if (destinationData.PixelFormat == PixelFormat.Format32bppArgb)
{
// ARGB
cy = -newYradius;
for (int y = 0; y < newHeight; y++)
{
cx = -newXradius;
for (int x = 0; x < newWidth; x++, dst += 3)
{
// coordinate of the nearest point
ox = (int)(angleCos * cx + angleSin * cy + oldXradius);
oy = (int)(-angleSin * cx + angleCos * cy + oldYradius);
// validate source pixel's coordinates
if ((ox < 0) || (oy < 0) || (ox >= width) || (oy >= height))
{
// fill destination image with filler
dst[RGB.A] = fillA;
dst[RGB.R] = fillR;
dst[RGB.G] = fillG;
dst[RGB.B] = fillB;
}
else
{
// fill destination image with pixel from source image
p = src + oy * srcStride + ox * 3;
dst[RGB.A] = p[RGB.A];
dst[RGB.R] = p[RGB.R];
dst[RGB.G] = p[RGB.G];
dst[RGB.B] = p[RGB.B];
}
cx++;
}
cy++;
dst += dstOffset;
}
}
else
{
throw new UnsupportedImageFormatException();
}
}