Reputation: 48736
I found this code on how to apply a color filter to a Bitmap object in C#. The problem with it is it uses unsafe code to accomplish this. Is there a managed, safe way to do this same thing? I know I could use a library like AForge.NET or something similar, but I'm hoping there is a simple way to just apply a color filter. All I need is simple color replacement, replacing white pixels with yellow. Any suggestions?
Upvotes: 5
Views: 11981
Reputation: 14532
You could always use the safe GetPixel and SetPixel methods, but they are slow when used on many pixels, which is the reason you use unsafe method to use pointers to the bitmap's memory. Unsafe is the way to do it.
If your bitmap is very small and you don't care about performance all that much, use the GetPixel and SetPixel methods.
private void ReplaceColor(Bitmap bitmap, Color originalColor, Color replacementColor)
{
for (var y = 0; y < bitmap.Height; y++)
{
for (var x = 0; x < bitmap.Width; x++)
{
if (bitmap.GetPixel(x, y) == originalColor)
{
bitmap.SetPixel(x, y, replacementColor);
}
}
}
}
private unsafe void ReplaceColorUnsafe(Bitmap bitmap, byte[] originalColor, byte[] replacementColor)
{
if (originalColor.Length != replacementColor.Length)
{
throw new ArgumentException("Original and Replacement arguments are in different pixel formats.");
}
if (originalColor.SequenceEqual(replacementColor))
{
return;
}
var data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size),
ImageLockMode.ReadWrite,
bitmap.PixelFormat);
var bpp = Image.GetPixelFormatSize(data.PixelFormat);
if (originalColor.Length != bpp)
{
throw new ArgumentException("Original and Replacement arguments and the bitmap are in different pixel format.");
}
var start = (byte*)data.Scan0;
var end = start + data.Stride;
for (var px = start; px < end; px += bpp)
{
var match = true;
for (var bit = 0; bit < bpp; bit++)
{
if (px[bit] != originalColor[bit])
{
match = false;
break;
}
}
if (!match)
{
continue;
}
for (var bit = 0; bit < bpp; bit++)
{
px[bit] = replacementColor[bit];
}
}
bitmap.UnlockBits(data);
}
Usage would be:
this.ReplaceColor(myBitmap, Color.White, Color.Yellow); // SLOW
OR
var orgRGB = new byte[] { 255, 255, 255 }; // White (in RGB format)
var repRGB = new byte[] { 255, 255, 0 }; // Yellow (in RGB format)
var orgARGB = new byte[] { 255, 255, 255, 255 }; // White (in ARGB format)
var repARGB = new byte[] { 255, 255, 255, 0 }; // Yellow (in ARGB format)
var orgRGBA = new byte[] { 255, 255, 255, 255 }; // White (in RGBA format)
var repRGBA = new byte[] { 255, 255, 0, 255 }; // Yellow (in RGBA format)
var orgBytes = orgRGB; // or ARGB or RGBA, depending on bitmap's pixel format
var repBytes = repRGB; // or ARGB or RGBA, depending on bitmap's pixel format
this.ReplaceColorUnsafe(myBitmap, orgBytes, repBytes); // FAST
Upvotes: 4