3

I need to load an image with green circle over a transparent background into a bitmap image using c# (System.Drawings).

That's the easy part. However I need to change the color of the circle before adding it to the bigger image, without affecting the transparency of the surrounding. In my case I need to change the circle color to yellow and add it as a sun.

I can't use fixed yellow circle image because the desired color is dynamic.

So in the code below, how can I change the color of the image before adding it to the bitmap?

Image i = Image.FromFile(greenCircleFile);
Bitmap b = new Bitmap(500, 500);

using(Graphics g = Graphics.FromImage(b))
{
    //--> Here I need to change the color of the green circle to yellow
    //afterwards I can add it to the bitmap image
    g.DrawImage(i, 0, 0, 500, 500);
}

Please note that two things need to be into consideration: Keeping the anti-aliasing of the shape (circle), and the color needs to be picked by user and used as is to overlay the original color of the circle.

Fixed:

Thanks to @TaW, he provided the correct answer. However with a glitch, here's the final version that worked for me:

Image i = Image.FromFile(greenCircleFile);
Bitmap b = new Bitmap(500, 500);

using(Graphics g = Graphics.FromImage(b))
{
    //Here I need to change the color of the green circle to yellow
    i = ChangeToColor(b, Color.Gold)
    //afterwards I can add it to the bitmap image
    g.DrawImage(i, 0, 0, 500, 500);
}

While ChangeToColor function is as follows:

Bitmap ChangeToColor(Bitmap bmp, Color c)
{
    Bitmap bmp2 = new Bitmap(bmp.Width, bmp.Height);
    using (Graphics g = Graphics.FromImage(bmp2))
    {
        float tr = c.R / 255f;
        float tg = c.G / 255f;
        float tb = c.B / 255f;

        ColorMatrix colorMatrix = new ColorMatrix(new float[][]
          {
            new float[] {0, 0, 0, 0, 0},
            new float[] {0, 0, 0, 0, 0},
            new float[] {0, 0, 0, 0, 0},
            new float[] {0, 0, 0, 1, 0},
            new float[] {tr, tg, tb, 0, 1}
          });

        ImageAttributes attributes = new ImageAttributes();
        attributes.SetColorMatrix(colorMatrix);

        g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height),
            0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
    }
    return bmp2;
}
Lamar
  • 1,761
  • 4
  • 24
  • 50

2 Answers2

3

This will create a new Bitmap with all non-transparent pixels moved strongly toward a new color:

    Bitmap ChangeToColor(Bitmap bmp, Color c)
    {
        Bitmap bmp2 = new Bitmap(bmp.Width, bmp.Height);
        using (Graphics g = Graphics.FromImage(bmp2))
        {
            float tr = c.R / 255f;
            float tg = c.G / 255f;
            float tb = c.B / 255f;

            ColorMatrix colorMatrix = new ColorMatrix(new float[][]
              {
                 new float[] {0, 0, 0, 0, 0},
                 new float[] {0, 0, 0, 0, 0},
                 new float[] {0, 0, 0, 0, 0},
                 new float[] {0, 0, 0, 1, 0},
                 new float[] {tr, tg, tb, 0, 1}  // kudos to OP!
              });

            ImageAttributes attributes = new ImageAttributes();
            attributes.SetColorMatrix(colorMatrix);

            g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height),
                0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
        }
        return bmp2;
    }

do make sure not to leak the Bitmaps you create!

Note that there are other methods as well. Here is a link to a method that uses ColorMapping. This allows for a range of colors to be replaced by another range, so it can keep gradients like the ones you get in anti-alised graphics..

Community
  • 1
  • 1
TaW
  • 53,122
  • 8
  • 69
  • 111
  • Thanks! I enjoyed following your stackoverflow references. However, I applied "Color.Gold" to a red image, but it produced another shade of red. I understand the RGB, but not the other WA arrays in the matrix. – Lamar Jan 22 '17 at 09:08
  • Thanks a lot!! I had tested with colors that actually did work with my version but your code is indeed right. I have updated my answer. – TaW Jan 22 '17 at 09:59
  • I tried this but It seems to be replacing the whole image to a color instead of just replacing the specified colors. – DreTaX Jan 01 '19 at 14:42
-1

Here's my solution you just need to create a new Control

then inherit the Picturebox check this out.

public partial class UICirclePicture : PictureBox
{
    [Browsable(false)]
    public int Depth { get; set; }
    [Browsable(false)]
    public SprikiwikiUI Ui
    {
        get { return SprikiwikiUI.Instance; }
    }
    [Browsable(false)]
    public MouseState MouseState { get; set; }

    public UICirclePicture()
    {


        BackColor = Ui.GetApplicationBackgroundColor();
        SizeMode = PictureBoxSizeMode.StretchImage;

    }


    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        using (var gp = new GraphicsPath())
        {
            gp.AddEllipse(new Rectangle(0, 0, this.Width - 1, this.Height - 1));
            this.Region = new Region(gp);
        }
    }

}
Pseudorandom
  • 716
  • 3
  • 14
  • 30