0

I'm trying to place an image that has no definitive shape (a hat for example) on top of a different image control. The thing is, since the control has a definitive shape, it leaves the default background color to cover up the space left blank. The image control is the exact same size of the image. I tried using control.BackColor = Color.Transparent; but it doesn't seem to work. Any other suggestions?

Sharon Dorot
  • 542
  • 1
  • 4
  • 15
  • 2
    Is the image itself transparent? For example, PNG images support the transparent color. This is pretty crucial for your attempt to work... – M.A. Hanin Jul 16 '13 at 20:44
  • Edited your title. Please read this: http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles – RahulD Jul 16 '13 at 20:52
  • I believe this is WinForms, so you may want to specify this in your tags (instead of background or picturebox perhaps). I originally was going to answer this for WPF before noticing `BackColor`. – Will Eddins Jul 16 '13 at 20:55
  • Yes my image has a transparent background as a PNG format. – Sharon Dorot Jul 16 '13 at 20:56
  • can u provide some code to clarify exactly whats needed? – terrybozzio Jul 16 '13 at 21:19
  • 1
    possible duplicate of [Winforms semi-transparent PNG over semi-transparent PNG](http://stackoverflow.com/questions/10455484/winforms-semi-transparent-png-over-semi-transparent-png) – Hans Passant Jul 16 '13 at 21:36

2 Answers2

1

You can use Control.Region for this purpose

GraphicsPath path = new GraphicsPath();
path.AddEllipse(control.ClientRectangle);
control.Region = new Region(path);

try this, you can create any shape using GraphicsPath and set it to Region for instance I created ellipse.

Edit

If you just want to set BackColor = Color.Transparent. for some reason some controls doesn't allow this. in such cases you can do the following

public class CustomControl1 : Control
{
    public CustomControl1()
    {
        this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    }
}

Create a descendant of your control and set this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); that should do the trick

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
0

If your Image Control (like a PictureBox) is not moved (by holding mouse down and dragging) by user at runtime, you can use this technique which allows you to display images on top of each other. The images should have transparent background:

public class ImageControl : Control {
   public ImageControl(){
      SetStyle(ControlStyles.Opaque, true);
   }
   public Image Image {get;set;}
   protected override CreateParams CreateParams {
      get {
          CreateParams cp = base.CreateParams;
          cp.ExStyle |= 0x20;
          return cp;
      }
   }
   protected override void OnPaint(PaintEventArgs e){
      if(Image != null) e.Graphics.DrawImage(Image, Point.Empty);
   }
}

You can use the control above instead of a PictureBox. Moving this control by dragging at runtime causes flicker much. So if you want so I think there is only 1 solution which uses Region. In this approach, you have to turn your Bitmap to a Region and assign this Region for your Control.Region property. The link given by Chris Dunaway is very helpful for you to do this. However I have to say that the Region has not a smooth border as you may expect. That's a shortage of this approach. For your convenience, I'll post the code with a little modification here, this code uses LockBits which will outperform the original code:

public class Util {
//invert will toggle backColor to foreColor (in fact, I mean foreColor here is the Solid Color which makes your image distinct from the background).
    public static Region RegionFromBitmap(Bitmap bm, Color backColor, bool invert)
    {
        Region rgn = new Region();
        rgn.MakeEmpty();//This is very important            
        int argbBack = backColor.ToArgb();
        BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        int[] bits = new int[bm.Width * bm.Height];
        Marshal.Copy(data.Scan0, bits, 0, bits.Length);
        //
        Rectangle line = Rectangle.Empty;
        line.Height = 1;
        bool inImage = false;
        for (int i = 0; i < bm.Height; i++)
        {
            for (int j = 0; j < bm.Width; j++)
            {
                int c = bits[j + i * bm.Width];
                if (!inImage)
                {
                    if (invert ? c == argbBack : c != argbBack)
                    {
                        inImage = true;
                        line.X = j;
                        line.Y = i;
                    }
                }
                else if(invert ? c != argbBack : c == argbBack)
                {
                    inImage = false;
                    line.Width = j - line.X;
                    rgn.Union(line);
                }
            }
        }
        bm.UnlockBits(data);
        return rgn;
    }
}
//Use the code
//if your Bitmap is a PNG with transparent background, you can get the Region from it like this:
Region rgn = Util.RegionFromBitmap(yourPng, Color.FromArgb(0), false);
//if your Bitmap has a figure with solid color of Black, you can get the Region like this:
Region rgn = Util.RegionFromBitmap(yourPng, Color.Black, true);
King King
  • 61,710
  • 16
  • 105
  • 130