Perl/Tk Transparent Icons
Update (2007-12-11): I've created a web-based XBM mask generator tool. Use it to create XBM masks.A problem that a lot of programmers run into after working with Perl/Tk programs for a while is that it's not very easy to create a non-square icon for our windows. In other words, having a transparent window icon is not an easy task to accomplish.
First of all, we can't very easily use Windows .ico files for our window's icons. No, our icons have to be a regular image of some format, such as a PNG or a GIF image. And the typical way to create a custom icon for your window is:
use Tk; use Tk::PNG; my $mw = MainWindow->new(); my $icon = $mw->Photo ( -file => 'my_icon.png', -format => 'PNG', ); $mw->Icon (-image => $icon); MainLoop;
use Tk; use Tk::PNG; my $mw = MainWindow->new ( -title => 'Cuvou.com', ); $mw->geometry ('200x30'); my $icon = $mw->Photo ( -file => 'firefox-icon.png', -format => 'PNG', -width => 32, -height => 32, ); $mw->iconimage ($icon); MainLoop;
The solution to having our transparent icon work is a little bit tricky. We'll need to create a mask file to define the transparent bits of our icon. Fortunately, some imaging programs out there can save images into the format required for the mask file. Namely, The GIMP. If you're a Linux user, you might already have this program installed, and if not it's probably easy to get through your package manager. For Windows users, don't fear: there's a GIMP for Windows too.
Simply open up the PNG image you wanted for your window icon, do a "File/Save As", and make sure you select to save it as an "X BitMap Image (xbm)" file.
Go ahead and click "Save". It will warn you about how you should export your image first. Go ahead and click on "Export" to have it do it for you.
Pay extra care to the next part. While it's going to save our image as an XBM format (or X bitmap image), the thing we really want it to do is to create a mask XBM of our icon. So make sure that the "Write extra mask file" option is selected. Note: if this option is disabled, it means your image probably didn't have any transparency in it. Double check that if this is the case.
I also check the "Write hot spot values" too, only because the example XBM files from Tk's demo directory has hot spots at (16,16) on their 32x32 pixel image. Go ahead and click on "Ok" and it will save your XBM images.
It will create two images: "firefox-icon.xbm" and "firefox-icon_mask.xbm" in this case. We're only interested in the mask file. If you view it in a text editor, you would see this:
#define firefox_icon_mask_width 32 #define firefox_icon_mask_height 32 #define firefox_icon_mask_x_hot 16 #define firefox_icon_mask_y_hot 16 static unsigned char firefox_icon_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0xc0, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0x03, 0x00, 0xfe, 0xff, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
Now, back to our code. Now that we have our mask bitmap, we can tell our MainWindow to use it as our icon mask (note: icon masks will only accept bitmaps).
use Tk; use Tk::PNG; my $mw = MainWindow->new ( -title => 'Cuvou.com', ); $mw->geometry ('200x30'); my $icon = $mw->Photo ( -file => 'firefox-icon.png', -format => 'PNG', -width => 32, -height => 32, ); $mw->iconimage ($icon); $mw->iconmask ('@firefox-icon_mask.xbm'); MainLoop;
Success!
Now, I mentioned that this works by using X BitMaps, and that Tk has a handful of built-in bitmaps. Here is a screenshot of the `widget` program under Linux which lists all of the built-ins:
So, if we wanted our window to use the questhead bitmap, we would simply tell it to use the bitmap for both the icon and the icon mask:
use Tk; use Tk::PNG; my $mw = MainWindow->new ( -title => 'Cuvou.com', ); $mw->geometry ('200x30'); $mw->iconbitmap ('questhead'); $mw->iconmask ('questhead'); MainLoop;
By now I hope that the elusive transparent window icon how-to has become clear. I know personally that this was quite an elusive monster to tackle and all I ever found via Google were others asking the very same question on forums all over the place, but nobody got any answers back.
~Casey Kirsle
Dec. 8, 2007
Downloads