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?
-
2Is 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
-
1possible 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 Answers
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

- 72,067
- 7
- 111
- 189
-
What about unconventional shapes? Like this one: http://img2-2.timeinc.net/people/i/2013/pets/news/130218/cat-monopoly-600.jpg – Sharon Dorot Jul 16 '13 at 20:55
-
If that image has Transparent Background you can set your Control's `BackGroundImage` Property and Set Control.BackColor = Color.Transparent; – Sriram Sakthivel Jul 16 '13 at 21:04
-
1@SharonJDDorot - You might find this article useful: http://bobpowell.net/region_from_bitmap.aspx – Chris Dunaway Jul 16 '13 at 22:29
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);

- 61,710
- 16
- 105
- 130