Palette problems

Palettes haven’t been much of an issue for Visual Basic programmers. Sure, the last several versions included a few DIB files (rainbow, bright, and pastel) with some obscure instructions about how you can use them to change the palette of your forms. But this was a halfway solution that few programmers took advantage of. This version takes another step toward full palette control. The Palette property lets you assign a custom Palette for a form, and the PaletteMode property gives you some control over which palette will be used. You can learn more about the details from the documentation.

“Wait,” you’re saying. “What’s a palette anyway?” Well, some bitmaps have what’s called a logical palette. This is an array containing all the colors that the bitmap would like to use. So if your bitmap has a reddish hue, it will probably have a palette full of reds. Palette colors are a limited resource. There are slots for 256 colors in most contexts on common video adapters. The problem is that all the bitmaps in the system have to get their colors mapped into those same slots. If there are several bitmaps visible on the screen, they will all be fighting for those same slots. There’s a constant battle with colors being mapped in and out of the system palette as the focus switches between programs. Your bitmaps will have a better chance of displaying themselves correctly in the foreground and in the background if you supply a list of your desired colors (and only those colors) rather than trying to use whatever the system has available. If you are fortunate enough to have access to a real bitmap editor—the wretched ImagEdit supplied with Visual Basic won’t edit bitmaps with palettes—you should use no more than 236 colors so that your choices won’t conflict with the 20 reserved system colors.

And that’s the short version of a very long story.

To see what WinWatch does with palettes, let’s imagine that the ShowBitmap function is looking at bitmap resource 6603 in VB5IDE.DLL. This is one of three 256-color bitmaps of a Visual Basic logo that looks like it must be used in the splash screen. Resources 6600 to 6602 are 16-color versions of the same bitmaps. I’d show you a screen dump, but unfortunately I wasn’t able to persuade my publisher to print this book in 256 colors. If I were to convert this bitmap to a picture without the palette, the system wouldn’t know how to set the hPal property of the picture. And without the palette, Visual Basic would do its best with the system palette rather than use the palette designed for the bitmap. So I load the real palette with LoadBitmapPalette.

After loading the bitmap and palette handles and applying them with Bitmap­ToPicture, Visual Basic has the information it needs to ask Windows to render the bitmap on the picture box in all its glory. Of course, you needn’t take my word for it. WinWatch displays the colors of the palette used at the bottom of the resource picture box. The Browse Picture program shows a similar palette display for bitmaps loaded from files.

The palette display is created by DrawPalette, a procedure that takes a destination canvas (such as the picture box), a palette handle to be drawn, and some optional parameters indicating where and what size to draw. You can see the full code in PALTOOL.BAS, but I’ll summarize briefly. First DrawPalette gets the size of the palette using the PalSize function. This is just a wrapper for a variation of the multi-purpose GetObject function, which tells you everything you want to know about any GDI object. DrawPalette then allocates a dynamic array containing the appropriate number of PALETTEENTRY elements. The PALETTE­ENTRY UDT consists of four bytes for the red, green, blue, and flags elements of a color. Next the procedure calls the GetPaletteEntries API function to fill the array with the actual colors of the palette. And finally it loops through the colors, drawing a vertical line for each of them. The width of each line is calculated by dividing the width of the display area by the number of colors.