Eclipse Corner Article |
Summary
The combination of platforms, display devices and color depth makes providing an easy to use yet powerful and portable color model an interesting challenge. In this article we will examine the color management models of Windows® and X/Motif and then dig into the makings of the SWT color model and its implications for client code.By James Moody & Carolyn MacLeod OTI
April 24, 2001
Color management on Windows depends on the depth of the display, which can be either low-color (usually 8 bits per pixel or less) or high-color (typically 15 bits per pixel or higher). On low-color displays, the concept of a Palette is important. A palette is simply a logical grouping of colors. When a color is requested, the system can either put the color in the palette, or, if the palette is full, do a closest match of the colors in the palette to find a reasonable facsimile.
Windows allows the user to define and use one palette per graphics context (GC), or to use the default system palette that is on the display. The advantage of defining your own palette is space: it is initialized as empty, and you have the entire capacity to fill with your own colors. On the other hand, the system palette undoubtedly already has many colors in it, especially if other applications are using it; the user may not be able to use the entire capacity for his or her own application. Using the system palette has its advantages, however. For one, it is easier to use: simply use your colors normally, and the system will take care of mapping them to the system palette. Secondly, switching between two applications that are both using the system palette will be smooth. Switching between two applications that use different palettes will result in a visible flash as Windows maps the appropriate palette and takes colors away from the application that no longer has control.
On high-color displays, colors are effectively free: one can simply use RGB values without any regard to palettes or color availability.
On high-color displays, where the pixel value encodes the RGB value of the color, colors are free as they are on Windows. Although the surest way to use colors on a high-color display is still to use XAllocColor, one can simply encode the RGB values into pixel values and use the pixels directly, without having to allocate or free the colors.
Palette
as a class to the SWT
user:Palette
as a class to the SWT user, and allow the Palette to be set into a
GC. One problem with this approach is that X's palette solution is
undesirable due to its flashy behavior. This approach maps better to Windows
due to the platform’s improved palette switching capabilities. On X, however,
given the above limitation, SWT would want to give the illusion of palettes
to the developer, while mapping colors to the default colormap underneath.
Another problem is that of managing the palettes of multiple GCs in
the same window; on Windows, the colors from these palettes would need to
be somehow combined into a single palette when the window is given focus.
Providing user palettes would also require SWT to implement a default palette,
which would add complexity to the palette management code. Providing the user with palettes that they can manage (as described in the first option – “expose palette as a class”) sounds like a good solution, but in practice, it makes client code very complex and hard to manage. Given the simple color requirements of typical applications, this option was ruled out.
Thus, the only remaining option (the last one listed above), allocating and disposing of colors independently, forms the basis of SWT's color model.
On palette-based displays under X, SWT does not create a private colormap (palette), but instead uses the default colormap to avoid flashing and undesirable behavior. When the user allocates a Color, SWT tries to allocate the color with XAllocColor. If this succeeds, the user gets exactly the color they asked for, and that color is remembered by the Display. If it does not succeed, SWT finds the closest available color and uses that instead. In both cases, the reference count for that Color is incremented.
When a Color is disposed on X, SWT will call XFreeColor, which decrements the reference count on the X Server. As well, SWT will decrement its internal reference count for that Color, and remove it from the Display if the reference count is zero.
On high-color displays on both Windows and X, the SWT display does not maintain a palette. Colors are still allocated and freed on X, but this operation simply calculates the pixel value and nothing else. On 24-bit and higher displays, the user is guaranteed to get exactly the color requested. On 16-bit displays, the user will get a very close approximation, but not necessarily the exact color, due to the fact that 16-bit pixel values cannot encode 8-bit red, green and blue values with 100% accuracy. Low-color displays that use a lot of colors may still flash.
SWT provides access to the standard colors through Display.getSystemColor(int). The following snipet returns the standard color for green.
display.getSystemColor(SWT.COLOR_GREEN)
The creator of an SWT Color is responsible for disposing of the color when it is no longer required. In the above snipet we did not actually create the color, consequently we must not dispose of the color.
When an SWT image is loaded, code similar to the following is usually used:
Image image = new Image(display, "filename");
Image loading is actually a two-step process. In the first step, SWT loads the image into a device-independent, format-independent object, called ImageData. The second step involves creating the actual device-dependent Image from the ImageData. Before this can happen, the colors that the image desires must be mapped to colors that are actually available on the device. On a true-color display (high-color display with at least 24-bit color), the colors are always available.
On a low-color display the RGB values contained in the ImageData's palette are mapped to the closest match available in the SWT palette. The colors that are available depend on which colors the user has already allocated. If the user has not allocated many colors, then there may not be many colors in the SWT palette for SWT to do a closest match to. SWT does not allocate application colors. For this reason, it may be desirable to pre-allocate the colors needed for the image. In the example above, however, there is no place to allocate the colors; the user doesn't know what colors the image needs before it is created. In situations like these, code such as the following may be useful:
ImageDate imageData = new ImageData("filename"); rgbs = imageData.getRGBs(); colors = new Color[rgbs.length]; for (int i = 0; i < colors.length; i++) { colors[i] = new Color(display, rgbs[i]); } image = new Image(display, imageData); ... // dispose the image and colors when no longer needed
In this example, the two-step process is revealed to the user, giving an opportunity to construct colors before the image is created, resulting in a more realistic image. In practice, this is not needed, since most displays are high-color.
The way SWT does image loading presents one possible difficulty. What if the user allocates some colors, loads an image, and subsequently frees some colors? There is a possibility that the image has chosen some of the colors that the user freed. In this case, unpredictable results can occur after the colors have been freed. Fortunately, this is very easy to work around: always allocate your colors in a static fashion, and free them when you are finished with them. This model is described in the section "Tips for Color Management in SWT".
Microsoft, Windows, Windows NT, and the Windows logo are trademarks of Microsoft Corporation in the United States, other countries, or both.