Quartz Graphics Data Types

As we discussed earlier, the Application Kit defines a number of data types and structures that are useful for drawing with Quartz. These data types are defined in the file NSGeometry.h, and we’ll describe some of them in this section.

Any point on the computer’s screen is defined by an NSPoint structure:

typedef struct _NSPoint {
    float x;
    float y;
} NSPoint;

An extent in space is defined by an NSSize structure:

typedef struct _NSSize {
    float width;             // should never be negative
    float height;            // should never be negative
} NSSize;

Conveniently, a rectangle, NSRect, is defined by an extent from a point:

typedef struct _NSRect {
    NSPoint origin;
    NSSize size;
} NSRect;

Cocoa defines a number of inline functions for creating and managing these structures. The code for an inline function is integrated directly into the code for its callers, so there is no function call overhead associated with using them. These functions allow you to create an unnamed structure that is used as an argument in a function call or method invocation and then destroyed. The functions are:

NSPoint NSMakePoint(float x, float y)
NSSize  NSMakeSize(float w, float h)
NSRect  NSMakeRect(float x, float y, float w, float h)

There are also a number of convenience functions in Cocoa, which are summarized in Table 14-1.

Table 14-1. Convenience graphics functions

Graphics function

Purpose

float NSMaxX(aRect)

Returns the maximum X coordinate (the right side) of the rectangle

float NSMaxY(aRect)

Returns the maximum Y coordinate (usually the top, unless the coordinate system is flipped) of the rectangle

float NSMidX(aRect)

Returns the horizontal median of the rectangle

float NSMidY(aRect)

Returns the vertical median of the rectangle

float NSMinX(aRect)

Returns the minimum X coordinate (the left side) of the rectangle

float NSMinY(aRect)

Returns the minimum Y coordinate (usually the bottom) of the rectangle

float NSWidth(aRect)

Returns the width of the rectangle

float NSHeight(aRect)

Returns the height of the rectangle

BOOL NSEqualPoints(point1,point2)

Returns YES if point1==point2

BOOL NSEqualSizes(size1,size2)

Returns YES if size1==size2

BOOL NSEqualRects(rect1,rect2)

Returns YES if rect1==rect2

BOOL NSIsEmptyRect(aRect)

Returns YES if aRect has a zero size

NSRect NSUnionRect(rect1,rect2)

Returns the union of two rectangles

NSRect NSIntersectionRect(rect1,rect2)

Returns the intersection of two rectangles

BOOL NSPointInRect(aPoint,aRect)

Returns YES if aPoint is inside aRect

BOOL NSContainsRect(aRect,bRect)

Returns YES if bRect is inside aRect

BOOL NSIntersectsRect(aRect,bRect)

Returns YES if the two rectangles intersect

NSString *NSStringFromPoint(aPoint)

Returns a standard string coding of a point

NSString *NSStringFromSize(aSize)

Returns a standard string coding of a size

NSString *NSStringFromRect(aRect)

Returns a standard string coding of a rectangle

NSPoint NSPointFromString(aString)

Maps the string back to a point

NSSize NSSizeFromString(aString)

Maps the string back to a size

NSRect NSRectFromString(aString)

Maps the string back to a rectangle

There are other functions as well; you should review the file NSGeometry.h or the “Functions” section of the Foundation framework documentation to learn about them.

Setting Colors, Drawing Rectangles, and Drawing Lines

The NSColor class is used both to specify a particular color and to set it to be the current color in the current drawing context.

The NSColor class predefines 15 colors as class (or factory) methods. They are shown in Table 14-2 (the + means they are class methods).

Table 14-2. Predefined color methods in the NSColor class

+ blackColor

+ blueColor

+ brownColor

+ clearColor

+ cyanColor

+ darkGrayColor

+ grayColor

+ greenColor

+ lightGrayColor

+ magentaColor

+ orangeColor

+ purpleColor

+ redColor

+ whiteColor

+ yellowColor

You can also create a color by specifying its components using a variety of color models, including RGB, CYMK, HSB, and Pantone colors. These NSColor class methods are listed in Table 14-3.

Table 14-3. Factory methods for creating colors

+ colorWithCalibratedHue:saturation:brightness:alpha:

+ colorWithCalibratedRed:green:blue:alpha:

+ colorWithCalibratedWhite:alpha:

+ colorWithCatalogName:colorName:

+ colorWithDeviceCyan:magenta:yellow:black:alpha:

+ colorWithDeviceHue:saturation:brightness:alpha:

+ colorWithDeviceRed:green:blue:alpha:

+ colorWithDeviceWhite:alpha:

After you have created an NSColor object, you can make it the current drawing color by sending it the set method. Remember that before you call this method, a view must be established as the current drawing context with the lockFocus method (and have its drawing method called with drawRect:).

After you set a color, you can draw in that color. In the NSGraphics.h file, you’ll find an extensive list of functions for drawing a variety of rectangles, bitmaps, bezeled rectangles, and so on. More complicated objects can be drawn using the NSBezierPath class. One way to think of this class is as a variable-length storage object that allows you to create a path with a particular combination of lines and curves. This object can have a specific line width, fill, end caps, etc. When you’re done, you send the instance the stroke method to perform all of the drawing.

For example, we could use the following two statements to draw a white rectangle in the currently selected drawing view:

[ [NSColor whiteColor] set];
[NSBezierPath fillRect:rect];

We could draw four horizontal black lines, each two points thick, using the following sequence:

[ [NSColor blackColor] set];
[NSBezierPath setDefaultLineWidth:2.0];
[NSBezierPath strokeLineFromPoint:NSMakePoint(20,20)
                          toPoint:NSMakePoint(300,20)];
[NSBezierPath strokeLineFromPoint:NSMakePoint(20,30)
                          toPoint:NSMakePoint(300,30)];
[NSBezierPath strokeLineFromPoint:NSMakePoint(20,40)
                          toPoint:NSMakePoint(300,40)];
[NSBezierPath strokeLineFromPoint:NSMakePoint(20,50)
                          toPoint:NSMakePoint(300,50)];

To create a simple four-pointed star, we could use four Bezier curves that have their endpoints at the corners of the star and their control points in the star’s center (see the documentation for more on Bezier curves), as shown in this code:

NSBezierPath *path = [NSBezierPath bezierPath];
NSPoint center = NSMakePoint(50,50);

[ [NSColor blackColor] set];
[path setLineWidth:1.0];
[path moveToPoint:NSMakePoint(50,0)];
[path curveToPoint:NSMakePoint(100,50)
     controlPoint1:center controlPoint2:center];
[path curveToPoint:NSMakePoint(50,100)
     controlPoint1:center controlPoint2:center];
[path curveToPoint:NSMakePoint(0,50)
     controlPoint1:center controlPoint2:center];
[path curveToPoint:NSMakePoint(50,0)
     controlPoint1:center controlPoint2:center];
[path stroke];

Drawing Text with Quartz

To draw text with Quartz, you need the following:

  • A view in which to draw

  • The actual text that you want to draw

  • The font, font size, and other attribute information for the text

  • A location in the selected view where you want the text to be drawn

You can draw text in Cocoa with either the NSString class or the NSAttributedString class. The classes themselves don’t do the actual drawings; instead, the AppKit adds a category to each called NSStringDrawing. Details of this category can be found in the include file NSStringDrawing.h.

The view in which you want to draw is selected with the lockFocus method. The text is specified by the contents of the NSString or NSAttributedString class with which you are drawing.

The AppKit allows you to specify a wide variety of attributes when you draw text. These attributes can be stored in an NSDictionary. If you are drawing text with the NSString class, the NSDictionary must be provided to the NSString object when the drawing begins. If you are drawing with an NSAttributedString object, the attributes can be applied to a range of characters within the NSAttributedString class before you actually draw. Table 14-4 lists the available attributes. These attributes are defined in the file NSAttributedString.h, and they are all NSString * values.

Table 14-4. Drawing attributes for the NSAttributedString and NSString classes

Attribute identifier

Value class

Default value

NSFontAttributeName

NSFont

12-point Helvetica

NSForegroundColorAttributeName

NSColor

Black

NSBackgroundColorAttributeName

NSColor

None (no background drawn)

NSUnderlineStyleAttributeName

NSNumber, as an int

None (no underline)

NSSuperscriptAttributeName

NSNumber, as an int

0

NSBaselineOffsetAttributeName

NSNumber, as a float

0.0

NSKernAttributeName

NSNumber, as a float

0.0

NSLigatureAttributeName

NSNumber, as an int

1 (standard ligatures)

NSParagraphStyleAttributeName

NSParagraphStyle

Value returned by NSParagraphStyle’s defaultParagraphStyle method

NSAttachmentAttributeName

NSTextAttachment

None (no attachment)

For example, let’s say that we want to draw some text in green, 36-point Helvetica. First we need to create the font. We can do this using the fontWithName:size: class method, as follows:

NSFont *font = [NSFont fontWithName:@"Helvetica" size:36.0];

Next we need to create an NSMutableDictionary of key/value pairs that contains this font as the value for the key NSFontAttributeName and the green NSColor object as the value for the NSForegroundColorAttributeName key.

The NSMutableDictionary should look like this:

NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
[attrs setObject:font forKey:NSFontAttributeName];
[attrs setObject:[NSColor greenColor]forKey:NSForegroundColorAttributeName];

With the NSMutableDictionary set up, we can now create an NSAttributedString that contains the text that we want to draw, modified by the new attributes:

str = [ [NSMutableAttributedString alloc]
        initWithString:@"MathPaper" attributes:attrs];

To draw with this string, we need to lock focus on a particular view and use the NSAttributeString’s drawAtPoint: method:

[aView lockFocus];
[str drawAtPoint:NSMakePoint(20,50)];
[aView unlockFocus];

Even better would be implementing a drawRect: method to draw the text:

- (void)drawRect:(NSRect)rect
{
    [str drawAtPoint:NSMakePoint(20,50)];
}

As an alternative to drawing with an NSAttributedString class, we can simply use an NSString object. We can use any NSString object, even one created with the @"" operator:

- (void)drawRect:(NSRect)rect
{
    [@"Text" drawAtPoint:NSMakePoint(20,20) withAttributes:attrs];
}

If we know that the text should fit within a particular size box, we can use the drawInRect:withAttributes: method:

- (void)drawRect:(NSRect)rect
{
    [@"Text" drawAInRect:NSMakeRect(20,20,100,100)
             withAttributes:attrs];
}

The drawInRect:withAttributes: method is also useful for displaying text that is wrapped to a particular width.

Drawing Images with Quartz

It’s just as easy to draw pictures with Quartz as it is to draw text. In fact, in some ways it’s even easier. Practically anything that you’ll ever need to do with an image in Cocoa can be done with the NSImage class for manipulating images.

Using the NSImage class, you can do all of the following:

  • Read an image from a file.

  • Scale an image to a particular size.

  • Convert an image from one representation to another.

  • Draw an image in a view, or combine the contents of the image with the contents already present in the view.

NSImage accomplishes this magic by using objects of another class, called NSImageRep, to perform the actual work of storing the image. A single NSImage instance can have several NSImageRep representations of an image. For example, it might have both a bitmap representation for quick redisplay on the screen and a PDF representation for detailed display on a printer. (At this point, we recommend that you read the Cocoa documentation for the NSImage class.)

The NSImage class transfers images to the screen through a process called compositing . Compositing is a way of combining two images, a source image and a destination image (the image already in place on the screen). The combining is done with a special function called the compositing operator , which combines the two images on a pixel-by-pixel basis and displays the result.

When you composite, you can specify the following:

  • The source image for the compositing.

  • The destination image.

  • The compositing operation.

  • The fraction of the compositing operation that should be used for calculating the final result. A fraction of 1.0 means that the source pixels should be set entirely depending on the results of the compositing. A fraction of 0.5 means that half of the pixel’s final value should come from the result of the compositing operation, and half of the pixel’s final value should be the same as the original value.

Cocoa supports 14 different compositing operations. These operations are defined in the file NSGraphics.h. The two most common compositing operations are NSCompositeCopy and NSCompositeSourceOver. NSCompositeCopy copies the rectangle bounded by the source image into the destination image; everything in the destination image is lost. NSCompositeSourceOver is similar, but the source image is placed on top of the destination image, so that you may be able to see parts of the destination image through any pixels in the source image that are transparent or partially transparent. Because of the way Aqua handles transparency, you should generally use NSCompositeSourceOver and not NSCompositeCopy. If you have a few transparent pixels in your source image, NSCompositeCopy will copy these transparent pixels to the destination, making it transparent as well. This is not usually what you want.

The most common compositing operations are listed in Table 14-5. In each case, the source is defined as the image stored inside the NSImage object, while the destination is the region in which the NSImage is being composited. The destination can be any locked focus, including an NSView, another NSImage, or even a Quartz graphics state.

Table 14-5. Common compositing operations

Compositing operation

Meaning

NSCompositeSourceOver

“Source over destination” composites with attention to transparency in NSImage. This is the operation that you should normally use to “copy” an image into a window.

NSCompositeCopy

Copies the image to the NSView (destination). You generally should not use this operation, as it can cause your windows to be “promoted” to windows that contain alpha (transparency) if the source image has alpha.

NSCompositeClear

Clears the area where the image is to be copied. This isn’t used much.

NSCompositeXOR

Performs an exclusive-OR between the NSImage and the NSView destination.

NSCompositePlusDarker

Performs mathematical addition between the source and the NSView. Whites get brighter and blacks get darker.

NSCompositeHighlight

Highlights the source image.

The key method for compositing is compositeToPoint:operation . Because this method is a Quartz drawing operation, it should be used only inside a drawRect: method or between invocations of the lockFocus and unlockFocus methods sent to the NSView object in which the compositing is to occur.

For example, to display an NSImage in a view is to lock focus on the view and then to composite the image to a point. To do this, you might use code that looks like this:

- drawRect:(NSRect)aRect
{
    image = [NSImage imageNamed:@"PaperIcon"];
    [image compositeToPoint:NSMakePoint(100,100)
                  operation:NSCompositeSourceOver];
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.124.177