There are some circumstances when it makes sense to use device-independent bitmaps (DIB). Here is a list of factors that would make DIBs desirable:
- Your Win 32 application uses them.
- Your application depends on photographic quality images.
- Your application sets or actively manages palettes.
- Your application copies bitmaps from the screen, modifies them, and then copies them back to the screen.
If your application uses DIBs, you can load them by name, using this API:
HBITMAP SHLoadDIBitmap(LPCTSTR szFileName);
Notice that the filename parameter is typed LPCTSTR. This is a long pointer to a TCHAR, and to successfully load the file, the filename string must be in Unicode. This is how to use SHLoadDIBitmap() with a literal string as a file name:
Windows CE supports color depths of 1, 2, 4, 8, 16, 24, and 32 bits per pixel. Most of the time, devices organize some or all of the available colors by using a structure called a palette. Often, even if a device is theoretically capable of displaying millions of colors, it can only display a subset of them simultaneously. The colors available for display are the onex in the currently selected palette. When you get or create a display context, (using GetDC() or CreateCompatibleDC(), for example ), Windows CE creates a default palette for that device context. The exact composition of that palette may differ across devices because there is no standard Windows CE color palette.
DIBs contain their own color information in an array of structures that follows the DIB header information. The color of individual pixels in the image is determined by indexing this color table. Windows CE matches the colors specified by the DIB as closely as it is able, using the colors currently available in selected palette. Windows CE does not support dithered colors.
Device-dependent bitmaps simply contain RGB color information for each pixel. You don’t get the benefit of the color arbitration step that happens when a DIB is rendered, and if you try to display an image with greater color depth than the device supports, at best the attempt will fail. At worst, your application may crash and lock up the CE device.
Pens, Brushes, & Fonts
If possible, you should try to stick with the available stock pens and brushes. There are always present, and live in ROM, so they come to your application at no memory cost. You also don’t have to worry about freeing them when you are finished using them.
|Table 3—Windows CE Stock Objects|
|GetStockObject() Constant||Object Properties|
|DKGRAY_BRUSH||Dark gray brush|
|HOLLOW_BRUSH||Hollow brush doesn’t erase what it paints (equivalent to NULL_BRUSH)|
|LTGRAY_BRUSH||Light gray brush|
|NULL_BRUSH||Same as HOLLOW_BRUSH)|
|SYSTEM_FONT||System font. By default, the system uses the system font to draw menus, dialog box controls, and text|
|DEFAULT_PALETTE||The default set of colors|
The number of each type of object in the stock objects collection is instructive. There are several brushes, which in practice are small, grayscale bitmaps. There are only two pens, a black one and a white one—and what doesn’t show up in the table is that each of the pens is 1 pixel wide. Next, there’s a single system font, and we finish with the default palette.
This set of objects is designed to be highly portable—it reproduces well even on one-bit devices. It is also designed to use an absolute minimum of memory for these necessary resources. What I take from this example is that it’s possible to do an extraordinary amount of productive work, without an elaborate graphical infrastructure. Examine what it is you need to accomplish with graphics in your application, and if at all possible consider paring down your working set of graphic objects, especially paying attention to the following:
- Always use the system font.
- Don’t create pens that are more than 1 pixel wide. Drawing with wider pens is computationally intensive, slows performance, and escalates power consumption.
- Avoid the use of Ellipse() and RoundRect where possible; these are also computationally intensive.
Usability studies have shown that human vision is optimized for recognizing contrast and locating edges. The tiny, backlit screens featured in most CE devices wash out in even moderate light. This argues against using a large palette of colors and against serif, rotated, or decorative fonts.
Porting Tip: For greatest application usability and readability, employ graphics and fonts that display dark, sharp-edged features against a white background.
Device-independent bitmaps take their name from the fact that they include color information along with image data. The advantage of this is that they can be dynamically adjusted to paint properly on any display device, with the disadvantage that the color information takes up space and significantly complicates the process of reading a file and rendering the bitmap. For this reason, if you use DIBs, you use different APIs to access them. On CE devices, unlike on the desktop, we use the function SHLoadDIBitmap() to get a handle to the DIB. After that, the steps required to manipulate and display the image are more or less the same ones you would use with a device-dependent bitmap. The example application PasteDIB shows these steps, but because it’s much like the bitmap code you’ve already seen, we’ll just highlight the differences here. (The sources and support files are included in their entirety on the accompanying CD.)
First, for many CE platforms, you’ll need a special header file, shellapi.h:
Some of the earlier CE devices declare their shell functions in commctrl.h, so try this header instead if you come up with a compiler error on shellapi.h.
Next, we load the bitmap file by name in response to the WM_PAINT message:
case WM_PAINT: RECT rt; hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); //use a null-terminated Unicode string for the file name hbmpDIB = SHLoadDIBitmap( TEXT("WindowsClouds.dib")); //now, use the returned bitmap handle in the typical ways hdcMemory = CreateCompatibleDC( hdc ); SelectObject( hdcMemory, hbmpDIB ); GetObject( hbmpDIB, sizeof(BITMAP), &bmp ); BitBlt(hdc, 0, (GetSystemMetrics(SM_CYSCREEN ) / 8 ), bmp.bmWidth, bmp.bmHeight, hdcMemory, 0, 0, SRCCOPY ); EndPaint(hWnd, &ps); break;
Notice two things about this code fragment. First, we use the TEXT() macro to format a literal string for the file name. Under CE, all filenames and user interface text strings are Unicode. SHLoadDIBitmap() will fail if the filename string is not Unicode. Also, notice that we have specified a fully qualified pathname, WindowsClouds.dib, for the DIB file. When you copy files, a CE device to try DIBPaste; you’ll need make sure that Clouds.dib ends up there. Finally, notice that once we retrieve a handle to the bitmap data contained in the DIB file, we can treat it in the same way as we’d treat any other bitmap.
Perhaps the most noticeable differences in the graphics programming you’ll undertake for CE hinge on the fact that users rely heavily or even exclusively on the “touchable screen” metaphor implemented in the stylus. In some cases, programming for stylus “taps” isn’t awfully different than programming for mouse clicks. When it comes to the stylus as a text input device, however, things definitely begin to become a bit more complex.
In the next series of examples, we’ll explore handling the stylus and the ink control. In the process, we’ll look into what you can do to make your Win32 applications stylus capable as quickly and effectively as possible.
About the Author
Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, entry time data validation.
In addition to writing for Developer.com, she has written several books including Making Win 32 Applications Mobile. She has also written numerous articles on programming technology for national publications including Dr. Dobbs, BYTE Magazine, Microsoft Systems Journal, PC Magazine; Computer Shopper, Windows Sources and Databased Advisor.
# # #