Important: The information in this document is obsolete and should not be used for new development.
Using Color QuickDraw
To use Color QuickDraw, you generally
This section gives an overview of routines that your application typically calls while using Color QuickDraw. Before calling these routines, however, your application should test for the existence of Color QuickDraw by using the
- initialize QuickDraw
- create a color window into which your application can draw
- create
RGBColor
records to define your own foreground and background colors- create pixel pattern (
'ppat'
) resources to define your own colored patterns- use these colors and pixel patterns for drawing with the graphics pen, for filling as the background pattern, and for filling into shapes
- use the basic QuickDraw routines previously described in this book to perform all other onscreen graphics port manipulations and calculations
Gestalt
function with thegestaltQuickDrawVersion
selector. TheGestalt
function returns a 4-byte value in itsresponse
parameter; the low-order word contains QuickDraw version data. In that low-order word, the high-order byte gives the major revision number and the low-order byte gives the minor revision number. If the value returned in theresponse
parameter is equal to the value of the constantgestalt32BitQD13
, then the system supports the System 7 version of Color QuickDraw. Listed here are the various constants, and the values they represent, that indicate earlier versions of Color QuickDraw.
CONST gestalt8BitQD = $100; {8-bit Color QD} gestalt32BitQD = $200; {32-bit Color QD} gestalt32BitQD11 = $210; {32-bit Color QDv1.1} gestalt32BitQD12 = $220; {32-bit Color QDv1.2} gestalt32BitQD13 = $230; {System 7: 32-bit Color QDv1.3}Your application can also use theGestalt
function with the selectorgestaltQuickDrawFeatures
to determine whether the user's system supports various Color QuickDraw features. If the bits indicated by the following constants are set in theresponse
parameter, then the features are available:
CONST gestaltHasColor = 0; {Color QuickDraw is present} gestaltHasDeepGWorlds = 1; {GWorlds deeper than 1 bit} gestaltHasDirectPixMaps = 2; {PixMaps can be direct--16 or } { 32 bit} gestaltHasGrayishTextOr = 3; {supports text mode } { grayishTextOr}When testing for the existence of Color QuickDraw, your application should test the response to thegestaltQuickDrawVersion
selector (rather than test for the resultgestaltHasColor
, which is unreliable, from thegestaltQuickDrawFeatures
selector). The support for offscreen graphics worlds indicated by thegestaltHasDeepGWorlds
response to thegestaltQuickDrawVersion
selector is described in the chapter "Offscreen Graphics Worlds." The support for the text mode indicated by thegestaltHasGrayishTextOr
response is described in the chapter "QuickDraw Text" in Inside Macintosh: Text. For more information about theGestalt
function, see the chapter "Gestalt Manager" in Inside Macintosh: Operating System Utilities.Initializing Color QuickDraw
To initialize Color QuickDraw, use theInitGraf
procedure, described in the chapter "Basic QuickDraw." Besides initializing basic QuickDraw, this procedure initializes Color QuickDraw on computers that support it.In addition to
InitGraf
, all other basic QuickDraw routines work with Color QuickDraw. For example, you can use theGetPort
procedure to save the current color graphics port, and you can use theCopyBits
procedure to copy an image between two different color graphics ports. See the chapters "Basic QuickDraw" and "QuickDraw Drawing" for descriptions of additional routines that you can use with Color QuickDraw.Creating Color Graphics Ports
All graphics operations are performed in graphics ports. Before a color graphics port can be used, it must be allocated with theOpenCPort
procedure and initialized with theInitCPort
procedure. Normally, your application does not call these procedures directly. Instead, your application creates a color graphics port by using theGetNewCWindow
orNewCWindow
function (described in the chapter "Window Manager" in Inside Macintosh: Macintosh Toolbox Essentials) or theNewGWorld
function (described in the chapter "Offscreen Graphics Worlds" in this book). These functions automatically callOpenCPort
, which in turn callsInitCPort
.Listing 4-1 shows a simplified application-defined procedure called
DoNew
that uses the Window Manager functionGetNewCWindow
to create a color graphics port.Listing 4-1 Using the Window Manager to create a color graphics port
PROCEDURE DoNew (VAR window: WindowPtr); VAR windStorage: Ptr; {memory for window record} BEGIN window := NIL; {allocate memory for window record from previously allocated block} windStorage := MyPtrAllocationProc; IF windStorage <> NIL THEN {memory allocation succeeded} BEGIN IF gColorQDAvailable THEN {use Gestalt to determine color availability} window := GetNewCWindow(rDocWindow, windStorage, WindowPtr(-1)) ELSE {create a basic graphics port for a black-and-white screen} window := GetNewWindow(rDocWindow, windStorage, WindowPtr(-1)); END; IF (window <> NIL) THEN SetPort(window); END;You can useGetNewCWindow
to create color graphics ports whether or not a color monitor is currently installed. So that most of your window-handling code can handle color windows and black-and-white windows identically,GetNewCWindow
returns a pointer of typeWindowPtr
(not of typeCWindowPtr
).A window pointer points to a window record (
WindowRecord
), which contains aGrafPort
record. If you need to check the fields of the color graphics port associated with a window, you can coerce the pointer to theGrafPort
record into a pointer to aCGrafPort
record.You can allow
GetNewCWindow
to allocate the memory for your window record and its associated basic graphics port. You can maintain more control over memory use, however, by allocating the memory yourself from a block allocated for such purposes during your own initialization routine, and then passing the pointer toGetNewWindow
, as shown in Listing 4-1.To dispose of a color graphics port when you are finished using a color window, you normally use the
DisposeWindow
procedure (if you let the Window Manager allocate memory for the window) or theCloseWindow
procedure (if you allocated memory for the window). If you use theCloseWindow
procedure, you also dispose of the window record containing the graphics port by calling the Memory Manager procedureDisposePtr
. You use theDisposeGWorld
procedure when you are finished with a color graphics port for an offscreen graphics world.Drawing With Different Foreground Colors
You can set the foreground and background colors using either Color QuickDraw or Palette Manager routines. If your application uses the Palette Manager, it should set the foreground and background colors with thePmForeColor
andPmBackColor
routines, as described in the chapter "Palette Manager" in Inside Macintosh: Advanced Color Imaging. Otherwise, your application can use theRGBForeColor
procedure to set the foreground color, and it can use theRGBBackColor
procedure to set the background color. Both of these Color QuickDraw procedures also operate for basic graphics ports created in System 7. (To set the foreground and background colors for basic graphics ports on older versions of system software, use theForeColor
andBackColor
procedures described in the chapter "QuickDraw Drawing.")The
RGBForeColor
procedure lets you set the foreground color to the best color available on the current graphics device. This changes the color of the "ink" used for drawing. All of the line-drawing, framing, and painting routines described in the chapter "QuickDraw Drawing" (such asLineTo
,FrameRect
, andPaintPoly
) draw with the foreground color that you specify withRGBForeColor
.
To specify a foreground color, create an
- Note
- Because a pixel pattern already contains color, Color QuickDraw ignores the foreground and background colors when your application draws with a pixel pattern. As described in "Drawing With Pixel Patterns" beginning on page 4-19, you can draw with a pixel pattern by using the
PenPixPat
procedure to assign a pixel pattern to the graphics pen, by using theBackPixPat
procedure to assign a pixel pattern as the background pattern for the current color graphics port, and by using theFillCRect
,FillCOval
,FillCRoundRect
,FillCArc
,FillCRgn
, andFillCPoly
procedures to fill shapes with a pixel pattern.RGBColor
record. Listing 4-2 defines twoRGBColor
records. The first is declared asmyDarkBlue
, and it's defined with a medium-intensive blue component and with zero-intensity red and green components. The second is declared asmyMediumGreen
, and it's defined with an intensive green component, a mildly intensive red component, and a very slight blue component.Listing 4-2 Changing the foreground color
PROCEDURE MyPaintAndFillColorRects; VAR firstRect, secondRect: Rect; myDarkBlue: RGBColor; myMediumGreen: RGBColor; BEGIN {create dark blue color} myDarkBlue.red := $0000; myDarkBlue.green := $0000; myDarkBlue.blue := $9999; {create medium green color} myMediumGreen.red := $3206; myMediumGreen.green := $9038; myMediumGreen.blue := $013D; RGBForeColor(myDarkBlue); {draw with dark blue pen} PenMode(patCopy); SetRect(firstRect, 20, 20, 70, 70); PaintRect(firstRect); {paint a dark blue rectangle} RGBForeColor(myMediumGreen); {draw with a medium green pen} SetRect(secondRect, 90, 20, 140, 70); FillRect(secondRect, ltGray); {paint a medium green rectangle} END;In Listing 4-2, theRGBColor
recordmyDarkBlue
is supplied to theRGBForeColor
procedure. TheRGBForeColor
procedure supplies thergbFgColor
field of theCGrafPort
record with thisRGBColor
record, and it places the closest-matching available color in thefgColor
field; the color in thefgColor
field is the color actually used as the foreground color.After using
SetRect
to create a rectangle, Listing 4-2 callsPaintRect
to paint the rectangle. By default, the foreground color is black; by changing the foreground color to dark blue, every pixel that would normally be painted in black is instead painted in dark blue.Listing 4-2 then changes the foreground color again to the medium green specified in the
RGBColor
recordmyMediumGreen
. After creating another rectangle, this listing callsFillRect
to fill the rectangle with the bit pattern specified by the global variableltGray
. As explained in the chapter "QuickDraw Drawing," this bit pattern consists of widely spaced black pixels that create the effect of gray on black-and-white screens. However, by changing the foreground color, every pixel in the pattern that would normally be painted black is instead drawn in medium green.The effects of Listing 4-2 are illustrated in the grayscale screen capture shown in
Figure 4-9.Figure 4-9 Drawing with two different foreground colors (on a grayscale screen)
If you wish to draw with a color other than the foreground color, you can use thePenPixPat
procedure to give the graphics pen a colored pixel pattern that you define, and you can use theFillCRect
,FillCRoundRect
,FillCOval
,FillCArc
,FillCPoly
, andFillCRgn
procedures to fill shapes with colored patterns. The use of these procedures is illustrated in the next section.Drawing With Pixel Patterns
Using pixel pattern resources, you can create multicolored patterns for the pen pattern, for the background pattern, and for fill patterns.To set the pixel pattern to be used by the graphics pen in the current color graphics port, you use the
PenPixPat
procedure. To assign a pixel pattern as the background pattern, you use theBackPixPat
procedure; this causes theScrollRect
procedure and the shape-erasing procedures (for example,EraseRect
) to fill the background with your pixel pattern. To fill shapes with a pixel pattern, you use theFillCRect
,FillCRoundRect
,FillCOval
,FillCArc
,FillCPoly
, andFillCRgn
procedures.
When you use the
- Note
- Because a pixel pattern already contains color, Color QuickDraw ignores the foreground and background colors when your application uses these routines to draw with a pixel pattern. Color QuickDraw also ignores the pen mode by drawing the pixel pattern directly onto the pixel image.
PenPat
orBackPat
procedure in a color graphics port, Color QuickDraw constructs a pixel pattern equivalent to the bit pattern you specify toPenPat
orBackPat
. The pen pattern or background pattern you thereby specify always uses the graphics port's current foreground and background colors. ThePenPat
andBackPat
procedures are described in the chapter "QuickDraw Drawing."A pixel pattern resource is a resource of type
'ppat'
. You typically use a high-level tool such as the ResEdit application, available through APDA, to create'ppat'
resources. Figure 4-10 illustrates a ResEdit window displaying an application's'ppat'
resource with resource ID 128.Figure 4-10 Using ResEdit to create a pixel pattern resource
As shown in this figure, you should also define an analogous, black-and-white bit pattern (described in the chapter "QuickDraw Drawing") to be used when this pattern is drawn into a basic graphics port. This bit pattern is stored within the pixel pattern resource.After using ResEdit to define a pixel pattern, you can then use the DeRez decompiler to convert your
'ppat'
resources into Rez input when necessary. (The DeRez resource decompiler and the Rez resource compiler are part of Macintosh Programmer's Workshop [MPW], which is available through APDA.) Listing 4-3 shows the Rez input created from the'ppat'
resource created in Figure 4-10.Listing 4-3 Rez input for a pixel pattern resource
resource 'ppat' (128) { $"0001 0000 001C 0000 004E 0000 0000 FFFF" $"0000 0000 8292 1082 9210 8292 0000 0000" $"8002 0000 0000 0008 0008 0000 0000 0000" $"0000 0048 0000 0048 0000 0000 0002 0001" $"0002 0000 0000 0000 005E 0000 0000 1212" $"4848 1212 4848 1212 4848 1212 4848 0000" $"0000 0000 0002 0000 AAAA AAAA AAAA 0001" $"2222 2222 2222 0002 7777 7777 7777" };To retrieve the pixel pattern stored in a'ppat'
resource, you can use theGetPixPat
function. Listing 4-4 usesGetPixPat
to retrieve the'ppat'
resource created in
Listing 4-3. To assign this pixel pattern to the graphics pen, Listing 4-4 uses thePenPixPat
procedure.Listing 4-4 Using pixel patterns to paint and fill
PROCEDURE MyPaintPixelPatternRects; VAR firstRect, secondRect: Rect; myPenPattern, myFillPattern: PixPatHandle; BEGIN myPenPattern := GetPixPat(128); {get a pixel pattern} PenPixPat(myPenPattern); {assign the pattern to the pen} SetRect(firstRect, 20, 20, 70, 70); PaintRect(firstRect); {paint with the pen's pixel pattern} DisposePixPat(myPenPattern); {dispose of the pixel pattern} myFillPattern := GetPixPat(129); {get another pixel pattern} SetRect(secondRect, 90, 20, 140, 70); FillCRect(secondRect, myFillPattern); {fill with this pattern} DisposePixPat(myFillPattern); {dispose of the pixel pattern} END;Listing 4-4 uses thePaintRect
procedure to draw a rectangle. The rectangle on the left side of Figure 4-11 illustrates the effect of painting a rectangle with the previously defined pen pattern.Figure 4-11 Painting and filling rectangles with pixel patterns
The rectangle on the right side of Figure 4-11 illustrates the effect of using theFillCRect
procedure to fill a rectangle with another previously defined pen pattern. TheGetPixPat
function is used to retrieve the pixel pattern defined in the'ppat'
resource with resource ID 129. This pixel pattern is then specified to theFillCRect
procedure.Copying Pixels Between Color Graphics Ports
As explained in the chapter "QuickDraw Drawing," QuickDraw has three primary image-processing routines.
In basic QuickDraw,
- The
CopyBits
procedure copies a pixel map or bitmap image to another graphics port, with facilities for resizing the image, modifying the image with transfer modes, and clipping the image to a region.- The
CopyMask
procedure copies a pixel map or bitmap image to another graphics port, with facilities for resizing the image and for altering the image by passing it through a mask--which for Color QuickDraw may be another pixel map whose pixels indicate proportionate weights of the colors for the source and destination pixels.- The
CopyDeepMask
procedure combines the effects ofCopyBits
andCopyMask
: you can resize an image, clip it to a region, specify a transfer mode, and use another pixel map as a mask when transferring it to another graphics port.
CopyBits
,CopyMask
, andCopyDeepMask
copy bit images between two basic graphics ports. In Color QuickDraw, you can also use these procedures to copy pixel images between two color graphics ports. Detailed routine descriptions for these procedures appear in the chapter "QuickDraw Drawing." This section provides an overview of how to use the extra capabilities that Color QuickDraw provides for these procedures.When using
CopyBits
,CopyMask
, andCopyDeepMask
to copy images between color graphics ports, you must coerce each port'sCGrafPtr
data type to aGrafPtr
data type, dereference theportBits
fields of each, and then pass these "bitmaps" in thesrcBits
anddstBits
parameters. If your application copies a pixel image from a color graphics port calledMyColorPort
, in thesrcBits
parameter you could specifyGrafPtr(MyColorPort)^.portBits
. In aCGrafPort
record, the high 2 bits of theportVersion
field are set. This field, which shares the same position in aCGrafPort
record as theportBits.rowBytes
field in aGrafPort
record, indicates to these routines that you have passed it a handle to a pixel map rather than a bitmap.Color QuickDraw's processing sequence of the
CopyBits
procedure is illustrated in Figure 4-12. Listing 6-1 in the chapter "Offscreen Graphics Worlds" illustrates how to useCopyBits
to transfer an image prepared in an offscreen graphics world to an onscreen color graphics port.Figure 4-12 Copying pixel images with the
CopyBits
procedure
With theCopyMask
procedure, you can supply a pixel map to act as a copying mask. The values of pixels in the mask act as weights that proportionally select between source and destination pixel values. The process is shown in Figure 4-13, and an example of the effect can be seen in Plate 3 Plate 3 at the front of this book. Listing 6-2 in the chapter "Offscreen Graphics Worlds" illustrates how to useCopyMask
to mask and copy an image prepared in an offscreen graphics world to an onscreen color graphics port.Figure 4-13 Copying pixel images with the
CopyMask
procedure
TheCopyDeepMask
procedure combines the capabilities of theCopyBits
andCopyMask
procedures. WithCopyDeepMask
you can specify a pixel map mask, a transfer mode, and a mask region, as shown in Figure 4-14.Figure 4-14 Copying pixel images with the
CopyDeepMask
procedure
On indexed devices, pixel images are always copied using the color table of the sourcePixMap
record for source color information, and using the color table of the currentGDevice record
for destination color information. The color table attached to the destinationPixMap
record is ignored. As explained in the chapter "Offscreen Graphics Worlds," if you need to copy to an offscreenPixMap
record with characteristics differing from those of the current graphics device, you should create an appropriate offscreenGDevice
record and set it as the current graphics device before the copy operation.When the
PixMap
record for the mask is 1 bit deep, it has the same effect as a bitmap mask: a black bit in the mask means that the destination pixel is to take the color of the source pixel; a white bit in the mask means that the destination pixel is to retain its current color. When masks havePixMap
records with greater pixel depths than 1, Color QuickDraw takes a weighted average between the colors of the source and destinationPixMap
records. Within each pixel, the calculation is done in RGB color, on a color component basis. A grayPixMap
record mask, for example, works like blend mode in aCopyBits
procedure. A red mask (that is, one with high values for the red components of all pixels) filters out red values coming from the source pixel image.Boolean Transfer Modes With Color Pixels
As described in the chapter "QuickDraw Drawing," QuickDraw offers two types of Boolean transfer modes: pattern modes for drawing lines and shapes, and source modes for copying images or drawing text. In basic graphics ports and in color graphics ports with 1-bit pixel maps, these modes describe the interaction between the bits your application draws and the bits that are already in the destination bitmap or 1-bit pixel map. These interactions involve turning the bits on or off--that is, making the pixels black or white.The Boolean operations on bitmaps and 1-bit pixel maps are described in the chapter "QuickDraw Drawing." When you draw or copy images to and from bitmaps or 1-bit pixel maps, Color QuickDraw behaves in the manner described in that chapter.
When you use pattern modes in pixel maps with depths greater than 1 bit, Color QuickDraw uses the foreground color and background color when transferring bit patterns; for example, the
patCopy
mode applies the foreground color to every destination pixel that corresponds to a black pixel in a bit pattern, and it applies the background color to every destination pixel that corresponds to a white pixel in a bit pattern. See the description of thePenMode
procedure in the chapter "QuickDraw Drawing" for a list that summarizes how the foreground and background colors are applied with pattern modes.When you use the
CopyBits
,CopyMask
, andCopyDeepMask
procedures to transfer images between pixel maps with depths greater than 1 bit, Color QuickDraw performs the Boolean transfer operations in the manner summarized in Table 4-1. In general, with pixel images you will probably want to use thesrcCopy
mode or one of the arithmetic transfer modes described in "Arithmetic Transfer Modes" beginning on page 4-29.
When you use the
- Note
- When your application draws with a pixel pattern, Color QuickDraw ignores the pattern mode and simply transfers the pattern directly to the pixel map without regard to the foreground and background colors.
srcCopy
mode to transfer a pixel into a pixel map, Color QuickDraw determines how close the color of that pixel is to black, and then assigns this relative amount of foreground color to the destination pixel. Color QuickDraw also determines how close the color of that pixel is to white, and assigns this relative amount of background color to the destination pixel.To accomplish this, Color QuickDraw first multiplies the relative intensity of each red, green, and blue component of the source pixel by the corresponding value of the red, green, or blue component of the foreground color. It then multiplies the relative intensity of each red, green, and blue component of the source pixel by the corresponding value of the red, green, or blue component of the background color. For each component, Color QuickDraw adds the results and then assigns the new result as the value for the destination pixel's corresponding component.
For example, the pixel in an image might be all red: that is, its red component has a pixel value of $FFFF, and its green and blue components each have pixel values of $0000. The current foreground color might be black (that is, with pixel values of $0000, $0000, $0000 for its components) and its background color might be all white (that is, with pixel values of $FFFF, $FFFF, $FFFF). When that image is copied using the
CopyBits
procedure and thesrcCopy
source mode,CopyBits
determines that the red component of the source pixel has 100 percent intensity; multiplying this by the intensity of the red component ($0000) of the foreground color produces a value of $0000, and multiplying this by the intensity of the red component ($FFFF) of the background color produces a value of $FFFF. Adding the results of these two operations produces a pixel value of $FFFF for the red component of the destination pixel. Performing similar operations on the green and blue components of the source pixel produces green and blue pixel values of $0000 for the destination pixel. In this way,CopyBits
renders the source's all-red pixel as an all-red pixel in the destination pixel map. A source pixel with only 50 percent intensity for its red component and no intensity for its blue and green components would similarly be drawn as a medium red pixel in the destination pixel map.Color QuickDraw produces similarly weighted destination colors when you use the other Boolean source modes. When you use the
srcBic
mode to transfer a colored source pixel into a pixel map, for example,CopyBits
determines how close the color of that pixel is to black, and then assigns a relative amount of background color to the destination pixel. For this mode,CopyBits
does not determine how close the color of the source pixel is to white.Because Color QuickDraw uses the foreground and background colors instead of black and white when performing its Boolean source operations, the following effects are produced:
As you can see, applying a foreground color other than black or a background color other than white to the pixel can produce an unexpected result. For consistent results, set the foreground color to black and the background color to white before using
- The
notSrcCopy
mode reverses the foreground and background colors.- Drawing into a white background with a black foreground always reproduces the source image, regardless of the pixel depth.
- Drawing is faster if the foreground color is black when you use the
srcOr
andnotSrcOr
modes.- If the background color is white when you use the
srcBic
mode, the black portions of the source are erased, resulting in white in the destination pixel map.
CopyBits
,CopyMask
, orCopyDeepMask
.However, by using the
RGBForeColor
andRGBBackColor
procedures to set the foreground and background colors to something other than black and white before usingCopyBits
,CopyMask
, orCopyDeepMask
, you can achieve some interesting coloration effects. Plate 2 at the front of this book shows how setting the foreground color to red and the background color to blue and then using theCopyBits
procedure turns a grayscale image into shades of red and blue. Listing 4-5 shows the code that produced these two pixel maps.Listing 4-5 Using
CopyBits
to produce coloration effects
PROCEDURE MyColorRamp; VAR origPort: CGrafPtr; origDevice: GDHandle; myErr: QDErr; myOffScreenWorld: GWorldPtr; TheColor: RGBColor; i: Integer; offPixMapHandle: PixMapHandle; good: Boolean; myRect: Rect; BEGIN GetGWorld(origPort, origDevice); {save onscreen graphics port} {create offscreen graphics world} myErr := NewGWorld(myOffScreenWorld, 0, origPort^.portRect, NIL, NIL, []); IF (myOffScreenWorld = NIL) OR (myErr <> noErr) THEN ; {handle errors here} SetGWorld(myOffScreenWorld, NIL); {set current graphics port to offscreen} offPixMapHandle := GetGWorldPixMap(myOffScreenWorld); good := LockPixels(offPixMapHandle); {lock offscreen pixel map} IF NOT good THEN ; {handle errors here} EraseRect(myOffScreenWorld^.portRect); {initialize offscreen pixel map} FOR i := 0 TO 9 DO BEGIN {create gray ramp} theColor.red := i * 7168; theColor.green := i * 7168; theColor.blue := i * 7168; RGBForeColor(theColor); SetRect(myRect, myOffScreenWorld^.portRect.left, i * 10, myOffScreenWorld^.portRect.right, i * 10 + 10); PaintRect(myRect); {fill offscreen pixel map with gray ramp} END; SetGWorld(origPort, origDevice); {restore onscreen graphics port} theColor.red := $0000; theColor.green := $0000; theColor.blue := $FFFF; RGBForeColor(theColor); {make foreground color all blue} theColor.red := $FFFF; theColor.green := $0000; theColor.blue := $0000; RGBBackColor(theColor); {make background color all red} {using blue foreground and red background colors, transfer "gray" } { ramp to onscreen graphics port} CopyBits(GrafPtr(myOffScreenWorld)^.portBits, {gray ramp is source} GrafPtr(origPort)^.portBits, {window is destination} myOffScreenWorld^.portRect, origPort^.portRect, srcCopy, NIL); UnlockPixels(offPixMapHandle); DisposeGWorld(myOffScreenWorld); END;Listing 4-5 uses theNewGWorld
function, described in the chapter "Offscreen Graphics Worlds," to create an offscreen pixel map. The sample code draws a gray ramp into the offscreen pixel map, which is illustrated on the left side of Plate 2 at the front of this book. Then Listing 4-5 creates an all-blue foreground color and an all-red background color. This sample code then uses theCopyBits
procedure to transfer the pixels in the offscreen pixel map to the onscreen window, which is shown on the right side of Plate 2.Here are some hints for using foreground and background colors and the
srcCopy
source mode to color a pixel image:
To help make color work well on different screen depths, Color QuickDraw does some validity checking of the foreground and background colors. If your application is drawing to a color graphics port with a pixel depth equal to 1 or 2, and if the foreground and background colors aren't the same but both of them map to the same pixel value, then the foreground color is inverted. This ensures that, for instance, a red image drawn on a green background doesn't map to black on black.
- You can copy a particular color component of a source pixel without change by setting the foreground color to have a value of $0000 for that component and the background color to have a value of $FFFF for that component. For example, if you want all the pixels in a source image to retain their red values in the destination image, set the red component of the foreground color to $0000, and set the red component of the background color to $FFFF.
- You can invert a particular color component of a source pixel by setting the foreground color to have a value of $FFFF for that component and the background color to have a value of $0000 for that component.
- You can remove a particular color component from all the pixels in the source image by setting the foreground color to have a value of $0000 for that component and the background color to have a value of $0000 for that component.
- You can force a particular color component in all the pixels in the source to be transferred with full intensity by setting the foreground color to have a value of $FFFF for that component and the background color to have a value of $FFFF for that component.
On indexed devices, these source modes produce unexpected colors, because Color QuickDraw performs Boolean operations on the indexes rather than on actual color values, and the resulting index may point to an entirely unrelated color. On direct devices these transfer modes generally do not exhibit rigorous Boolean behavior except when white is set as the background color.
Dithering
With theCopyBits
andCopyDeepMask
procedures you can use dithering, a technique used by these procedures for mixing existing colors together to create the illusion of a third color that may be unavailable on an indexed device. For example, if you specify dithering when copying a purple image from a 32-bit direct device to an 8-bit indexed device that does not have purple available, these procedures mix blue and red pixels to give the illusion of purple on the 8-bit device.Dithering is also useful for improving images that you shrink when copying them from a direct device to an indexed device.
On computers running System 7, you can add dithering to any source mode by adding the following constant or the value it represents to the source mode:
CONST ditherCopy = 64; {add to source mode for dithering}For example, specifyingsrcCopy
+
ditherCopy
in themode
parameter toCopyBits
causesCopyBits
to dither the image when it copies the image into the destination pixel map.Dithering has drawbacks. First, dithering slows the drawing operation. Second, a clipped dithering operation does not provide pixel-for-pixel equivalence to the same unclipped dithering operation. When you don't specify a clipping region, for example,
CopyDeepMask
begins copying the upper-left pixel in your source image and, if necessary, begins calculating how to dither the upper-left pixel and its adjoining pixels in your destination in order to approximate the color of the source pixel. AsCopyDeepMask
continues copying pixels in this manner, there is a cumulative dithering effect based on the preceding pixels in the source image. If you specify a clipping region toCopyDeepMask
, dithering begins with the upper-left pixel in the clipped region; this ignores the cumulative dithering effect that would otherwise occur by starting at the upper-left corner of the source image. In particular, if you clip and dither a region using thesrcXor
mode, you can't useCopyDeepMask
a second time to copy that region back into the destination pixel map in order to erase that region.If you replace the Color Manager's color search function with your own search function (as described in the chapter "Color Manager" in Advanced Color Imaging on the Mac OS),
CopyBits
andCopyDeepMask
cannot perform dithering. Without dithering, your application does color mapping on a pixel-by-pixel basis. If your source pixel map is composed of indexed pixels, and if you have installed a custom color search function, Color QuickDraw calls your function once for each color in the color table for the sourcePixMap
record. If your source pixel map is composed of direct pixels, Color QuickDraw calls your custom search function for each color in the pixel image for the sourcePixMap
record; with an image of many colors, this can take a long time.If you specify a destination rectangle that is smaller than the source rectangle when using
CopyBits
,CopyMask
, orCopyDeepMask
on a direct device, Color QuickDraw automatically uses an averaging technique to produce the destination pixels, maintaining high-quality images when shrinking them. On indexed devices, Color QuickDraw averages these pixels only if you specify dithering. Using dithering even when shrinking 1-bit images can produce much better representations of the original images. (The chapter "QuickDraw Drawing" includes a code sample calledMyShrinkImages
, shown in Listing 3-11 on page 3-29, that illustrates how to useCopyBits
to scale a bit image when copying it from one window into another.)Arithmetic Transfer Modes
In addition to the Boolean source modes described previously, Color QuickDraw offers a set of transfer modes that perform arithmetic operations on the values of the red, green, and blue components of the source and destination pixels. Although rarely used by applications, these arithmetic transfer modes produce predictable results on indexed devices because they work with RGB colors rather than with color table indexes. These arithmetic transfer modes are represented by the following constants:
CONST blend = 32; {replace destination pixel with a blend } { of the source and destination pixel } { colors; if the destination is a bitmap or } { 1-bit pixel map, revert to srcCopy mode} addPin = 33; {replace destination pixel with the sum of } { the source and destination pixel colors-- } { up to a maximum allowable value; if } { the destination is a bitmap or } { 1-bit pixel map, revert to srcBic mode} addOver = 34; {replace destination pixel with the sum of } { the source and destination pixel colors-- } { but if the value of the red, green, or } { blue component exceeds 65,536, then } { subtract 65,536 from that value; if the } { destination is a bitmap or 1-bit } { pixel map, revert to srcXor mode} subPin = 35; {replace destination pixel with the } { difference of the source and destination } { pixel colors--but not less than a minimum } { allowable value; if the destination } { is a bitmap or 1-bit pixel map, revert to } { srcOr mode} transparent = 36; {replace the destination pixel with the } { source pixel if the source pixel isn't } { equal to the background color} addMax = 37; {compare the source and destination pixels, } { and replace the destination pixel with } { the color containing the greater } { saturation of each of the RGB components; } { if the destination is a bitmap or } { 1-bit pixel map, revert to srcBic mode} subOver = 38; {replace destination pixel with the } { difference of the source and destination } { pixel colors--but if the value of a red, } { green, or blue component is } { less than 0, add the negative result to } { 65,536; if the destination is a bitmap or } { 1-bit pixel map, revert to srcXor mode} adMin = 39; {compare the source and destination pixels, } { and replace the destination pixel with } { the color containing the lesser } { saturation of each of the RGB components; } { if the destination is a bitmap or } { 1-bit pixel map, revert to srcOr mode}When you use the arithmetic transfer modes, each drawing routine converts indexed source and destination pixels to their RGB components; performs the arithmetic operation on each pair of red, green, and blue components to provide a new RGB color for the destination pixel; and then assigns the destination a pixel value close to the calculated RGB color.
- Note
- You can use the arithmetic modes for all drawing operations; that is, your application can pass them in parameters to the
PenMode
,CopyBits
,CopyDeepMask
, andTextMode
routines. (TheTextMode
procedure is described in Inside Macintosh: Text.For indexed pixels, the arithmetic transfer modes obtain the full 48-bit RGB color from the CLUT. For direct pixels, the arithmetic transfer modes use the 15 or 24 bits of the truncated RGB color. Note, however, that because the colors for indexed pixels depend on the set of colors currently loaded into a graphics device's CLUT, arithmetic transfer modes may produce effects that differ between indexed and direct devices.
When you use the
- Note
- The arithmetic transfer modes have no coloration effects.
addPin
mode in a basic graphics port, the maximum allowable value for the destination pixel is always white. In a color graphics port, you can assign the maximum allowable value with theOpColor
procedure, described on page 4-69. Note that theaddOver
mode is slightly faster than theaddPin
mode.When you use the
subPin
mode in a basic graphics port, the minimum allowable value for the destination pixel is always black. In a color graphics port, you can assign the minimum allowable value with theOpColor
procedure. Note that thesubOver
mode
is slightly faster than thesubPin
mode.When you use the
addMax
andadMin
modes, Color QuickDraw compares each RGB component of the source and destination pixels independently, so the resulting color isn't necessarily either the source or the destination color.When you use the
blend
mode, Color QuickDraw uses this formula to calculate the weighted average of the source and destination pixels, which Color QuickDraw assigns to the destination pixel:dest = source weight/65,535 + destination (1 - weight/65,535)
In this formula, weight is an unsigned value between 0 and 65,535, inclusive. In a basic graphics port, the weight is set to 50 percent gray, so that equal weights of the source and destination RGB components are combined to produce the destination color. In a color graphics port, the weight is an
RGBColor
record that individually specifies the weights of the red, green, and blue components. You can assign the weight value with theOpColor
procedure.The
transparent
mode is most useful on indexed devices, which have 8-bit and 4-bit pixel depths, and on black-and-white devices. You can specify thetransparent
mode in themode
parameter to theTextMode
,PenMode
, andCopyBits
routines. To specify a transparent pattern, add thetransparent
constant to thepatCopy
constant:
transparent + patCopyThetransparent
mode is optimized to handle source bitmaps with large transparent holes, as an alternative to specifying an unusual clipping region or mask to theCopyMask
procedure. Patterns aren't optimized, and may not draw as quickly.The arithmetic transfer modes are most useful in direct and 8-bit indexed pixels, but work on 4-bit and 2-bit pixels as well. If the destination pixel map is 1 bit deep, the arithmetic transfer mode reverts to a comparable Boolean transfer mode, as shown in Table 4-2. (The
hilite
mode is explained in the next section.)
Table 4-2 Arithmetic modes in a 1-bit environment Initial arithmetic mode Resulting source mode blend
srcCopy addOver
,subOver
,hilite
srcXor addPin
,addMax
srcBic subPin
,adMin
,transparent
srcOr Because drawing with the arithmetic modes uses the closest matching colors, and not necessarily exact matches, these modes might not produce the results you expect. For instance, suppose your application uses the
srcCopy
mode to paint a green pixel on a screen with 4-bit pixel values. Of the 16 colors available, the closest green may contain a small amount of red, as in RGB components of 300 red, 65,535 green, and 0 blue. Then, your application usesaddOver
mode to paint a red pixel on top of the green pixel, ideally resulting in a yellow pixel. But the red pixel's RGB components are 65,535 red, 0 green, and 0 blue. Adding the red components of the red and green pixels wraps to 300, since the largest representable value is 65,535. In this case,addOver
causes no visible change at all. You can prevent the maximum value from wrapping around by using theOpColor
procedure to set the maximum allowable color to white, in which the maximum red value is 65,535. Then you can use theaddPin
mode to produce the desired yellow result.Note that the arithmetic transfer modes don't call the Color Manager when mapping a requested RGB color to an indexed pixel value. If your application replaces the Color Manager's color-matching routines (which are described in the chapter "Color Manager" in Advanced Color Imaging on the Mac OS), you must not use these modes, or you must maintain the inverse table yourself.
Highlighting
When highlighting, Color QuickDraw replaces the background color with the highlight color when your application draws or copies images between graphics ports. This has the visual effect of using a highlighting pen to select the object. For instance, TextEdit (described in Inside Macintosh: Text) uses highlighting to indicated selected text; if the highlight color is yellow, TextEdit draws the selected text, then usesInvertRgn
to produce a yellow background for the text.With basic QuickDraw, you can use
InvertRect
,InvertRgn
,InvertArc
,InvertRoundRect
, orInvertPoly
and any image-copying routine that uses thesrcXor
source mode to invert objects on the screen.In general, however, you should use highlighting with Color QuickDraw when selecting and deselecting objects such as text or graphics. (Highlighting has no effect in basic QuickDraw.) The line reading "hilited" in Figure 4-15 uses highlighting; the user selected red as the highlight color, which the application uses as the background for the text. (This figure shows the effect in grayscale.) The application simply inverts the background for the line reading "inverted." Inversion reverses the colors of all pixels within the rectangle's boundary. On a black-and-white monitor, this changes all black pixels in the shape to white, and changes all white pixels to black. Although this procedure operates on color pixels in color graphics ports, the results are predictable only with direct pixels or 1-bit pixel maps.
Figure 4-15 Difference between highlighting and inverting
The global variableHiliteRGB
is read from parameter RAM when the machine starts. Basic graphics ports use the color stored in theHiliteRGB
global variable as the highlight color. Color graphics ports default to theHiliteRGB
global variable, but you can override this by using theHiliteColor
procedure, described on page 4-69.To turn highlighting on when using Color QuickDraw, you can clear the highlight bit just before calling
InvertRect
,InvertRgn
,InvertArc
,InvertRoundRect
,InvertPoly
, or any drawing or image-copying routine that uses thepatXor
orsrcXor
transfer mode. On a bitmap or a 1-bit pixel map, this works exactly like inversion and is compatible with all versions of QuickDraw.The following constant represents the highlight bit:
CONST pHiliteBit = 0; {flag bit in HiliteMode used with BitClr}You can use theBitClr
procedure as shown in Listing 4-6 to clear system software's highlight bit (BitClr
is described in Inside Macintosh: Operating System Utilities).Listing 4-6 Setting the highlight bit
PROCEDURE MySetHiliteMode; BEGIN BitClr(Ptr(HiliteMode), pHiliteBit); END;Listing 4-7 shows the code that produced the effects in Figure 4-15.Listing 4-7 Using highlighting for text
PROCEDURE HiliteDemonstration (window: WindowPtr); CONST s1 = ' hilited '; s2 = ' inverted '; VAR familyID: Integer; r1, r2: Rect; info: FontInfo; bg: RGBColor; BEGIN TextSize(48); GetFontInfo(info); SetRect(r1, 0, 0, StringWidth(s1), info.ascent + info.descent); SetRect(r2, 0, 0, StringWidth(s2), info.ascent + info.descent); OffsetRect(r1, 30, 20); OffsetRect(r2, 30, 100); {fill the background with a light-blue color} bg.red := $A000; bg.green := $FFFF; bg.blue := $E000; RGBBackColor(bg); EraseRect(window^.portRect); {draw the string to highlight} MoveTo(r1.left + 2, r1.bottom - info.descent); DrawString(s1); MySetHiliteMode; {clear the highlight bit} {InvertRect replaces pixels in background color with the } { user-specified highlight color} InvertRect(r1); {the highlight bit is reset automatically} {show inverted text, for comparison} MoveTo(r2.left + 2, r2.bottom - info.descent); DrawString(s2); InvertRect(r2); END;Color QuickDraw resets the highlight bit after performing each drawing operation, so your application should always clear the highlight bit immediately before calling a routine with which you want to use highlighting.Another way to use highlighting is to add this constant or its value to the mode you specify to the
PenMode
,CopyBits
,CopyDeepMask
, andTextMode
routines:
CONST hilite = 50;{add to source or pattern mode for highlighting}Highlighting uses the pattern or source image to decide which bits to exchange; only bits that are on in the pattern or source image can be highlighted in the destination.A very small selection should probably not use highlighting, because it might be too hard to see the selection in the highlight color. TextEdit, for instance, uses highlighting to select and deselect text, but not to highlight the insertion point.
Highlighting is optimized to look for consecutive pixels in either the highlight or background colors. For example, if the source is an all-black pattern, the highlighting is especially fast, operating internally on one long word at a time instead of one pixel at a time. Highlighting a large area without such consecutive pixels (a gray pattern, for instance) can be slow.