Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Color Replacer

0.00/5 (No votes)
6 Oct 2009 1  
An example showing you how to replace a specific color falling within a color range in an image.

Introduction

I remember how I used to love MS PhotoEditor that used to be included in MS Office 2000, for it's a simple and efficient tool when you want to make an image with transparent parts by eliminating a specific color from the entire image. Well, this article will show you how this is made possible.

Background

The idea behind this process lies in reading the image pixel by pixel, and for each pixel, a further break down is made for the three basic components of each color (ARGB): Alpha, Red, Green, Blue, respectively. We don't care much about reading alpha in this example, but will be when it comes to writing back the image pixels. After reading the pixel and getting its RGB components, we now set the upper and lower limits for each color by adding the tolerance value to composite the upper limit and subtracting it from the original value to come up with the lower color limit. Eventually, we decide whether or not a color lies between the boundaries of the range we set earlier, and if so, the new color is applicable to that pixel. In the case of transparency, the three color components don't matter anymore, so whatever they are, we just raise the Alpha factor to its maximum value, i.e., 255 DEC or FF HEX.

Using the Code

According to the tolerance value, we first define the limits of each color of the original color passed to our function.

//Defining Tolerance
//R
iR_Min = Math.Max((int)_colorOld.R - _tolerance, 0);
iR_Max = Math.Min((int)_colorOld.R + _tolerance, 255);

//G
iG_Min = Math.Max((int)_colorOld.G - _tolerance, 0);
iG_Max = Math.Min((int)_colorOld.G + _tolerance, 255);

//B
iB_Min = Math.Max((int)_colorOld.B - _tolerance, 0);
iB_Max = Math.Min((int)_colorOld.B + _tolerance, 255);

Then, we loop through the image pixels on a row, column basis:

for (int x = 0; x < bmap.Width; x++)
{
    for (int y = 0; y < bmap.Height; y++)
    {
        c = bmap.GetPixel(x, y);
        ...

Once a pixel is read, we check whether or not it falls within the range of our original color values defined earlier:

//Determinig Color Match
if(
    (c.R >= iR_Min && c.R <= iR_Max) &&
    (c.G >= iG_Min && c.G <= iG_Max) &&
    (c.B >= iB_Min && c.B <= iB_Max) 
  )

If it is a match, then we make another check, but this time, for writing the pixel, and the check is now about whether the replacing color is transparent or not.

if(_colorNew == Color.Transparent)
  bmap.SetPixel(x, y, Color.FromArgb(0,
       _colorNew.R,
       _colorNew.G,
       _colorNew.B));

else
  bmap.SetPixel(x, y, Color.FromArgb(c.A,
       _colorNew.R,
       _colorNew.G,
       _colorNew.B));

As you can see, if the new color is transparent, we simply decrease the alpha to 0; otherwise, we use the alpha value fetched from the original image, c.A.

Points of Interest

When trying to pick a color from the PictureBox, the MouseEventArgs coordinates are not very accurate and are still not fixed in this article, and I'm hoping that together, we can work something out. Here's how it is being managed right now...

private void pbPreview_MouseMove(object sender, MouseEventArgs e)
{
    if (bPicking)
    {
        Bitmap bmTemp = (Bitmap)((PictureBox)sender).Image;
        pnlOldColor.BackColor = bmTemp.GetPixel(e.X,e.Y);
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here