.NET Forum / Languages / C# / September 2007
Transparent Graphic Background
|
|
Thread rating:  |
Brian Ward - 12 Sep 2007 20:59 GMT I am looking for a simple way to set the image transparency in a PictureBox. I have a moving PictureBox containing a graphic image .. moving by incrementing its Left property. The background however shows white as the PictureBox moves but I want it to be transparent. The PictureBox BackColor is set to Transparent .. but no affect. I have used PhotoShop to make the image background transparent .. again no affect. If I make the image a BackgroundImage to a Panel instead of a PictureBox it shows up as I want it .. but then I can't move the Panel. I am using C# Visual Express 2005. Any help much appreciated. === Brian ===
Peter Duniho - 12 Sep 2007 22:15 GMT > I am looking for a simple way to set the image transparency in a PictureBox. > I have a moving PictureBox containing a graphic image .. moving by [quoted text clipped - 4 lines] > used PhotoShop to make the image background transparent .. again no > affect. What format did you save the image in? JPEG doesn't support transparency. TIFF and PNG do, though.
Also, how do you set the picture for the PictureBox? I have used PNG files with transparency, setting the Image property of the PictureBox to the image I want (in my case, set in the Designer, but loading at run-time should work fine too).
It should work. If the above does not help you fix the problem, you should be more specific about what you're doing.
Pete
Brian Ward - 13 Sep 2007 22:47 GMT The message <13eglnchhvgqs92@corp.supernews.com> from Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> contains these words:
> What format did you save the image in? JPEG doesn't support > transparency. TIFF and PNG do, though. GIF format. I thought that was supposed to work but I'll try the others.
> Also, how do you set the picture for the PictureBox? I have used PNG > files with transparency, setting the Image property of the PictureBox to > the image I want (in my case, set in the Designer, but loading at > run-time should work fine too). In Form Designer Mode I access the PictureBox Image property and browse to the image file.
> It should work. If the above does not help you fix the problem, you > should be more specific about what you're doing. > Pete Well its just using a timer_Tick() event to move the PictureBox across the screen by increasing the Left property. At the moment I have to set the Form background to white so the PictureBox background doesn't show .. but thats not what I want. Thanks .. I'll try PNG and TIFF == Brian ==
Peter Duniho - 14 Sep 2007 01:22 GMT >> What format did you save the image in? JPEG doesn't support >> transparency. TIFF and PNG do, though. > > GIF format. > I thought that was supposed to work but I'll try the others. GIF should work too. At least, I know it works in .NET 2.0, and since you're using VS 2005 Express, I assume that you're using .NET 2.0 or later.
> [...] > Well its just using a timer_Tick() event to move the PictureBox across > the screen by increasing the Left property. At the moment I have to set > the Form background to white so the PictureBox background doesn't show > ... but thats not what I want. > Thanks .. I'll try PNG and TIFF As an initial suggestion: don't mess with the animation until you get the GIF drawing statically correctly. It just confuses the issue.
You should double-check to make sure that the BackColor of the PictureBox control is set to Transparent as you believe it is. Assuming it is set correctly, then the only thing I can think of is that the GIF isn't actually being saved out with transparency. One way to check that would be to make a simple HTML page with a non-white background color and let your browser display it:
<body style="background-color: #008"> <img src="Test.gif"> </body>
(yes, that's ill-formed HTML...but I think most browsers will still display it fine :) )
Of course, you could also just load it back into the image editing program and verify that the transparency is still there.
The bottom line here is that what you're doing should work fine. If none of the above still leads to a solution, you should probably post a complete-but-concise sample of code that demonstrates the problem. You may also want to provide the actual GIF file, so that your entire scenario can be tested by other people.
(Don't attach the GIF file to your post; this isn't a binary newsgroup so it'd be bad form anyway, and because it's not many ISP's will either block the entire post or just strip off the attachment anyway. You can use upload/download web sites such as http://www.filecrunch.com/, http://www.sendspace.com/, http://www.yousendit.com/, etc. which allow you to upload a file and then get a link that you can include in your message so others can download it).
Pete
Brian Ward - 14 Sep 2007 23:18 GMT Thanks Peter ============= I have made some progress through double-checking etc. I thought I had saved the transparency from Photoshop but apparently not! So I now have a transparent graphic with the form background colour showing through instead of white as before. So far so good. But ... when the PictureBox moves it appears to take the form background colour with it .. i.e. when the box moves across other objects on the form such as panels, buttons, other PictureBoxes, etc. the outline of the Picturebox then shows up again .. with the form colour as its background. I would really like the graphic image only to be seen (not its container) as it passes other objects. === Brian ===
The message <13ejl1gig4l5db2@corp.supernews.com> from Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> contains these words:
> >> What format did you save the image in? JPEG doesn't support > >> transparency. TIFF and PNG do, though. > > > > GIF format. > > I thought that was supposed to work but I'll try the others.
> GIF should work too. At least, I know it works in .NET 2.0, and since > you're using VS 2005 Express, I assume that you're using .NET 2.0 or later.
> > [...] > > Well its just using a timer_Tick() event to move the PictureBox across > > the screen by increasing the Left property. At the moment I have to set > > the Form background to white so the PictureBox background doesn't show > > ... but thats not what I want. > > Thanks .. I'll try PNG and TIFF
> As an initial suggestion: don't mess with the animation until you get > the GIF drawing statically correctly. It just confuses the issue.
> You should double-check to make sure that the BackColor of the > PictureBox control is set to Transparent as you believe it is. Assuming > it is set correctly, then the only thing I can think of is that the GIF > isn't actually being saved out with transparency. One way to check that > would be to make a simple HTML page with a non-white background color > and let your browser display it:
> <body style="background-color: #008"> > <img src="Test.gif"> > </body>
> (yes, that's ill-formed HTML...but I think most browsers will still > display it fine :) )
> Of course, you could also just load it back into the image editing > program and verify that the transparency is still there.
> The bottom line here is that what you're doing should work fine. If > none of the above still leads to a solution, you should probably post a > complete-but-concise sample of code that demonstrates the problem. You > may also want to provide the actual GIF file, so that your entire > scenario can be tested by other people.
> (Don't attach the GIF file to your post; this isn't a binary newsgroup > so it'd be bad form anyway, and because it's not many ISP's will either [quoted text clipped - 3 lines] > you to upload a file and then get a link that you can include in your > message so others can download it).
> Pete Peter Duniho - 15 Sep 2007 03:02 GMT > Thanks Peter > ============= [quoted text clipped - 8 lines] > background. I would really like the graphic image only to be seen (not > its container) as it passes other objects. Hmph. I found this:
Windows Forms controls do not support true transparency. The background of a transparent Windows Forms control is painted by its parent.
(http://msdn2.microsoft.com/en-us/library/wk5b13s4.aspx)
I was able to reproduce the behavior you're reporting, and I admit it surprised me. But then I found the above quote, which suggests to me that there's no straight-forward way to do what you want.
I tried some things involving creating a PictureBox-derived class. I thought maybe I could set the AllPaintingInWmPaint style and not doing anything in the OnPaintBackground method, but in spite of the implication in the docs that you can set the style and avoid having to paint the background, Windows apparently expects that you will completely draw the entire control when this style is set. Simply not drawing the part of the control that's transparent results in garbage, presumably left over from temporary caching of drawing of the other controls in the form (at least that's what it looks like to me).
Ordinarily, I would suggest skipping making the thing a control and just drawing it directly yourself into the form. However, it sounds as though you want it to be drawn on top of other controls, and of course all of the form's own rendering happens under any controls that are in the form. So that wouldn't be appropriate in your case.
If you can come up with a way to represent the transparency as a Region (or rather, the area that's not transparent), then you could use that Region as the Control's region, which would cause all drawing, including the background, to be clipped to the region. But if you're using a plain bitmap, that could be problematic, as I'm not aware of any built-in functions that would do that. I suppose you could do it yourself by scanning the bitmap line by line, checking the alpha of each pixel, generating a Region that way (either pixel-by-pixel, or consolidating adjacent non-transparent pixels in each line into a single rectangle you add to the Region). But that seems like a lot of work to me. :)
Unfortunately, that's all I have with respect to decent ideas. So, here's one last bad one: write your own picture-box control that copies whatever's underneath it for use in drawing it's own background. I tried it, and it does work. There's a little bit of "smudging" that goes on as the control is moved, because some how it gets drawn in its new location before the OnLocationChanged method is called. This might be fixable, but I think I'll leave that up to you to explore, at least for now. :)
I think this is a really hacky solution, and I'd probably try to use something a little more "polite". Also, this has potential performance issues, since each time the control is moved, the entire form has to be redrawn into a bitmap. It's plenty fast on my fast PC with a small form though.
Anyway, see if this is helpful at all (take this code and use it to implement a custom control class in your own project):
using System; using System.Drawing; using System.Windows.Forms;
namespace TestTransparentGIF { public partial class TransparentPictureBox : PictureBox { Bitmap _bmpBackground; bool _fDontDraw;
public TransparentPictureBox() { InitializeComponent();
SetStyle(ControlStyles.Opaque, true); }
protected override void OnPaint(PaintEventArgs pe) { if (!_fDontDraw) { if (_bmpBackground == null) { using (Bitmap bmpT = new Bitmap(Parent.Size.Width, Parent.Size.Height)) { Point ptParentScreen = Parent.Location; Point ptScreen = Parent.PointToScreen(Location); Point ptInParent;
if (Parent.Parent != null) { ptParentScreen = Parent.Parent.PointToScreen(ptParentScreen); }
ptInParent = ptScreen - new Size(ptParentScreen);
_fDontDraw = true; Parent.DrawToBitmap(bmpT, new Rectangle(new Point(), Parent.Size)); _fDontDraw = false;
_bmpBackground = new Bitmap(Width, Height); using (Graphics gfxT = Graphics.FromImage(_bmpBackground)) { gfxT.DrawImageUnscaled(bmpT, new Point() - new Size(ptInParent)); } } }
if (_bmpBackground != null) { pe.Graphics.DrawImage(_bmpBackground, new Point()); }
// Calling the base class OnPaint base.OnPaint(pe); } }
protected override void OnLocationChanged(EventArgs e) { if (_bmpBackground != null) { _bmpBackground.Dispose(); _bmpBackground = null;
Invalidate(); }
base.OnLocationChanged(e); } } }
Peter Duniho - 15 Sep 2007 03:42 GMT Okay, had a hunch that panned out. Instead of overriding OnLocationChanged like this:
> protected override void OnLocationChanged(EventArgs e) > { [quoted text clipped - 8 lines] > base.OnLocationChanged(e); > } Override SetBoundsCore like this:
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { if (_bmpBackground != null) { _bmpBackground.Dispose(); _bmpBackground = null;
Invalidate(); }
base.SetBoundsCore(x, y, width, height, specified); }
That method gets called before the on-screen update occurs, allowing you to reset the background before that happens. By doing this, the smudging effect goes away.
Other that the potential performance issues, this actually might work okay for you. :) For what it's worth though, I did try it with the form sized much larger, and it definitely slows down noticeably. :(
Brian Ward - 15 Sep 2007 23:46 GMT Thanks Again Peter ================= I'll have a go with this although I hadn't realised I had stepped into quite such a big pile of smelly stuff! I thought it would be such a straightforward thing to do. Heh-ho! Thanks for your patience and diligence. === Brian ===
The message <13emhk3h834jjb0@corp.supernews.com> from Peter Duniho <NpOeStPeAdM@NnOwSlPiAnMk.com> contains these words:
> Okay, had a hunch that panned out. Instead of overriding > OnLocationChanged like this:
> > protected override void OnLocationChanged(EventArgs e) > > { [quoted text clipped - 8 lines] > > base.OnLocationChanged(e); > > }
> Override SetBoundsCore like this:
> protected override void SetBoundsCore(int x, int y, int width, > int height, BoundsSpecified specified) [quoted text clipped - 3 lines] > _bmpBackground.Dispose(); > _bmpBackground = null;
> Invalidate(); > }
> base.SetBoundsCore(x, y, width, height, specified); > }
> That method gets called before the on-screen update occurs, allowing you > to reset the background before that happens. By doing this, the > smudging effect goes away.
> Other that the potential performance issues, this actually might work > okay for you. :) For what it's worth though, I did try it with the > form sized much larger, and it definitely slows down noticeably. :( Peter Duniho - 16 Sep 2007 19:20 GMT > Thanks Again Peter > ================= > I'll have a go with this although I hadn't realised I had stepped into > quite such a big pile of smelly stuff! > I thought it would be such a straightforward thing to do. Heh-ho! Me too. Not having ever had a transparent control overlapping any other control, I never realized that "Transparent" doesn't actually mean "transparent", but instead only means "draw the background with the parent's background color".
IMHO, that's a pretty significant difference in meaning, and also IMHO the docs are wrong here. Not only does the doc page for Control.BackColor not describe this discrepancy, it even implies that transparent colors can be supported when it discusses the control style SupportsTransparentBackColor as being required for using transparent color. All that a "transparent" color does is blend with the parent's background color; it's still not really transparent.
> Thanks for your patience and diligence. You're welcome. One other point I might as well make, though you likely already understand it: the performance hit in the technique I posted is because the entire parent has to be copied with DrawToBitmap every time that the control moves. If you can avoid this, performance should be fine; the only way I know to avoid it is if the parent's contents are static, but of course if you figured out some way to get DrawToBitmap to draw only the portion of the parent you are interested in that would work as well.
You might also have some success with an "in-between" solution in which you only update the background bitmap when the parent contents change. If the parent isn't static, but also doesn't change very often, that could be a better approach.
Pete
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|