private unsafe void ProcessImage(UnmanagedImage image, Rectangle rect, byte* mask, int maskLineSize)
{
// apply base filter to the specified image
UnmanagedImage filteredImage = baseFilter.Apply(image);
if ((image.Width != filteredImage.Width) ||
(image.Height != filteredImage.Height))
{
throw new ArgumentException("Base filter must not change image size.");
}
int pixelSize = Bitmap.GetPixelFormatSize(image.PixelFormat) / 8;
int startY = rect.Top;
int stopY = startY + rect.Height;
int startX = rect.Left;
int stopX = startX + rect.Width;
int srcStride = image.Stride;
int filteredStride = filteredImage.Stride;
int maskOffset = maskLineSize - rect.Width;
// allign mask to the first pixel
mask += maskLineSize * startY + startX;
if ((pixelSize <= 4) && (pixelSize != 2))
{
// 8 bits per channel
byte* imagePtr = (byte*)image.ImageData.ToPointer() +
srcStride * startY + pixelSize * startX;
int srcOffset = srcStride - rect.Width * pixelSize;
byte* filteredPtr = (byte*)filteredImage.ImageData.ToPointer() +
filteredStride * startY + pixelSize * startX;
int filteredOffset = filteredStride - rect.Width * pixelSize;
#region 8 bit cases
switch (pixelSize)
{
case 1:
// 8 bpp grayscale
for (int y = startY; y < stopY; y++)
{
for (int x = startX; x < stopX; x++, imagePtr++, filteredPtr++, mask++)
{
if (*mask != 0)
{
*imagePtr = *filteredPtr;
}
}
imagePtr += srcOffset;
filteredPtr += filteredOffset;
mask += maskOffset;
}
break;
case 3:
// 24 bpp color
for (int y = startY; y < stopY; y++)
{
for (int x = startX; x < stopX; x++, imagePtr += 3, filteredPtr += 3, mask++)
{
if (*mask != 0)
{
imagePtr[RGB.R] = filteredPtr[RGB.R];
imagePtr[RGB.G] = filteredPtr[RGB.G];
imagePtr[RGB.B] = filteredPtr[RGB.B];
}
}
imagePtr += srcOffset;
filteredPtr += filteredOffset;
mask += maskOffset;
}
break;
case 4:
// 32 bpp color
for (int y = startY; y < stopY; y++)
{
for (int x = startX; x < stopX; x++, imagePtr += 4, filteredPtr += 4, mask++)
{
if (*mask != 0)
{
imagePtr[RGB.R] = filteredPtr[RGB.R];
imagePtr[RGB.G] = filteredPtr[RGB.G];
imagePtr[RGB.B] = filteredPtr[RGB.B];
imagePtr[RGB.A] = filteredPtr[RGB.A];
}
}
imagePtr += srcOffset;
filteredPtr += filteredOffset;
mask += maskOffset;
}
break;
}
#endregion
}
else
{
// 16 bits per channel
byte* imagePtrBase = (byte*)image.ImageData.ToPointer() +
srcStride * startY + pixelSize * startX;
byte* filteredPtrBase = (byte*)filteredImage.ImageData.ToPointer() +
filteredStride * startY + pixelSize * startX;
#region 16 bit cases
switch (pixelSize)
{
case 2:
// 16 bpp grayscale
for (int y = startY; y < stopY; y++)
{
ushort* imagePtr = (ushort*)imagePtrBase;
ushort* filteredPtr = (ushort*)filteredPtrBase;
for (int x = startX; x < stopX; x++, imagePtr++, filteredPtr++, mask++)
{
if (*mask != 0)
{
*imagePtr = *filteredPtr;
}
}
imagePtrBase += srcStride;
filteredPtrBase += filteredStride;
mask += maskOffset;
}
break;
case 6:
// 16 bpp grayscale
for (int y = startY; y < stopY; y++)
{
ushort* imagePtr = (ushort*)imagePtrBase;
ushort* filteredPtr = (ushort*)filteredPtrBase;
for (int x = startX; x < stopX; x++, imagePtr += 3, filteredPtr += 3, mask++)
{
if (*mask != 0)
{
imagePtr[RGB.R] = filteredPtr[RGB.R];
imagePtr[RGB.G] = filteredPtr[RGB.G];
imagePtr[RGB.B] = filteredPtr[RGB.B];
}
}
imagePtrBase += srcStride;
filteredPtrBase += filteredStride;
mask += maskOffset;
}
break;
case 8:
// 16 bpp grayscale
for (int y = startY; y < stopY; y++)
{
ushort* imagePtr = (ushort*)imagePtrBase;
ushort* filteredPtr = (ushort*)filteredPtrBase;
for (int x = startX; x < stopX; x++, imagePtr += 4, filteredPtr += 4, mask++)
{
if (*mask != 0)
{
imagePtr[RGB.R] = filteredPtr[RGB.R];
imagePtr[RGB.G] = filteredPtr[RGB.G];
imagePtr[RGB.B] = filteredPtr[RGB.B];
imagePtr[RGB.A] = filteredPtr[RGB.A];
}
}
imagePtrBase += srcStride;
filteredPtrBase += filteredStride;
mask += maskOffset;
}
break;
}
#endregion
}
}
}