Click here to Skip to main content
15,867,568 members
Articles / Multimedia / GDI

TransparentSplash Control

Rate me:
Please Sign up or sign in to vote.
4.64/5 (9 votes)
4 Oct 2018CPOL4 min read 36.3K   2.2K   38   6
A non rectangular/transparent splash screen control that starts life before the Application Form

TransparentSplash/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 resource 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. Remember 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.

C#
// 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:

C#
// 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 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 useful and discover any other useful 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)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalhi Pin
gc_229927-Apr-11 3:41
gc_229927-Apr-11 3:41 
Generalcool Pin
Yves12-Jul-10 13:39
Yves12-Jul-10 13:39 
GeneralRe: cool Pin
TwinLane12-Jul-10 21:58
TwinLane12-Jul-10 21:58 
GeneralRe: cool Pin
Yves13-Jul-10 12:45
Yves13-Jul-10 12:45 
Questionwhy called transparent? Pin
Seraph_summer6-Jul-10 11:22
Seraph_summer6-Jul-10 11:22 
AnswerRe: why called transparent? Pin
TwinLane6-Jul-10 12:04
TwinLane6-Jul-10 12:04 

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

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