There is nothing wrong with your television set. Do not attempt to adjust the picture.
27 May 2008
In this the second, and concluding, part of our experiments with Alpha Blended forms in Delphi, I will modify the demo application to use a compressed alpha transparent PNG image instead of a BMP. I will also move the bitmap to a resource file, demonstrate run-time premultiplication and enhance the splash screen with a few visual gimmicks.
If you haven’t read part 1 yet I strongly suggest you do so first: Alpha Blended Splash Screen in Delphi - Part 1. This part will be right here waiting for you when you get back.
For this part I have replaced the sample bitmap with another one. Mostly because the original was too big but also because I didn’t quite like the look of it. The new one is just a grid of 15 colored glass orbs. Not very meaningful, but I love glass orbs
Each of the techniques we try out in this part builds on the source code of the previous steps. If you don’t want to enter the code manually or copy/paste from the article, you can “cheat” and download the complete source.
The first step in improving our demo application is to get rid of the external bitmap file. Instead of reading the splash bitmap from an external file, we move the bitmap to a resource file, link it into the application and read it from there instead.
A resource file, most commonly seen with the file extension .res
, is a container for resources such as strings, bitmaps, icons, cursors, forms and dialogs. Resource files are rarely used by themselves. Instead they are linked into the applications or DLLs that uses them.
Resource files can be created with specialized resource editors such as Colin Wilson’s opensource XN Resource Editor or a commercial tool such as Resource Builder. Or if you are really desperate, the crummy, buggy imagedit.exe
that came with Delphi up to Delphi 2006 or the equally buggy, 20 year old Resource Workshop. The upcoming Delphi 2008 is supposed to (finally!) include some sort of integrated resource management.
You can also skip the resource editor and let Delphi create the resource file for you. Delphi comes with a resource compiler brcc32.exe
that can be used to compile resource script files into binary resource files. All you have to do is include the resource script file in your project and Delphi will take care of the rest.
The resource script is just a plain text file with the file extension .rc
. The complete resource script syntax is beyond the scope of this article (also, I can’t find the documentation for it anymore), but for our purpose it is very simple; Each line of the file lists the name of the resource, the resource type and the source filename of the resource.
Normally the resource type for a bitmap would be BITMAP
, but because our bitmap is a bit special (remember it’s a 32 bit bitmap with premultiplied alpha) and the BITMAP
resource type is reserved for “plain vanilla” bitmaps, we have to use the RCDATA
resource type. RCDATA
is the resource equivalent of a BLOB in a database; It’s a data type that can be used to store anything you like. For example Delphi’s forms (the DFM files) are stored as RCDATA
resources.
With me so far? OK, let’s try it out:
1 2 | // Name Type Filename SPLASH RCDATA "splash.bmp" |
{$R 'splash.res' 'splash.rc'}
procedure TFormSplash.Execute; var Stream: TStream; ··· begin ··· Bitmap := TBitmap.Create; try // Bitmap.LoadFromFile('splash.bmp'); Stream := TResourceStream.Create(HInstance, 'SPLASH', RT_RCDATA); try Bitmap.LoadFromStream(Stream); finally Stream.Free; end; ···
You might wonder why we don’t just use TBitmap.LoadFromResourceName()
. The reason is simply that LoadFromResourceName
is hardwired to only load the BITMAP
resource type and thus can’t be used to load our RCDATA
resource.
splash.rc
resource script into the splash.res
resource file and link it into the application.As you might remember from the first part, I promised to show you how to premultiply the bitmap at run-time. Premultiplication requires us to perform the following simple transformation on each pixel in the bitmap: Color = Color * Alpha / 255. The following function does just that:
procedure PremultiplyBitmap(Bitmap: TBitmap); var Row, Col: integer; p: PRGBQuad; begin for Row := 0 to Bitmap.Height-1 do begin Col := Bitmap.Width; p := Bitmap.ScanLine[Row]; while (Col > 0) do begin p.rgbBlue := p.rgbBlue * p.rgbReserved div 255; p.rgbGreen := p.rgbGreen * p.rgbReserved div 255; p.rgbRed := p.rgbRed * p.rgbReserved div 255; inc(p); dec(Col); end; end; end;
Since there’s only 256 possible color values per channel and only 256 possible alpha values, we can optimize this process by sacrificing a little memory (256*256 = 64Kb) and replace the calculations with a table lookup. Here’s the optimized version:
procedure PremultiplyBitmap(Bitmap: TBitmap); var Row, Col: integer; p: PRGBQuad; PreMult: array[byte, byte] of byte; begin // precalculate all possible values of a*b for Row := 0 to 255 do for Col := Row to 255 do begin PreMult[Row, Col] := Row*Col div 255; if (Row <> Col) then PreMult[Col, Row] := PreMult[Row, Col]; // a*b = b*a end; for Row := 0 to Bitmap.Height-1 do begin Col := Bitmap.Width; p := Bitmap.ScanLine[Row]; while (Col > 0) do begin p.rgbBlue := PreMult[p.rgbReserved, p.rgbBlue]; p.rgbGreen := PreMult[p.rgbReserved, p.rgbGreen]; p.rgbRed := PreMult[p.rgbReserved, p.rgbRed]; inc(p); dec(Col); end; end; end;
My tests show the optimized version to be 2-3 times faster. The function still has plenty of optimization opportunities but since it’s already fast enough, further performance gains doesn’t seem worth the resulting obfuscation of the code. I clocked the above function to 5 mS with the sample bitmap.
To try it out, go back to your original PhotoShop image and save it as a normal 32-bit bitmap with an alpha channel:
Shift+Ctrl+E
).Ctrl+Click
on the layer or Right-click on the layer+Select Pixels).Now modify your application to perform premultiplication on the bitmap after is has been loaded:
··· Bitmap.LoadFromStream(Stream); finally Stream.Free; end; ASSERT(Bitmap.PixelFormat = pf32bit, 'Wrong bitmap format - must be 32 bits/pixel'); // Perform run-time premultiplication PremultiplyBitmap(Bitmap); // Resize form to fit bitmap ClientWidth := Bitmap.Width; ClientHeight := Bitmap.Height; ···
Before you compile you should delete the old splash.res
to force the resource compiler to recompile with your new bitmap.
Give it a go before we move on.
thanks for this i have been wondering for a long time how to do it, but i think you are missing the
GraphicColor
files from your zip.great work tho thanks heaps
You're right.
The
GraphicEx\GraphicColor.pas
unit was missing. I've uploaded a new version which includes the missing file.Thanks.
Hi Anders
This is certainly one of the best tutorials I have ever seen regarding the idea, so thank you for that.
All my applications now use these alpha-blended splash windows, in PNG format (because it's so much easier). It really adds a great taste to the application. I have, however, stumbled accross a problem (my own problem, that is). I would like to start making widgets (similar to that of Yahoo!™ Widget Engine) in the near future, as well as glass toasters for my applications. Do you know how to add VCL controls to these alpha-blended windows?
Any help would really be appreciated. Thanks very much for putting time aside to show us this.
Michael
Hi, my apologies - you already answered my question in Part 1 of this article.
AlphaControls gives me the ability to have PNG based controls in my applications, but does not do the same to it's forms. If it does, however, my pocket does not match the dollar signs dancing around the Prices page of their website. I'm also based in South Africa, and don't have all these nausiating (spelling sucks, I think) accounts. Is there any way that you know of to get the effect and functionality of this widget?
Hi i've had the same problem but a programmer helped to me and i want to direct you to solution of this problem (using this way into real program that has child controls) please download this file, everything is clear but don't forget explanations are Turkish… And owner of sources said that, this is a simple generic example and it has no some other abilities (such as coloration)..
Link:
rapidshare.com/files/170827754/Generic_Clock.rar[edit: link dead]Hej Anders
I just tried this in Delphi 2009 and it cannot compile. I get several errors in MZLib and GraphicEx. Any chance you tried it?
Kind regards, Claus
Same for me here. Looks like GraphicEx doesn't work for D2009. I tried to fix the code but with no luck, so I switched to GDI+ and it works.
Delphi 2009 comes with PNG support.
Add
PNGImage
to your uses,Use
TPNGImage
instead ofTPNGGraphic
, although it does not descend fromTBitmap
, so you'll have to redo some of the code to support this.I tried modifying the code to use TPNGImage in Delphi 2009, but I guess I am missing something… The code compiles, but the image is never shown. Is there anyone out there that would post here the changes that have to be made in order to use TPNGImage in D2009? I thank you in advance!
Does anyone would know how to write with TLabel or TMemo on top of the transparant PNG image? My goal is to report loading progress during the display of the splash screen.
Haven't found a way to do that. We use the following code to draw licensing information on top of the form (you can't directly use
canvas.TextOut()
because it draws with the alpha channel set to 0, so you need to use GDI+ functions with the{$define PNG_GDIPLUS}
definition enabled). It's not completely self-explanatory, but hope it helps:This looks very helpful - thanks for the post. I will try it as soon as I have my new computer.
Been looking for this for ages. Now I'm assuming any image will do the trick? Another semi-transparent image over the alpha layer?
Hi All,
I also had compilation errors, however came up with my own solution. I decided to create two forms that become attached to each other. The first form is a frameless content holder. It holds all the data you need to display on a splash screen. The second uses the above-mentioned techniques to create a glassy border.
I will post the result soon.
I am also in the process of updating my website (inniosoft.netii.net), which is still new. Once done, the QuickShutdown program will be uploaded.
Regards
Michael Rockett
Thank you for this great tutorial, have been looking for something like this since the fail that was Winamp 3 came out, with it's alpha blended skins =)
Anyhow, I'm really looking forward to seeing how you will go about to attach a normal borderless form to an alpha blended one, in order to be able to use standard vcl components. I haven't managed to find a good enough solution for that.
Thanks
/Daniel
Thank you for this great tutorial, have been looking for something like this since the fail that was Winamp 3 came out, with it's alpha blended skins =)Anyhow, I'm really looking forward to seeing how you will go about to attach a normal borderless form to an alpha blended one, in order to be able to use standard vcl components. I haven't managed to find a good enough solution for that.
Thanks
/Daniel
Hi Daniel
I am in the process of completing my website, which is still static, but will contain everything soon. I am still in the process of developing my software, this of which - once completed - you’ll be able to download. The only programmes that use the method mention above are those listed in the Shareware section. It can still be downloaded for free, as the splash screen will be shown. If you haven’t purchased it, then that’s all you’ll see.
I’ll keep updates running.
Regards,
Michael
Hi Daniel (and others)
The website has been updated, however I have not uploaded any new software on to it. Daniel, I will create a full tutorial regarding the two forms that are used soon. The simple concept is this that the two forms do not collide. One uses the Alpha Blended Splash Screen tutorial (above), while the other does not. Once these forms are positioned correctly, the effect is provided. This method doesn't cater for what you may see with the Yahoo! Widget Engine - but if you wanted that particular effect, you would have to download a third-party component that generates such a form.
I'm sure there are methods that can be used within WinAPI that can call a procedure that creates the Alpha Blended form without layering it. From what I can tell, the software on Lee-Soft's website does not use layering as it is captured in a screen-shot. Layered windows are excluded from the screen-shot.
I find Delphi limited in this regard - and suggest using a third-party application for that reason.
I hope I have helped in some way
Regards,
Michael
Compiled under Delphi 7, running the demo app under Vista shows the window frame around the splash screen. Any thoughts on getting rid if this?
Thanks!
Setting the BorderStyle to bsNone resolved this problem.
Thanks Tim, I found the same problem (only shows up when Aero is enabled, which unfortunately it wasn't when testing under VMWare).
My website has been updated, and the download links for my applications that use the method from Part 1 are there to download, under the QuickDownloads section in the side bar.
To complete this great tutorial, it would be fine to upload the solution for windows-controls on Alpha-Blended Forms.
The download-Link, Alper Demir provided, is no longer working (RapidShare-Limit).
Is someone able to post his solution (or upload the file again) ?
Many Thanks!
Hi again Michael,
Have you had the time to compose the tutorial about placing a non-blended form ontop a blended one, making it possible to use standard vcl-components?
Really looking forward to that!
/Daniel
Hi Daniel
Unfortunately not - I recently had a PC crash and was not able to back up my data.
The purpose of that was to make splash screen dynamic. I had not found a way to make the forms movable at the same time.
There is, however, a handy set of utilities that you can use. I had the web bookmark for it, but I have lost it due to the crash. It's a set of flash components that enable you to have alpha blended forms. Problem with that is you wouldn't be able to fully utilise the Delphi language as you'd be using flash.
Furthermore, and unfortunately, I am not going to be continuing to use alpha forms as it is becoming highly tedious.
Kind Regards, and sorry I couldn't help.
Michael
Hi Daniel
I have found the link to the flash utilities:
http://www.almdev.com/
It's called SmartFlash. It isn't free - but it works well
Hello, I haven't work with PNG in Delphi, so I'm looking for advices about next problem: I have to show picture over picture, but I can't manage with the transparent spots, so the below one to be visible where the above should be transparent. I tried with Image component and pnglibrary, but still have no solution.
I don't know what that has to do with the article you're commenting on but
TImage
andTPngImage
support transparent PNGs just fine.Thanks, i really appreciate this tutorial.
Hi! I wonder if it is possible to use into a form with buttons? Thanks
Thanks for professional tutorial. It was really what I needed for my free desktop widgets engine.
You can download the Delphi TPNGImage from various sources. Like http://code.google.com/p/livreerp/downloads/list
Excellent article! Well written and to the point. It is a bit outdated though and I think more people could benefit if it was updated for Delphi 2010 etc. I Googled for quite some time before I found this article.
For example Embarcadero has now purchased to PNGImage source code and it is now included in the VCL from Delphi 2009 so there's no need for 3rd party libraries.
http://blogs.embarcadero.com/n...../13/39100/
For me, this solution worked - without GDI+:
I copy the ARGB image to a temporary bitmap and draw text on this bitmap using normal Canvas methods. These methods, however, always draw transparent objects, so I set the alpha channel for all areas where I drew on the image to 255 afterwards. This works for me because the areas of the image where I put my text on are not transparent (it is a splash screen with transparent borders):
… thans for the great article, anyway.