Advanced Search
Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC
Previous Book Contents Book Index Next

Inside Macintosh: Imaging With QuickDraw /
Chapter 3 - QuickDraw Drawing


Drawing With QuickDraw

You can use QuickDraw's basic drawing routines to

System software uses QuickDraw's drawing routines to implement the Macintosh user interface. The next several sections provide an introduction to these routines, which your application can use to create complex onscreen images.

To draw lines, your application

To draw rectangles, rounded rectangles, ovals, arcs, and wedges, your application generally

To draw regions and polygons, your application

These tasks are explained in greater detail in the rest of this chapter.

Before using QuickDraw's drawing routines, you must initialize QuickDraw with the InitGraf procedure, as explained in the chapter "Basic QuickDraw."

The routines described in this chapter are available on all models of Macintosh computers. However, all nonwhite colors that you specify with the ForeColor and BackColor procedures are displayed as black on a black-and-white screen. Before using the ForeColor and BackColor procedures to display colors in a basic graphics port, you can use the DeviceLoop procedure, which is described in the chapter "Graphics Device," to determine the color characteristics of the current screen.

Drawing Lines

A line is defined by two points: the current location of the graphics pen and its destination. The graphics pen draws below and to the right of the defining points. As described in "The Graphics Pen" on page 3-4, the pen draws the line between its defining points with the size, pattern, and pattern mode stored in the current graphics port.

You specify where to begin drawing a line by using the MoveTo or Move procedure to place the graphics pen at some point in the window's local coordinate system. Then you call the LineTo or Line procedure to draw a line from there to another point. Take, for example, the following lines of code:

MoveTo(20,20);
LineTo(70,20);
LineTo(70,70);
The MoveTo procedure moves the graphics pen to a point with a horizontal coordinate of 20 and a vertical coordinate of 20 (in the local coordinate system of the graphics port). The first call to the LineTo procedure draws a line from that position to the point with a horizontal coordinate of 70 and a vertical coordinate of 20. The second call to the LineTo procedure draws a line from the pen's new position to the point with a horizontal coordinate of 70 and a vertical coordinate of 70, as shown in Figure 3-5.

Figure 3-5 Using the LineTo procedure


Listing 3-1 illustrates how to use the LineTo procedure to draw the four sides of a square, which is shown on the left side of Figure 3-6. In Figure 3-6, the current graphics port is the window "untitled."

Listing 3-1 Drawing lines with the LineTo and Line procedures

PROCEDURE MyDrawLines;
BEGIN
   MoveTo(20,20);
   LineTo(70,20);
   LineTo(70,70);
   LineTo(20,70);
   LineTo(20,20);

   Move(70,0);
   Line(50,0);
   Line(0,50);
   Line(-50,0);
   Line(0,-50);
END;
Figure 3-6 Drawing lines


The MoveTo and LineTo procedures require you to specify a point in the local coordinate system of the current graphics port. These procedures then transfer the graphics pen to that specific location. As alternatives to using the MoveTo and LineTo procedures, you can use the Move and Line procedures, which require you to pass relative horizontal and vertical distances to move the pen from its current location. The square on the right side of Figure 3-6 is drawn using the Move and Line procedures.

The final call to LineTo in Listing 3-1 moves the graphics pen to the point with a horizontal coordinate of 20 and a vertical coordinate of 20. Listing 3-1 then uses the Move procedure to move the graphics pen a horizontal distance of 70 points--that is, to the point with a horizontal coordinate of 90. The first call to the Line procedure draws a horizontal line 50 pixels long--that is, to the point with a horizontal coordinate of 140 and a vertical coordinate of 20. Starting from there, the second call to Line draws a vertical line 50 pixels long--that is, to the point with a horizontal coordinate of 140 and a vertical coordinate of 70, as shown in Figure 3-7.

Figure 3-7 Using the LineTo and Line procedures


In Figure 3-6, the lines are drawn using the default pen size (1,1), giving the line a vertical depth of one pixel and a horizontal width of one pixel. You can use the PenSize procedure to change the width and height of the graphics pen so that it draws thicker lines, as shown in Figure 3-8.

Figure 3-8 Resizing the pen


The square on the left side of Figure 3-8 is drawn with a pen that has a width of two pixels and a height of eight pixels. The square on the right side of this figure is drawn with a pen that has a width of eight pixels and a height of two pixels. Listing 3-2 shows the code that draws these squares.

Listing 3-2 Using the PenSize procedure

PROCEDURE MyResizePens;
BEGIN
   PenSize(2,8);
   MoveTo(20,20);
   LineTo(70,20); LineTo(70,70); LineTo(20,70); LineTo(20,20);
   PenSize(8,2);
   Move(70,0);
   Line(50,0); Line(0,50); Line(-50,0); Line(0,-50);
   PenNormal;
END;
At the end of Listing 3-2, the PenNormal procedure is used to restore the graphics pen to its default size, pattern, and pattern mode.

The default pattern for the graphics pen consists of all black pixels. However, you can use the PenPat procedure to change the pen's pattern. When you use the PenPat procedure, you can pass it any one of the predefined global variables listed in to specify the bit pattern for the graphics pen.
Table 3-2 The global variables for five predefined bit patterns
Global variableResult
blackAll-black pattern
dkGray75% gray pattern
gray50% gray pattern
ltGray25% gray pattern
whiteAll-white pattern

In Figure 3-9, the pen pattern for the square on the left has changed to ltGray; the pen pattern for the square on the right has changed to dkGray.

Figure 3-9 Changing the pen pattern


Listing 3-3 shows the code that produces these squares.

Listing 3-3 Using the PenPat procedure to change the pattern of the graphics pen

PROCEDURE MyRepatternPens;
BEGIN
   PenSize(2,8);
   PenPat(ltGray);
   MoveTo(20,20);
   LineTo(70,20); LineTo(70,70); LineTo(20,70); LineTo(20,20);

   PenSize(8,2);
   PenPat(dkGray);
   Move(70,0);
   Line(50,0); Line(0,50); Line(-50,0); Line(0,-50);
   PenNormal; 
END;
QuickDraw provides methods for drawing squares and rectangles that are easier than drawing each side individually as a line. The next section describes how to draw rectangles.

Drawing Rectangles

As explained in the chapter "Basic QuickDraw," rectangles are mathematical entities. There are two ways to specify a rectangle: by its four boundary coordinates, as shown in the left rectangle in Figure 3-10, or by its upper-left and lower-right points, as shown in the right rectangle.

Figure 3-10 Two ways to specify a rectangle


However, specifying a rectangle does not draw one. Because the border of a rectangle is infinitely thin, it can have no direct representation on the screen until you use the FrameRect procedure to draw its outline, or you can use the PaintRect or FillRect procedure to draw its outline and its interior with a pattern. Figure 3-11 illustrates two rectangles that are drawn with the FrameRect procedure.

Figure 3-11 Drawing rectangles


Listing 3-4 shows the code that draws the rectangles in Figure 3-11. This listing uses the PenSize procedure to assign a size of (2,2) to the graphics pen. Then the code assigns four boundary coordinates to the rectangle on the left side of this figure, and it calls FrameRect to use the graphics pen to draw the rectangle's outline.

Listing 3-4 Using the FrameRect procedure to draw rectangles

PROCEDURE MyDrawRects;
   VAR
      firstRect, secondRect: Rect;
BEGIN
   PenSize(2,2);

   firstRect.top := 20;
   firstRect.left := 20;
   firstRect.bottom := 70;
   firstRect.right := 70;
   FrameRect(firstRect);

   SetRect(secondRect,90,20,140,70);
   FrameRect(secondRect);

   PenNormal;
END;
To shorten code text, Listing 3-4 uses the SetRect procedure to define the rectangle on the right side of Figure 3-11. Again, FrameRect is used to draw an outline around the rectangle. Notice that while a Rect record lists the fields for a rectangle's boundaries in the order top, left, bottom, and right, you pass these boundaries as parameters to the SetRect procedure in the order left, top, right, and bottom.

Remember that the graphics pen hangs to the right of and below its location point; therefore, the lower-right corner of the two-pixel outline around the rectangle on the right side of Figure 3-11 lies at the point with a horizontal coordinate of 142 and a vertical coordinate of 72.

Figure 3-12 illustrates painted and filled rectangles. Listing 3-5 shows the code that creates these images.

Figure 3-12 Painting and filling rectangles


Listing 3-5 uses the PaintRect procedure to draw the outline and the interior of the rectangle on the left side of Figure 3-12 with the pattern of the graphics pen, according to the pattern mode of the graphics pen. Because Listing 3-5 calls the PenNormal procedure immediately before calling PaintRect, the graphics pen has its default characteristics: a pattern of all-black pixels and the patCopy pattern mode, which changes all of the pixels in the destination to the pen's pattern.

Listing 3-5 Using the PaintRect and FillRect procedures

PROCEDURE MyPaintAndFillRects;
   VAR
   firstRect, secondRect: Rect;
BEGIN
   PenNormal;
   SetRect(firstRect,20,20,70,70);
   PaintRect(firstRect);
   SetRect(secondRect,20,90,70,140);
   FillRect(secondRect,ltGray);
END;
The PaintRect procedure always uses the pattern and pattern mode of the graphics pen when drawing a rectangle. If you want to use a pattern other than that of the graphics pen, you can use the FillRect procedure. The FillRect procedure, however, always uses the patCopy pattern mode. Listing 3-5 uses the FillRect procedure to draw the outline and the interior of the rectangle on the right side of
Figure 3-12 with a light gray pattern.

Note
Neither the PaintRect nor FillRect procedure changes the location of the graphics pen.
If the application that draws the rectangles in Figure 3-12 uses the EraseRect procedure to erase them both, then they would be filled with the background pattern specified by the bkPat field of the current graphics port. If the application uses the InvertRect procedure to invert the rectangles, then the black pixels in each would become white and the white pixels would become black.

QuickDraw provides a similar set of routines for drawing rounded rectangles, which are defined by their rectangles and the widths and heights of the ovals forming their corners. See "Drawing Rounded Rectangles" beginning on page 3-59 for detailed information about these routines.

Drawing Ovals, Arcs, and Wedges

An oval is a circular or elliptical shape defined by the bounding rectangle that encloses it. After specifying the bounding rectangle for an oval, you use the FrameOval procedure to draw its outline, or the PaintOval or FillOval procedure to draw its outline and its interior with a pattern. Figure 3-13 illustrates two ovals drawn with the FrameOval procedure.

Figure 3-13 Drawing ovals


Listing 3-6 shows the code that produces the ovals in Figure 3-13. The bounding rectangles for the ovals are created with the SetRect procedure. The resulting rectangles are then passed to the FrameOval procedure.

Listing 3-6 Using the FrameOval procedure to draw ovals

PROCEDURE MyDrawOvals;
   VAR
      firstRect, secondRect: Rect;
BEGIN
   PenSize(2,2);
   SetRect(firstRect,20,20,70,70);   {create a bounding rectangle}
   FrameOval(firstRect);             {draw the oval}
   SetRect(secondRect,90,20,140,70); {create a bounding rectangle}
   FrameOval(secondRect);            {draw the oval}
   PenNormal;
END;
An arc is defined as a portion of an oval's circumference bounded by a pair of radii. A wedge is a pie-shaped segment bounded by a pair of radii, and it extends from the center of the oval to its circumference. You use the FrameArc procedure to draw an arc (as shown on the left side of Figure 3-14), and you use the PaintArc or FillArc procedure to draw a wedge (as shown on the right side of Figure 3-14).

Figure 3-14 Drawing an arc and a wedge


Listing 3-7 shows the code that produces the images in Figure 3-14. The FrameArc, PaintArc, and FillArc procedures take three parameters: a rectangle that defines an oval's boundaries, an angle indicating the start of the arc, and an angle indicating the arc's extent. For the angle parameters, 0 indicates a vertical line straight up from the center of the oval. Positive values indicate angles in the clockwise direction from this vertical line, and negative values indicate angles in the counterclockwise direction. The arc and the wedge in Figure 3-14 both begin at 45 and extend to 135.

Listing 3-7 Using the FrameArc and PaintArc procedures

PROCEDURE MyDrawArcAndPaintWedge;
   VAR
      firstRect, secondRect: Rect;
BEGIN
   SetRect(firstRect,20,20,70,70);   {create a bounding rectangle}
   FrameArc(firstRect,45,135);       {draw an arc}
   SetRect(secondRect,90,20,140,70); {create a bounding rectangle}
   PaintArc(secondRect,45,135);      {draw a wedge}
END;
You can also fill, erase, and invert wedges by using, respectively, the FillArc, EraseArc, and InvertArc procedures.

Drawing Regions and Polygons

Before drawing regions and polygons, you must call several routines to create them. To create a region or polygon, you first call an open routine, which tells QuickDraw to collect subsequent routines to construct the shape. You use a close procedure when you are finished constructing the region or polygon. You can then frame the shape, fill it, paint it, erase it, and invert it.

To begin defining a region, you must use the NewRgn function to allocate space for it, and then call the OpenRgn procedure. You can then use any QuickDraw routine to construct the outline of the region. The outline can be any set of lines and shapes (including other regions) forming one or more closed loops. When you are finished constructing the region, use the CloseRgn procedure.

WARNING
Ensure that the memory for a region is valid before calling routines to manipulate that region; if there isn't sufficient memory, the system may crash. Regions are limited to 32 KB in size in basic QuickDraw and 64 KB in Color QuickDraw. Before defining a region, you can use the Memory Manager function MaxMem to determine whether the memory for the region is valid. You can determine the current size of an existing region by calling the Memory Manager function GetHandleSize. (Both MaxMem and GetHandleSize are described in Inside Macintosh: Memory.) When you record drawing operations in an open region, the resulting region description may overflow the 32 KB or 64 KB limit. Should this happen in Color QuickDraw, the QDError function (described in the chapter "Color QuickDraw" in this book) returns the result code regionTooBigError.
To draw the region, use the FrameRgn, PaintRgn, or FillRgn procedure. To draw the region with the background pattern of the graphics port, use the EraseRgn procedure; to invert the pixels in the region, use the InvertRgn procedure. When you no longer need the region, use the DisposeRgn procedure to release the memory used by the region.

Listing 3-8 illustrates how to create and open a region, define a shape, close the region, fill it with the all-black pattern, and dispose of the region.

Listing 3-8 Creating and drawing a region

PROCEDURE MyDrawDumbbell;
VAR
   grow:       LongInt;
   dumbbell:   RgnHandle;
   tempRect:   Rect;
BEGIN
   IF MaxMem(grow) > kMinReserve THEN
   BEGIN
      dumbbell := NewRgn;           {create a new region}
      OpenRgn;                      {begin drawing instructions}
      SetRect(tempRect,20,20,30,50);
      FrameOval(tempRect);          {form the left "weight"}
      SetRect(tempRect,25,30,85,40);
      FrameRect(tempRect);          {form the bar}
      SetRect(tempRect,80,20,90,50);
      FrameOval(tempRect);          {form the right "weight"}
      CloseRgn(dumbbell);           {stop collecting}
      FillRgn(dumbbell,black);      {draw the shape onscreen}
      IF QDError <> noErr THEN
         ; {likely error is that there is insufficient memory}
      DisposeRgn(dumbbell)             {dispose of the region}
   END;
END;
Figure 3-15 shows the shape created by Listing 3-8.

Figure 3-15 A shape created by a region


To assist you with scrolling, you can use QuickDraw routines to define a clipping region that excludes the scroll bars of the content region of a window. You can then scroll that area so that the region being updated does not draw into the scroll bars. Listing 3-9 illustrates how to create such a clipping region and, for illustrative purposes, how to fill it with a pattern. (The chapter "Basic QuickDraw" illustrates how to scroll the pixels in a rectangle such as the one created with the ClipRect procedure in Listing 3-9.)

Listing 3-9 Creating a clipping region and filling it with a pattern

FUNCTION MyFillClipRegion: RgnHandle;
VAR
   grow:          LongInt;
   newClip:       Rect;
   oldClipRegion: RgnHandle;
   newClipRegion: RgnHandle;
   myWindow:      WindowPtr;
BEGIN
   IF MaxMem(grow) > kMinReserve THEN
   BEGIN
      oldClipRegion := NewRgn;   {allocate old clipping region}
      myWindow := FrontWindow;   {get the front window}
      SetPort(myWindow);         {make the front window the current }
                                 { graphics port}
      GetClip(oldClipRegion);    {save the old clipping region}
      newClip := myWindow^.portRect;   {create a new rectangle}
      newClip.right := newClip.right - 15;   {exclude scroll bar}
      newClip.bottom := newClip.bottom - 15; {exclude scroll bar}
      ClipRect(newClip); {make the new rectangle the clipping region}
      newClipRegion := NewRgn;   {allocate new clipping region}
      RectRgn(newClipRegion, newClip);
      FillRgn(newClipRegion, ltGray);  {paint clipping region gray}
      SetClip(oldClipRegion);    {restore previous clipping region}
      IF QDError <> noErr THEN
         ; {likely error is that there is insufficient memory}
      DisposeRgn(oldClipRegion); {dispose previous clipping region}
      MyFillClipRect := (newClipRegion);
   END;
END;
Figure 3-16 shows the results of using the code in Listing 3-9.

Figure 3-16 Filling a clipping region


To create a polygon, you first call the OpenPoly function and then some number of LineTo procedures to draw lines from the first vertex of the polygon to the second, from the second to the third, and so on, until you've drawn a line to the last vertex. You then use the ClosePoly procedure, which completes the figure by drawing a connecting line from the last vertex back to the first. After defining a polygon in this way, you can display it with the FramePoly, PaintPoly, FillPoly, ErasePoly, and InvertPoly procedures. When you are finished using the polygon, use the KillPoly procedure to release its memory.

WARNING
Do not create a height or width for the polygon greater than 32,767 pixels, or PaintPoly will crash.
Listing 3-10 illustrates how to create a triangular polygon and fill it with a gray pattern.

Listing 3-10 Creating a triangular polygon

PROCEDURE MyDrawTriangle;
VAR
   triPoly: PolyHandle;
BEGIN
   triPoly := OpenPoly; {save handle and begin collecting lines}
   MoveTo(300,100);     {move to first point}
   LineTo(400,200);     {form the triangle's sides}
   LineTo(200,200);     
   ClosePoly;           {stop collecting lines}
   FillPoly(triPoly,gray); {fill the polygon with gray}
   IF QDError <> noErr THEN
      ; {likely error is that there is insufficient memory}
   KillPoly(triPoly);   {dispose of its memory}
END;

Performing Calculations and Other Manipulations of Shapes

QuickDraw provides a multitude of routines for manipulating rectangles and regions. You can use the routines that manipulate rectangles to manipulate any shape based on a rectangle--namely, rounded rectangles, ovals, arcs, and wedges. For example, you could define a rectangle to bound an oval and then frame the oval. You could then use the OffsetRect procedure to move the oval's bounding rectangle downward. Using the offset bounding rectangle, you could frame a second, connected oval to form a figure eight with the first oval. You could use that shape to help define a region. You could create a second region, and then use the UnionRgn procedure to create a region from the union of the two.

The routines for performing calculations and other manipulations of rectangles are summarized in Table 3-3 and are described in detail in "Creating and Managing Rectangles" beginning on page 3-48.
Table 3-3 QuickDraw routines for calculating and manipulating rectangles (Continued)
RoutineDescription
EmptyRectDetermines whether a rectangle is an empty rectangle
EqualRectDetermines whether two rectangles are equal
InsetRectShrinks or expands a rectangle
OffsetRectMoves a rectangle
PtInRectDetermines whether a pixel is enclosed in a rectangle
PtToAngleCalculates the angle from the middle of a rectangle to a point
Pt2RectDetermines the smallest rectangle that encloses two points
SectRectDetermines whether two rectangles intersect
UnionRectCalculates the smallest rectangle that encloses two rectangles

The routines for performing calculations and other manipulations of regions are summarized in Table 3-4 and are described in detail in "Creating and Managing Regions" beginning on page 3-81.
Table 3-4 QuickDraw routines for calculating and manipulating regions (Continued)
RoutineDescription
CopyRgnMakes a copy of a region
DiffRgnSubtracts one region from another
EmptyRgnDetermines whether a region is empty
EqualRgnDetermines whether two regions have identical sizes, shapes,
and locations
InsetRgnShrinks or expands a region
OffsetRgnMoves a region
PtInRgnDetermines whether a pixel is within a region
RectInRgnDetermines whether a rectangle intersects a region
RectRgnChanges a region to a rectangle
SectRgnCalculates the intersection of two regions
SetEmptyRgnSets a region to empty
SetRectRgnChanges a region to a rectangle
UnionRgnCalculates the union of two regions
XorRgnCalculates the difference between the union and the intersection
of two regions

Note that while you can use the OffSetPoly procedure to move a polygon, QuickDraw provides no other routines for calculating or manipulating polygons.

Copying Bits Between Graphics Ports

You can use the CopyBits procedure to copy a bit image from one graphics port to another. Along with the CopyMask procedure and the Color QuickDraw procedure CopyDeepMask, CopyBits is integral to QuickDraw's image-processing capabilities. You can use CopyBits to move offscreen graphics images into an onscreen window, to blend colors for the image in a pixel map, and to shrink and expand images. For example, Figure 3-17 illustrates how CopyBits can be used to scale the image in one window to a smaller image in another window.

Figure 3-17 Shrinking images between graphics ports


Listing 3-11 shows the code that produces the scaled image in Figure 3-17.

Listing 3-11 Using the CopyBits procedure to copy between two windows

PROCEDURE MyShrinkImages;
   VAR
      myWindow:               WindowPtr;
      sourceRect, destRect:   rect;
      halfHeight, halfWidth:  Integer;
BEGIN
   myWindow := FrontWindow;
   sourceRect.top := myWindow^.portRect.top; {create source rectangle}
   sourceRect.left := myWindow^.portRect.left;
   sourceRect.bottom := myWindow^.portRect.bottom - 15; {exclude scroll bar}
   sourceRect.right := myWindow^.portRect.right - 15;  {exclude scroll bar}

   destRect.top := gShrinkWindow^.portRect.top; {create destination rect}
   destRect.left := gShrinkWindow^.portRect.left;
   halfHeight :=              {make destination half as tall as the source}
            Integer((sourceRect.bottom - sourceRect.top)) DIV 2;
   destRect.bottom := destRect.top + halfHeight;
   halfWidth :=               {make destination half as wide as the source}
            Integer((sourceRect.right - sourceRect.left)) DIV 2;
   destRect.right := destRect.left + halfWidth;
   
   GetPort(myWindow);      {save the graphics port for the active window}
   SetPort(gShrinkWindow); {make the target window the current }
                           { graphics port for drawing purposes}
   CopyBits(myWindow^.portBits, 
            gShrinkWindow^.portBits, 
            sourceRect, 
            destRect, 
            srcCopy+ditherCopy, NIL);
   IF QDError <> noErr THEN
      ; {likely error is that there is insufficient memory}
   SetPort(myWindow);      {restore active window as current graphics port}
END;
When copying between basic graphics ports, you specify a source bitmap and a destination bitmap to CopyBits. Remember that the bitmap is stored in the portBits field of a GrafPort record. By dereferencing the desired window record when it calls CopyBits, Listing 3-11 uses the bitmap for the front window, "untitled" in Figure 3-17, as the source bitmap. Listing 3-11 uses the bitmap for the window titled "50%" as the destination bitmap.

When copying images between color graphics ports, as explained in the chapter "Color QuickDraw," you must coerce each CGrafPort record to a GrafPort record, dereference the portBits fields of each, and then pass these "bitmaps" to CopyBits.

Note
If there is insufficient memory to complete a CopyBits operation in Color QuickDraw, the QDError function (described in the chapter "Color QuickDraw" in this book) returns the result code -143.
You can specify differently sized source and destination rectangles, and CopyBits scales the source image to fit the destination. Listing 3-11 uses the area of the port rectangle excluding the scroll bars as the source rectangle. To scale the image in the front window, Listing 3-11 creates a destination rectangle that is half as high and half as wide as the source rectangle.

The manner by which CopyBits transfers the bits between bitmaps depends on the source mode that you specify. In Listing 3-11, the srcCopy mode is used to copy bits from the source directly into the destination. Source modes are described in "Boolean Transfer Modes With 1-Bit Pixels" beginning on page 3-7.

Note
To scale shapes and regions within the same graphics port, you can use the routines described in "Scaling and Mapping Points, Rectangles, Polygons, and Regions" beginning on page 3-100.
To gracefully display complex images that your application creates, your application should use the drawing routines described in this chapter to construct such images in offscreen graphics worlds. Your application can then use the CopyBits procedure to transfer these images to onscreen graphics ports. This technique prevents the choppiness that can occur when you build complex images onscreen, and is described in the chapter "Offscreen Graphics Worlds," which also offers an example of using a mask to copy color pixels from an offscreen graphics world.

To copy only certain bits from a bitmap, you can use the CopyMask procedure, which is a specialized variant of CopyBits. The CopyMask procedure, which is described on page 3-115, transfers bits only where the corresponding bits of another bit image, which serves as a mask, are set to 1 (that is, black). The CopyMask procedure does not allow scaling or resizing. However, the CopyDeepMask procedure, which is described on page 3-116, does allow scaling and resizing; in effect it combines the capabilities of the CopyBits and CopyMask procedures.

Customizing QuickDraw's Low-Level Routines

For each shape that QuickDraw knows how to draw, there are procedures that perform these basic graphics operations on the shape: frame, paint, erase, invert, and fill. Those procedures in turn call a low-level drawing routine for the shape. For example, the FrameOval, PaintOval, EraseOval, InvertOval, and FillOval procedures all call the low-level procedure StdOval, which draws the oval. For each type of object QuickDraw can draw, including text and lines, there's a pointer to such a low-level routine. By changing these pointers, you can install your own routines, and either completely override the standard ones or call them after your routines have modified their parameters as necessary.

Other low-level routines that you can install in this way include

All of the low-level QuickDraw routines that your application can replace or call after performing its own operations are described in "Customizing QuickDraw Operations" beginning on page 3-124.

The grafProcs field of a graphics port determines which low-level routines are called. If that field contains the value of NIL, the standard routines are called, so that all operations in that graphics port are done in the standard ways described in this chapter. You can set the grafProcs field to point to a record of pointers to your own routines. This record of pointers is defined by a data structure of type QDProcs, which is described on page 3-35.

To assist you in setting up a record, QuickDraw provides the SetStdProcs procedure, which is described on page 3-125. You can use the SetStdProcs procedure to get a QDProcs record with fields that point to the standard routines. You can reset the ones with which you are concerned. You can replace these low-level routines with your own, and then point to your modified QDProcs record in the grafProcs field of a GrafPort record to change basic QuickDraw's standard low-level behavior.

IMPORTANT
When modifying the low-level routines for a color graphics port, you must always use the SetStdCProcs procedure instead of SetStdProcs.
The chapter "Pictures" in this book provides sample code and explanations for changing the standard low-level routines for reading and writing pictures.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996

Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2004 Apple Computer, Inc.
All rights reserved. | Terms of use | Privacy Notice