Previous Book Contents Book Index Next

Inside Macintosh: Advanced Color Imaging on the Mac OS /
Chapter 1 - Palette Manager / About the Palette Manager

Colors in a Palette

When the user activates a window, the Palette Manager examines the window and its palette to determine how many screens the window touches and whether colors need to be loaded into any device's color lookup table. If your window requires 180 shades of green, for example, chances are the current device color tables lack the necessary colors. Whether the Palette Manager must change a color table depends on what colors are in it already, what colors you ask for, and the categories into which your colors fall.

When using Color QuickDraw you specify colors as RGB values. An RGB color is defined by its red, green, and blue components, which you specify in an RGBColor data structure. The brightest white consists of three maximum integer values (65535); black is three minimum values (0); grays are any three equal values between white and black. See the "Color QuickDraw" chapter of Inside Macintosh: Imaging With QuickDraw for further information about RGB colors and the RGBColor structures you use to specify them.

You may know the RGB values of the colors you need, or you may determine them by trial and error or by using a color picker.

Generally, the Palette Manager comes into play implicitly in your application; that is, you first create a palette and attach it to a window. Then, when you display an image or draw in the window, if any of the colors you specify is not available in the color table, the Palette Manager loads them for you, if it can.

The Palette Manager also provides two functions, PMForeColor and PMBackColor, that enable you to draw explicitly with a palette's colors. Each of these functions takes a palette entry as an argument. You can use PMForeColor and PMBackColor with any type of color (see the rest of this section for a description of the different usage categories that determine the type of a palette color, including courteous, tolerant, animated and explicit). You must use PMForeColor and PMBackColor when drawing with animated colors. See "Drawing With a Palette's Colors" (page 1-31) for more information on when and how to use the Palette Manager drawing functions. The PMForeColor function (page 1-16) and PMBackColor function (page 1-17) are described in Advanced Color Imaging Reference.

The Palette Manager tracks colors in usage categories, which you specify to control the way the Palette Manager allocates your palette's colors. When you create your palette, you assign usage categories to colors with the usage constants in the color information record--see "The Color Information Structure" in Advanced Color Imaging Reference. You can change the categories by using Palette Manager functions. You can assign any of the following categories to each color in your palette. The four categories, courteous, tolerant, animated, and explicit define the types of colors that the Palette Manager provides. (Note that some of the categories can be combined.)

The next two groups of categories, inhibited and pmWhite/pmBlack are always used with one or more of the four color-type usage categories just defined.

You can combine several color usage categories. You can specify that a color is both tolerant and explicit, for example, which means that your RGB color, or a tolerably close match, is placed in the color table at the index corresponding to that palette entry (as opposed to merely being available somewhere in the table) on all devices that touch the window. See "Combining Color Usage for an Entry" (page 1-15) for additional information on combining two or more color usage categories.

Typically, you create a palette in which all colors have the same usage, and then if any entries need to be in a different category, you change them with Palette Manager functions.

The following sections describe the usage categories in more detail.

Courteous Colors

Courteous colors have no special properties, but they can serve as convenient placeholders. If your application uses a small number of colors, you can order them in a palette according to your preference and designate them as courteous.

Colors with specified usage categories that can't be satisfied by the Palette Manager default to courteous colors. This occurs, for example, when drawing to a direct device or one with a fixed device color table.

Suppose you have an open window named myColorWindow that has a palette resource consisting of a set of eight colors: white, black, red, orange, yellow, green, blue, and violet, in that order, each with its color usage specified as courteous, as shown in Table 1-1.

Table 1-1 Table 1-1 A courteous palette
IndexRGB valueUsage

The following example paints the rectangle myRect in yellow (palette entry 4, where white is 0).

SetPort (myColorWindow);
SetPalette (myColorWindow, srcPalette, TRUE);
PmForeColor (4);
PaintRect (myRect);
This is exactly analogous (if the usage is courteous) to the following sequence of Color QuickDraw functions, where yellowRGB is of type ColorSpec: = $FFFF; = $FFFF; = $0000;

SetPort (myColorWindow);
SetPalette (myColorWindow, srcPalette, TRUE);
RGBForeColor (yellowRGB);
PaintRect (myRect);

Tolerant Colors

Tolerant colors allow you to change the current color environment if the available colors are not sufficiently close to those your application needs. When your window becomes the frontmost window on a device, its palette's colors are given preference. Each tolerant color is compared to the best match available in the current color environment. (In a multiscreen environment this comparison is done for each device on which the window is drawn.) When the difference between your color and the best available match is greater than the tolerance you specify, the Palette Manager loads an exact match into the device color table.

The Palette Manager compares the tolerance value associated with each palette entry to a measure of the difference between two RGB color values. This difference is an approximation of the distance between the two points as measured in a Cartesian coordinate system where the axes are the unsigned red, green, and blue values. The distance formula used is

RGB = maximum of (abs(Red1 - Red2), abs(Green1 - Green2), abs(Blue1 - Blue2))

A tolerance value of $0000 means that only an exact match is acceptable. (Any value of $0xxx other than $0000 is reserved and should not be used in applications.) A value of $5000 is generally sufficient to allow matching without updates in well-balanced color environments, such as those provided by the default palettes.

The color needs of your application determine the tolerance value to set for palette entries. For example, if your application is a drawing program in which exact colors are required, then you will specify a tolerance of zero for your palette entries. On the other hand, if exact matching is not a requirement, specifying a higher tolerance such as $5000 is a good idea because it eliminates updates which can cause annoying screen flashes and also alter the color environment for other applications.

If your palette requires more colors than the number of unreserved table indexes, the Palette Manager checks to see if some other palette has reserved indexes for animation. If so, it cancels their reservation and makes their indexes available for your palette.

If you ask for more colors than are available on a device, the Palette Manager cannot honor your request. Color requests that can't be met default to courteous colors, and the Color Manager selects the best color available. That selection will, of necessity, match one of the colors elsewhere in your palette, because the Palette Manager runs out of colors only after it has given your palette all that are available. This function works as well as possible for a given device, but of course, works better if your window is moved to a device of greater pixel depth where the request can be met.

Note that two tolerant entries may match to the same index even if space isn't the problem. For instance, when all indexes are initially assigned to black, activating a palette with 256 shades of gray with tolerance of $2000 uses up four indexes, that being sufficient to match all 256 shades within a tolerance of $2000. If the tolerance value were decreased to $1000, then eight indexes would be altered.

On direct devices, tolerant entries always match as close to exactly as the hardware allows (to the first 8 bits of each component).

Animated Colors

Animated colors allow you to create color-table animation effects while lessening the disturbance caused other windows.

One way to change the color of an object on the screen is to change the pixel values in the object's part of the pixel map--you draw it again in a different color. In certain situations, you can get the same effect at less cost in processing and memory by changing the colors in the video device's color table instead. All pixel values corresponding to the altered indexes immediately appear on the display device in a new color. By careful selection of index values and the corresponding colors, you can achieve a number of special animation effects.

Note that no objects move in this animation; rather, the animation gives the appearance of motion, like the lights of a movie marquee.

To use an animated color, you must first draw with it using the PmForeColor or PmBackColor function. To create color-table animation, you then change that entry's RGB color by using the AnimateEntry function. You can animate a contiguous set of colors by using the AnimatePalette function to supply RGB colors from a color table.

The way the Palette Manager reserves indexes for animated colors creates some side effects. The Palette Manager first checks each animated color to see if it already has a reserved index for the target device. If it does not, the Palette Manager checks all windows and reserves the least frequently used indexes for your palette. (This reservation process is analogous to that used by the Color Manager function ReserveEntry.) The device's index and its corresponding color value are removed from the matching scheme used by Color QuickDraw; you cannot draw with the color by calling RGBForeColor. (However, when you call PmForeColor, the Palette Manager locates the reserved index and configures your window's port to draw with it.) On a multiscreen system the index reserved is likely to be different for each device, but this process is invisible to your application.

After reserving one device index per device for each animated color it detects, the Palette Manager changes the color environment to match the RGB values specified in the palette.

The Palette Manager returns the indexes used by your animated entries to each screen device when any of the following occur:

The Palette Manager replaces previously animated indexes with the corresponding colors from the default color table for that device.

The Palette Manager receives notice when the screen depth changes, so that it can take appropriate action at that time, such as setting color tables to their defaults.

Displaying Animated Colors on Direct Devices

Color-table animation doesn't work on a direct device because it has no color table. To present the best appearance, for example, on a window that spans an indexed device and a direct device, the Palette Manager records two colors in the ciRGB field of the ColorInfo structure: the last color the entry was set to by the SetEntryColor function and the last color the entry was set to by the AnimateEntry or AnimatePalette function. In the ColorInfo structure, the high bytes of the components in the ciRGB field reflect the animated color, and the low bytes contain the color set by SetEntryColor. (The GetEntryColor function returns the last color to which the entry was animated.) When you draw with an animated color on a direct device (or on any device on which the animated color was not allocated and reserved), then the color set by SetEntryColor is used. This allows successive updates of an animated image on a direct device to match correctly. A side effect is that GetEntryColor does not necessarily return an exact match of the color originally set (only the top 8 bits are an exact match).

This internal usage of color information fields may change. For maximum safety, use the functions SetEntryColor, SetEntryUsage, GetEntryColor, and GetEntryUsage.

Explicit Colors

Use explicit colors when your primary concern is the index value rather than the color stored at that index.

Explicit colors cause no change in the color environment. For indexed devices, the Palette Manager ignores the RGB value in a palette if a color is an explicit color. When you draw with an explicit color, you get the color that is currently at the entry in the device color table whose index corresponds to the explicit color's position in the palette. When you call PmForeColor with a parameter of 12, it places a value of 12 into the foreground color field of your window's color graphics port. (Since the value wraps around the table, the value placed into the foreground field would be

12 modulo (maxIndex + 1)

where maxIndex is the maximum available index for each device under consideration.)

On direct devices an explicit entry produces the color for that entry in the palette.

You can use explicit colors to monitor the color environment on an indexed screen device. For example, you could draw a 16-by-16 grid of 256 explicit colors in a small window. Whatever colors appear are exactly those in the device's color table. If color-table animation is taking place simultaneously, the corresponding colors in the small window animate as well. If you display such a window on a 4-bit device, the first 16 colors match the 16 colors available in the device, and each row thereafter is a copy of the first row.

Inhibited Colors

The Palette Manager recognizes six inhibited usage categories that give you control of which palette entries can and cannot appear on depths of 2, 4, and 8 bits per pixel, on color or grayscale devices. The categories are specified using these constants:

enum {
      pmInhibitG2 = $0100; /* inhibit on 2-bit grayscale device 
      pmInhibitC2 = $0200; /* inhibit on 2-bit color device */ 
      pmInhibitG4 = $0400; /* inhibit on 4-bit grayscale device 
      pmInhibitC4 = $0800; /* inhibit on 4-bit color device */ 
      pmInhibitG8 = $1000; /* inhibit on 8-bit grayscale device 
      pmInhibitC8 = $2000; /* inhibit on 8-bit color device */ 
Here is an example of how these categories can be combined:

myColor8Usage = SetEntryUsage(myPalHandle,270,pmAnimated+         
This example sets the usage of entry 270 of the palette specified by myPalHandle to the combined usages of animated and explicit, to be allocated only on color 8-bit devices. See "Selecting the Right Color Set" (page 1-25) for a further example of inhibiting particular colors on different types of devices.

You should always inhibit tolerant colors on grayscale devices. The default color table on a grayscale device is an evenly spaced gray ramp from black to white. Since this is usually the best possible spread on a grayscale device, you could specify all three inhibited grayscale categories.

As another example, on a 4-bit device you might want to allocate 14 tolerant colors, while on an 8-bit device there are sufficient indexes that you can also use a number of animated colors. By inhibiting the animated entries on 4-bit devices, you ensure that your 14 tolerant colors are allocated. Merely sequencing the palette doesn't solve this problem because the animated colors always take precedence over the tolerant colors.

Combining Color Usage for an Entry

You must always combine the inhibited usage category with some other usage category. In addition, you can combine the explicit usage category with the tolerant and animated categories if you wish.

The main purpose for using explicit colors is to provide a convenient interface to color table indexes. The PmForeColor function configures the color graphics port to draw with the index of your choice. So that you can easily create effective explicit palettes, two color usage categories can be combined: pmTolerant + pmExplicit and pmAnimated + pmExplicit.

The pmTolerant + pmExplicit combined usage means that you get the color you want at the index you want, across all devices that the window touches. As with pmTolerant, other windows may use those colors in their displays.

The pmAnimated + pmExplicit combined usage means that you get the color you want at the index you want, across all devices that intersect the window, but windows that don't share the palette can't use that index. The entry can be animated by a call to the AnimateEntry function.

Since the value of an explicit entry is treated as the entry modulo the bit depth, index collisions can occur between entries of the same usage within a palette. In this case, the lower-numbered entry gets the index. For example, if palette entries 1 and 17 were both pmAnimated + pmExplicit, then on a 4-bit screen, entry 1 would get index 1, and entry 17, although it wraps around to 1, would get nothing.

Unallocated pmTolerant + pmExplicit colors revert to pmTolerant. Unallocated pmAnimated + pmExplicit colors revert to pmCourteous.

Sequencing the Entries

Using the inhibited usage categories is the best way to be sure that the right colors are available for screens of different depths, but in many situations you can achieve the same effect with a single set of colors if you sequence the colors in the palette or arrange them according to the screen depth of the device that uses them, from least to greatest depth.

Color QuickDraw, to support standard QuickDraw features, puts white and black at the beginning and end, respectively, of each device's color table, and the Palette Manager never changes them. Thus the maximum number of indexes available for animated or tolerant colors is really the maximum number of indexes minus 2.

After white and black, you should assign the next two colors to the two you wish to have if the device is a 2-bit device. Likewise, the first 16 colors should be the optimal palette entries for a 4-bit device, and the first 256 colors should be the optimal palette entries for an 8-bit device. You should inhibit colors for grayscale devices.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
13 NOV 1996