protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData)
{
// get source image dimension
int width = sourceData.Width;
int height = sourceData.Height;
// if generator was specified, then generate a texture
// otherwise use provided texture
if (textureGenerator != null)
{
texture = textureGenerator.Generate(width, height);
}
else
{
// check existing texture
if ((texture.GetLength(0) != height) || (texture.GetLength(1) != width))
{
// sorry, but source image must have the same dimension as texture
throw new InvalidImagePropertiesException("Texture size does not match image size.");
}
}
// apply first filter
UnmanagedImage filteredImage1 = filter1.Apply(sourceData);
// check size of the result image
if ((width != filteredImage1.Width) || (height != filteredImage1.Height))
{
filteredImage1.Dispose();
throw new InvalidOperationException("Filters should not change image dimension.");
}
// convert 1st image to RGB if required
if (filteredImage1.PixelFormat == PixelFormat.Format8bppIndexed)
{
GrayscaleToRGB coloringFilter = new GrayscaleToRGB();
UnmanagedImage temp = coloringFilter.Apply(filteredImage1);
filteredImage1.Dispose();
filteredImage1 = temp;
}
UnmanagedImage filteredImage2 = null;
// apply second filter, if it was specified
if (filter2 != null)
{
filteredImage2 = filter2.Apply(sourceData);
// check size of the result image
if ((width != filteredImage2.Width) || (height != filteredImage2.Height))
{
filteredImage1.Dispose();
filteredImage2.Dispose();
// we are not handling such situations yet
throw new InvalidOperationException("Filters should not change image dimension.");
}
// convert 2nd image to RGB if required
if (filteredImage2.PixelFormat == PixelFormat.Format8bppIndexed)
{
GrayscaleToRGB coloringFilter = new GrayscaleToRGB();
UnmanagedImage temp = coloringFilter.Apply(filteredImage2);
filteredImage2.Dispose();
filteredImage2 = temp;
}
}
// use source image as a second image, if second filter is not set
if (filteredImage2 == null)
{
filteredImage2 = sourceData;
}
// do the job
unsafe
{
byte* dst = (byte*)destinationData.ImageData.ToPointer();
byte* src1 = (byte*)filteredImage1.ImageData.ToPointer();
byte* src2 = (byte*)filteredImage2.ImageData.ToPointer();
int dstOffset = destinationData.Stride - 3 * width;
int src1Offset = filteredImage1.Stride - 3 * width;
int src2Offset = filteredImage2.Stride - 3 * width;
if (preserveLevel != 0.0)
{
// for each line
for (int y = 0; y < height; y++)
{
// for each pixel
for (int x = 0; x < width; x++)
{
double t1 = texture[y, x];
double t2 = 1 - t1;
for (int i = 0; i < 3; i++, src1++, src2++, dst++)
{
*dst = (byte)Math.Min(255.0f,
filterLevel * (t1 * (*src1) + t2 * (*src2)) +
preserveLevel * (*src2));
}
}
src1 += src1Offset;
src2 += src2Offset;
dst += dstOffset;
}
}
else
{
// for each line
for (int y = 0; y < height; y++)
{
// for each pixel
for (int x = 0; x < width; x++)
{
double t1 = texture[y, x];
double t2 = 1 - t1;
for (int i = 0; i < 3; i++, src1++, src2++, dst++)
{
*dst = (byte)Math.Min(255.0f, t1 * *src1 + t2 * *src2);
}
}
src1 += src1Offset;
src2 += src2Offset;
dst += dstOffset;
}
}
}
// dispose temp images
filteredImage1.Dispose();
if (filteredImage2 != sourceData)
{
filteredImage2.Dispose();
}
}
}