Click here to Skip to main content
Click here to Skip to main content

Tagged as

TransparentSplash Control

, 5 Jul 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
A non rectangular/transparent splash screen control that starts life before the Application Form.
transparentsplash.PNG

Introduction

A few years back I wrote an article on creating a splash control derived from UserControl SplashScreen Control A reader asked me why his transparent images just showed a black background.  This was because the control was not transparent itself, and the transparency in the image was revealing the unpainted background.

I said I would look at the requirement and at the time guessed it might involve BitBlt, a function in the Windows SDK to do block transfer of pixels. The technique in mind was to copy and paint the screen background before drawing the 'Transparent' image.  It's a satisfactory solution until the 'host' image below changes or moves.  Then it's exposed as a trick.  I dropped this idea in favour of the solution presented here.

To achieve real transparency I override and consume OnPaintBackground, and in the OnPaint override I paint only the opaque pixels required.

Unsafe!

This solution will not appeal to the .NET purist because it goes 'off road' from .NET by using the Interop and Unsafe code, which is direct code access to memory via pointers.  This is a way of life for C and C++ programmers.  It also requires that you find a suitable image that will look good in all conditions.  This is because the edges of your image will contrast with the background without dithering, shadowing or other techniques to smooth the result.  But if you don't mind this, and know what you have in mind, this is how I've found you can do it, and I hope it works well for you.

What you'll need for your Implementation

You will need to provide an image resourse in your project that is masked by one color, representing the transparent or undrawn pixels.  For an example see the demo project which uses a nicely composed sphere, in fact derived from the Armenian flag, which is for no other reason than I thought it looked nice and had nicely formed and smooth edges.

Understanding the Code

To find out about the basic principles behind this control please refer to the SplashScreen control I presented in SplashScreen Control

TransparentSplash is different because it draws the image pixel by pixel to be truly non-rectangular.  Using GDI+ to do this is not viable, at this point in time at least, because it's too slow. 

The image provided with the sample application is 256 x 256 pixels. To process this image requires 65536 Get operations and then the Set operations required to place the opaque pixels.  We need to use native methods to do this very intense operation because they allow us to get a lock on some memory that contains the bitmap pixels and then use pointer methods to do the getting.  This is considerably faster than managed GDI+ code can achieve. 

Whilst investigating this operation I found a very nice class called FastBitmap at Visual C# Kicks which gives us all the Unsafe methods we need in a well tried and tested bit of code.  Thank you to them, and I include and use the code in the sample project.  Rememeber that the project containing the unsafe code needs its property page marked to allow unsafe code.

As you'll see in the following code extract from Onpaint, FastBitmap is used to lock the image in memory via its LockImage method.  We then loop through the pixels column by column, row by row testing each one against the mask color.  If it matches the mask it is ignored, if it doesn't match it is painted by SetPixel a Windows SDK method provided by an interop import.  Refer to the 'Interop definitions' region in the code for this and other imports used.

// TransparentSplash.cs
 
#region image painting
 
Color colorMatch = Color.FromArgb(TransparencyColor.R, TransparencyColor.G, TransparencyColor.B);
IntPtr hdc = g.GetHdc();
Point point = new Point();
Color pixelColor = new Color();
Bitmap bmp = (Bitmap)BackgroundImage;
BitmapProcessing.FastBitmap fastBitmap = new BitmapProcessing.FastBitmap(bmp);
 
fastBitmap.LockImage();
for (point.Y = 0; point.Y < BackgroundImage.Height; point.Y++)
{
	for (point.X = 0; point.X < BackgroundImage.Width; point.X++)
	{
		if ((pixelColor = fastBitmap.GetPixel(point.X, point.Y)) != colorMatch)
		{
			SetPixel(hdc, point.X, point.Y, ColorToRGB(pixelColor));
		}
	}
}
fastBitmap.UnlockImage();
g.ReleaseHdc();
 
#endregion

That's the foreground painting done, but how did we paint the background?  Here is more proof, if you need it, that less is more:

// TransparentSplash.cs
 
protected override void OnPaintBackground(PaintEventArgs pevent)
{
	//must override and consume
}

This summons up enough GDI Voodoo to achieve the desired result.  I sympathise with anybody not finding this immediately intuitive.  You just need to remember that this control is a child of the desktop window and that if it does not paint its own background, and doesn't ask the base class to paint the background - then the background will be the background.  With the demo app you can bring up the the control and test moving the window below.  You should see that the background is refreshed without delay.

Share your Tips

If you find this technique usefull and discover any other usefull tips or techniques in your implementation please consider sharing them here - it will be most appreciated.

History

  • Version 1.0.0    Released: 5th July 2010

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

TwinLane

United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
Generalhi Pinmembergc_229927-Apr-11 3:41 
Generalcool PinmemberYves12-Jul-10 13:39 
GeneralRe: cool PinmemberTwinLane12-Jul-10 21:58 
GeneralRe: cool PinmemberYves13-Jul-10 12:45 
Questionwhy called transparent? PinmemberSeraph_summer6-Jul-10 11:22 
AnswerRe: why called transparent? PinmemberTwinLane6-Jul-10 12:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.2 | Last Updated 5 Jul 2010
Article Copyright 2010 by TwinLane
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid