In your view’s drawRect: method, one of the first things you may want to do is modify the current drawing environment. For example, you might want to configure the current drawing colors, modifying the clipping region, transform the coordinate system, and so on. Many attributes can be set directly using the methods of NSGraphicsContext but some require the use of other objects. The following sections list the available drawing attributes and how you modify them.
Important: Saving and restoring the current graphics state is an expensive operation and should done as little as possible. With the exception of clipping paths, most state attributes can be undone manually in your code without saving and restoring the entire state. In addition, if several paths use the same set of drawing attributes, it is more efficient to configure the graphics state once and draw those paths together than it is to save and restore the graphics state for each path.
Setting Colors and Patterns
Setting Path Attributes
Setting Text Attributes
Setting Compositing Options
Setting the Clipping Region
Setting the Anti-aliasing Options
Cocoa provides support for colors in a variety of different color spaces. The NSColor class supports RGB, CMYK, and grayscale color spaces by default but can also support custom color spaces defined by ICC and ColorSync profiles. The colors you specify include the color channels appropriate for the color space and an optional alpha component to define the transparency of the color.
To set the current stroke or fill attributes, create an NSColor object and send it a set, setStroke, or setFill message. The stroke and fill attributes define the color or pattern for paths and the areas they enclose. The current stroke and fill colors affect all drawn content except text, which requires the application of text attributes; see “Applying Color to Text.”
For more information about colors and how to create them, see “Color and Transparency.”
To modify the value of path attributes, you use the NSBezierPath class. Using the methods of this class, you can set the line width, line join style, line dash style, line cap style, miter limit, flatness, and winding rule attributes. All of these attributes affect the way paths are rendered by Cocoa.
Path attributes come in two flavors: global and path-specific. When you use the class methods in NSBezierPath to set the "default" value for an attribute, you are setting the global attribute. Global attributes are global to path objects (as opposed to the graphics state), so setting a global attribute affects all paths you render using the NSBezierPath class, but does not affect Quartz-based paths. To override a global attribute for an individual path object, you should set a path-specific value. For example, to set the global line width, you use the setDefaultLineWidth: class method of NSBezierPath. To set the line width for a specific NSBezierPath object, you use its setLineWidth: instance method.
For information on how to set both default and path-specific attributes, and to see the resulting appearance of rendered content, see “Path Attributes.”
For most string-based drawing in Cocoa, you apply text attributes directly to the strings, rather than relying on the global font settings. The Cocoa string objects and the Cocoa text system both support the use of attributes for modifying the appearance of string. For NSAttributedString objects, you apply the attributes directly to character ranges in the string. For regular NSString objects, you apply the attributes to the entire string when you draw it.
If you want to set the global font settings stored in the graphics state, perhaps for drawing strings using Quartz, you can use the NSFont object to set the font family and size. After creating a font object, you use its set method to apply the font information to the current graphics state.
For more information about drawing options for text, see “Text.” For more information about the Cocoa text system, see Text System Overview.
When you render each visual element, you need to decide how that element interacts with any surrounding content. You might want the element to be layered on top of or behind the current content or be merged with it in interesting ways. You specify this behavior using different compositing options.
Compositing options specify how the colors in source content are blended with the existing content in the drawing destination. With fully opaque colors, most compositing options simply mask or overlay different parts of the source and destination content. With partially transparent colors, however, you can achieve interesting blending effects.
The Cocoa compositing options differ from the blend modes used in Quartz, although the two perform basically the same task. The Cocoa options are inherited from the NextStep environment, whereas the Quartz blend modes are part of the newer PDF-based rendering model. Despite their historical legacy, the Cocoa options are still a very powerful way to composite content, and may even be a little easier to understand than their Quartz counterparts.
Important: Despite their similarities, there is no direct mapping between the Cocoa compositing options and the Quartz blend modes. In addition, when drawing to a print-based canvas, you should use only the NSCompositeCopy or the NSCompositeSourceOver operators. (For PDF content, you should use only the NSCompositeSourceOver operator or the Quartz blend modes.) If you need to use any other compositing operators, you should render your content to an image and then draw the image to the printing context using one of the supported operators. If your application relies heavily on PDF blend modes, you may want to use Quartz for your drawing instead.
Figure 2-1 shows the Cocoa compositing options and how they affect rendered content. At the top of the figure are the source and destination content being rendered. The veins of the leaf are completely transparent while the rest of the leaf is opaque. In the destination image, the color is rendered at partial opacity. Below that are the results for each of the supported compositing operations.
Table 2-2 lists the mathematical equations used to compute pixel colors during compositing operations. In each equation, R is the resulting (premultiplied) color, S is the source color, D is the destination color, Sa is the alpha value of the source color, and Da is the alpha value of the destination color. All color component values and alpha values are in the range 0 to 1 for these computations.
Para | Para |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To set the current compositing operation, you use the setCompositingOperation: method of NSGraphicsContext. This sets the global compositing option to use if no other operator is specified. The default compositing option is NSCompositeSourceOver.
The clipping region is a useful way to limit drawing to a specific portion of your view. Instead of creating complex graphics offscreen and then compositing them precisely in your view, you can use a clipping region to mask out the portions of your view you do not want modified. For example, you might use a clipping region to prevent drawing commands from drawing over some already rendered content. Similarly, you might use a clipping region to cut out specific portions of an image you want to render.
Before invoking your view’s drawRect: method, Cocoa configures the clipping region of the current graphics context to match the visible area of your view. This prevents your view's drawing code from rendering content outside of your view's boundaries, possibly on top of other views.
You can restrict the drawable region of your view even further by adding shapes to the current clipping region. Whenever you add a new shape to the current clipping region, Cocoa determines the intersection of the shape with the current clipping region and uses the result as the new clipping region. This behavior means that you should generally add only one shape to the clip region before doing your drawing. The shape you add can be a single rectangle, multiple rectangles, or a combination of multiple complex subpaths in a single NSBezierPath object.
For simple rectangular shapes, the easiest way to clip is using the NSRectClip function. To specify multiple rectangular regions, use the NSRectClipList function instead. To clip your view to a nonrectangular region, you must use an NSBezierPath object. The path you create can be arbitrarily complex and include multiple rectangular and nonrectangular regions. Once you have the path you want, use the object’s addClip method to add the resulting shape to the current clipping region. (For information on how to create paths, see “Drawing Fundamental Shapes.”)
Figure 2-2 shows the effects of applying a clipping path to an image. The top images show the image to be clipped and the path to use for the clip shape, which in this case consists of two shapes inside a single NSBezierPath object. Although the clip shape is the same in both cases, the resulting clip region is different. This is because clipping takes into account the current winding rule when calculating the clipping region.
The following example shows you how to create the clip region shown in Figure 2-2. The clip region is composed of an overlapping square and circle, so you simply add a rectangle and oval with the appropriate sizes to a Bezier path object and call the addClip method.
// If you plan to do more drawing later, it's a good idea |
// to save the graphics state before clipping. |
[NSGraphicsContext saveGraphicsState]; |
// Create the path and add the shapes |
NSBezierPath* clipPath = [NSBezierPath bezierPath]; |
[clipPath appendBezierPathWithRect:NSMakeRect(0.0, 0.0, 100.0, 100.0)]; |
[clipPath appendBezierPathWithOvalInRect:NSMakeRect(50.0, 50.0, 100.0, 100.0)]; |
// Add the path to the clip shape. |
[clipPath addClip]; |
// Draw the image. |
[NSGraphicsContext restoreGraphicsState]; |
Warning:
Although you can also use the setClip method of NSBezierPath to modify the clipping region, doing so is not recommended. The setClip method replaces the entire clipping region with the area you specify. If the new clipping region extends beyond the bounds of your view, this could lead to portions of your content spilling over into neighboring views.
Cocoa graphics contexts support anti-aliasing in the same way that their Quartz counterparts do. Anti-aliasing is the process of artificially correcting the jagged (or aliased) edges surrounding text or shapes in bitmap images. These jagged edges occur primarily in lower-resolution bitmaps where it is easier to see individual pixels. To remove the jagged edges, Cocoa uses different colors for the pixels that surround a shape’s outline. The colors it uses are a blend of the original pixel color and the color of the shape’s outline. By blending colors in this way, the edges of the shape appear much smoother. Figure 2-3 shows the same image aliased and anti-aliased.
To enable or disable anti-aliasing, use the setShouldAntialias: method of NSGraphicsContext. Even with anti-aliasing disabled, it may still appears as if Cocoa is drawing content using aliasing. When drawing content on nonpixel boundaries, Cocoa may opt to split the line over multiple pixels, which can give the impression of aliasing. For more information about how to avoid this situation, see “Doing Pixel-Exact Drawing.”
Last updated: 2007-10-31