Important: The information in this document is obsolete and should not be used for new development.
Creating Palettes
This section shows you several different ways to create a palette. The first example uses theNewPalette
function in a loop to create a 16-color palette with 14 shades of red plus black and white. The second example shows how to create a resource file containing the same 16 colors and shows you how to select the right color set by inhibiting certain colors on different screens. It also shows how to copy a palette from a color table and assign the palette to a window.Creating a Palette in Code
The Palette Manager is particularly useful when your application needs to display an image that uses a narrowed or skewed color set. For example, suppose that your application displays PICT images on a 4-bit depth screen and that a particular image contains only shades of red. By default, the system provides a range of colors to use. If your application uses these 16 default colors to display the red PICT file, the display will lose all subtlety. With the Palette Manager, you can create a special palette containing red hues only to display this PICT image.
Listing 1-1 shows how to create a palette containing shades of red only.
- Note
- This example assumes that the PICT image to display uses shades of red. One way to obtain information about a picture to display is by using the Picture Utilities, described in the chapter "Pictures" of Inside Macintosh: Imaging With QuickDraw. The Picture Utilities allow you to obtain various information about a picture to display, including the most used colors in the picture. The Picture Utilities are available in system software version 7.0 and later.
Listing 1-1 Creating a red palette
PaletteHandle DoMake14RedPalette (void) { long iterator; PaletteHandle myPalette; RGBColor color; myPalette = NewPalette(14, nil, pmTolerant, 4000); /* check here for nil result */ color.green = 0; color.blue = 0; for (iterator = 0; iterator < 14; iterator++) { /* range red component from 1/14 to 14/14 */ /* iterator is a long, so it can safely be multiplied by 65535 */ color.red = (iterator+1) * 65535 / 14; SetEntryColor(myPalette, iterator, &color); }; return ( myPalette ); }In Listing 1-1, theDoMake14RedPalette
function creates a new 14-color palette containing 14 shades of red. The Palette Manager always guarantees that black and white are available to an application so that menus, windows, and other such things display properly. Therefore, you can load at most 14 new colors from a palette into a 16-color lookup table because the Palette Manager will not overwrite white (the first entry) or black (the last entry).After defining three variables, the
DoMake14RedPalette
function calls theNewPalette
function to create a palette large enough to hold 14 colors. Thenil
value passed as the second parameter specifies that the palette not be created from a color lookup table. In this case, the Palette Manager sets all three fields of each color to 0 (black). In essence,NewPalette
has created a palette template. TheSetEntryColor
function later fills in, or changes, the color value for each color in the palette. TheNewPalette
function defines each color as tolerant with a tolerance of $4000.Because this palette contains shades of red only, the green and blue fields of the
color
variable are set to 0. The code then defines 14 shades of red in a loop by dividing the maximum red value (65535) by 14 and adding 1/14 of 65,535 each time through the loop. Each time through the loop, theSetEntryColor
function places a shade of red at the next palette entry (identified byiterator
, the iteration variable). When the loop is finished, the first 14 entries in the palette created by theNewPalette
function contain 14 evenly distributed shades of red.
- Note
- When the Palette Manager uses this palette--after you have attached it to a window with the
SetPalette
orNSetPalette
function--it looks at the colors of the color lookup table for the 4-bit display device and determines which of the 14 colors in the palette it must load. It then loads as many of the 14 palette entries as necessary to create the 14 shades of red defined in the palette. The Palette Manager keeps the first entry in the table as white and the last as black and uses the other 14 indexes as necessary to load the shades of red. See "How the Palette Manager Allocates Colors for Display" (page 1-17) for more information on how the Palette Manager loads colors from a palette into a color lookup table.Creating a Palette in a Resource File
The format of a palette resource (type'pltt'
) is an image of the palette structure minus the private fields. The private fields in both the header and in eachColorInfo
record are created by theGetNewPalette
function and are reserved for future use.Listing 1-2 shows a palette resource with 16 entries as it would appear within a resource file. The black and white entries each have a tolerance value of 0, meaning that their color should be matched exactly. The shades of red have a tolerance of $4000.
Listing 1-2 A palette (
'pltt'
) resource
resource 'pltt' (128, "Simple Palette") { { /* array ColorInfo: 16 elements */ /* [1] white */ 65535, 65535, 65535, pmTolerant, 0, /* [2] 2 through 15 are shades of red */ 4681, 0, 0, pmTolerant, $4000, /* [3] */ 9362, 0, 0, pmTolerant, $4000, /* [4] */ 14043, 0, 0, pmTolerant, $4000, /* [5] */ 18724, 0, 0, pmTolerant, $4000, /* [6] */ 23405, 0, 0, pmTolerant, $4000 /* [7] */ 28086, 0, 0, pmTolerant, $4000, /* [8] */ 32768, 0, 0, pmTolerant, $4000, /* [9] */ 37449, 0, 0, pmTolerant, $4000, /* [10] */ 42130, 0, 0, pmTolerant, $4000, /* [11] */ 46811, 0, 0, pmTolerant, $4000, /* [12] */ 51492, 0, 0, pmTolerant, $4000, /* [13] */ 56173, 0, 0, pmTolerant, $4000, /* [14] */ 60854, 0, 0, pmTolerant, $4000, /* [15] */ 65535, 0, 0, pmTolerant, $4000, /* [16] black */ 0, 0, 0, pmTolerant, 0 } };Use theGetNewPalette
function to obtain a'pltt'
resource; it initializes private fields in the palette structure. (Don't use the Resource Manager functionGetResource
.)The palette defined by the palette resource in Listing 1-2 is identical to the palette created in code in Listing 1-1 in the previous section except that white and black are explicitly placed in the palette in Listing 1-2. This palette contains black and white and 14 shades of red. The shades of red are defined by setting the green and blue values of each color entry to 0 and distributing the red color in 14 increments from the lowest to the highest value (65535). One possible use of this palette is to display a PICT file that contains only shades of red.
Selecting the Right Color Set
Different types of screens (for example, screens with different bit depths) often require different color sets to best display the same image. This section, like the previous section, uses an example of creating a palette to display an image in various shades of red. In addition, the code has been modified to display different colors on different screens.Listing 1-3 shows the code to display 14 shades of red on a 4-bit color screen, 254 shades of red on an 8-bit color screen, and no color requests at all on 2-bit screens or grayscale screens.
Listing 1-3 Displaying different colors on different types of screens
PaletteHandle MyMakeRedPalette (void) { long iterator; PaletteHandle myPalette; RGBColor color; myPalette = NewPalette(254+14, nil, 0, 0); /* check here for nil result */ color.green = 0; color.blue = 0; /* make 14 reds that are inhibited on all screens except 4-bit color */ for (iterator = 0; iterator < 14; iterator++) { /* range red component from 1/14 to 14/14 */ /* iterator is a long, so it can safely be multiplied by 65535 */ color.red = (iterator+1) * 65535 / 14; SetEntryColor(myPalette, iterator, &color); SetEntryUsage(myPalette, iterator, pmTolerant+pmInhibitC2+ pmInhibitG2+pmInhibitG4+ pmInhibitC8+pmInhibitG8, 0); }; /* make 254 reds that are inhibited on all screens except 8-bit color */ for (iterator = 0; iterator < 255; iterator++) { /* range red component from 1/254 to 254/254 */ /* iterator is a longint, so can safely be multiplied by 65535 */ color.red = (iterator+1) * 65535 / 254; SetEntryColor(myPalette, 14+iterator, &color); SetEntryUsage(myPalette, 14+iterator, pmTolerant+pmInhibitC2+ pmInhibitG2+pmInhibitG4+ pmInhibitC4+pmInhibitG8, 0); }; return ( myPalette ); }In Listing 1-3, theMyMakeRedPalette
function creates a palette that contains shades of red to optimally display an image that contains shades of red only. The palette contains two less colors than the maximum (14 for a 4-bit screen and 254 for an 8-bit screen) so that black and white are available in the color table.After defining three variables, the
MyMakeRedPalette
function calls theNewPalette
function to create a palette large enough to hold 268 colors (254 plus 14). Thenil
value passed as the second parameter specifies that no color table be used to create the template, in which case all the colors in the palette are set to black. The twofor
loops that follow use theSetEntryColor
andSetEntryUsage
functions to change the colors and their use in the palette.The first loop creates 14 shades of red. The green and blue values for all the colors are already set to 0. The
SetEntryColor
function is called in a loop to set the 14 red values. It specifies 1/14 increments up to the maximum value of 65535. TheSetEntryUsage
function specifies that each color is tolerant (it uses thepmTolerant
constant to do this) and that the tolerance is 0 so that each color must match exactly.The
SetEntryUsage
function also specifies that these 14 colors are to be used only on a 4-bit screen. It does this by inhibiting these colors on all other indexed screens using the constantspmInhibitC2
(inhibit on a 2-bit color screen),pmInhibitG2
(inhibit on a 2-bit grayscale screen), and so on for the other types of indexed screens.The second loop creates 254 shades of red. It uses the
SetEntryColor
function as the first loop does with the only difference being that the red color value is incremented 1/254 at each iteration rather than 1/14. As in the first loop, theSetEntryUsage
function specifies that each color is tolerant with a tolerance of 0 so that the colors must match exactly. TheSetEntryUsage
function also specifies that the colors are to be used only on an 8-bit color screen. It does this by inhibiting the colors on all other indexed screens.Creating a Palette by Copying and Assigning It to a Window
You can create a palette from the colors in a color table by using theNewPalette
function. It copies the colors from the table and assigns the usage and tolerance values you specify as function parameters. You assign a usage value and a tolerance value that apply to all of the palette's entries, but you can change individual entries with subsequent calls to theSetEntryUsage
function, which can change both the usage and tolerance values of an entry. (If you callNewPalette
without supplying a color table as a source, it creates a palette with all entries equal to black. You can then modify the entries as needed, using theSetEntryColor
andSetEntryUsage
functions.)
For example, suppose you are drawing to an indexed device with a color table containing 14 colors plus black and white and you want a palette in which the fifth color must be matched exactly but the others need only be close. Listing 1-4 shows how to create the palette from the color table and then modify the tolerance value for the fifth entry (remember that color table and palette entries are numbered starting at 0).
- Note
- Color tables define the colors that are available for pixel images on indexed devices. You can create color tables from either
ColorTable
data structures or color table ('clut'
) resources. See the chapter "Color QuickDraw" of Inside Macintosh: Imaging With QuickDraw for more information on color tables.Listing 1-4 Copying a color table to a palette
#define clutID 68 void DoCreatePalette() { CTabHandle myColorTable; PaletteHandle myPalette; WindowPtr myWindow; myColorTable = GetCTable (clutID); /* create a new window */ myWindow = NewCWindow(nil, &BaseRect, "\pUsing Palette Manager", TRUE, documentProc, (WindowPtr) -1, TRUE, nil); /* create a 16-color palette */ myPalette = NewPalette(16, myColorTable, pmTolerant, $2000); /* modify the 5th entry */ SetEntryUsage(myPalette, 4, 0); /* assign the palette to the window */ SetPalette ((WindowPtr) myWindow, myPalette, TRUE); }After defining three variables (to hold the color table ID, the palette ID, and the window ID), theDoCreatePalette
function uses theGetCTable
function (described in the chapter "Color QuickDraw" of Inside Macintosh: Imaging With QuickDraw) to retrieve the default color-table ('clut'
) resource for a screen with a 4-bit pixel depth. (You can obtain the default color-table resource for a screen by adding 64 to the pixel depth of the screen. Therefore, 68 identifies the color-table resource for a 4-bit pixel depth screen.) TheNewCWindow
function (described in the chapter "Window Manager" of Inside Macintosh: Macintosh Toolbox Essentials) then creates a new color window.The
NewPalette
function creates a palette from the color-table resource. All colors in the new palette have a tolerance of $2000. TheSetEntryUsage
function changes the tolerance of the fifth entry such that an exact match is required.Finally, the
SetPalette
function assigns the newly created palette to the newly created window.
If you want to change a window's palette momentarily and then restore the first palette, use the
- Note
- You can use either the
SetPalette
orNSetPalette
function to assign a palette to a window. These functions are identical except that theNSetPalette
function is more versatile in specifying whether the window is to receive updates when the color environment changes.NSetPalette
allows you to specify that the window is to receive updates only when the window is active, updates only when it is not active, all updates, or none. TheSetPalette
function only allows the last two settings.GetPalette
function to obtain a handle to a window's current palette and then restore it with eitherSetPalette
orNSetPalette
.