Cocoa was designed to integrate well with other technologies in Mac OS X. Many technologies are packaged as Objective-C frameworks, which makes including them in Cocoa easy. You are not limited to the use of Objective-C frameworks, though. Cocoa itself uses Quartz internally to implement most drawing routines. You can use Quartz and other C-based technologies, such as OpenGL and QuickTime, from your code with little extra effort.
The sections that follow provide information about how to incorporate some of the more important drawing technologies available in Mac OS X.
Using Quartz in Your Application
Using OpenGL in Your Application
Using QuickTime in Your Application
Using Quartz Composer Compositions
Choosing the Right Imaging Technology
Everything you can draw using Cocoa can also be drawn using Quartz. The Cocoa drawing code itself uses Quartz primitives to render content. Cocoa simply adds an object-oriented interface and in some cases does more of the work for you. Cocoa does not provide classes for all Quartz behavior, however. In situations where a feature is not available in Cocoa, you may want to use Quartz directly.
For general information about Quartz features and how to use them, see Quartz 2D Programming Guide.
Because Quartz implements some features that Cocoa does not, there may be times when you need to use Quartz function calls from your Cocoa code. Because Cocoa uses Quartz for most drawing operations, mixing the two technologies is not an issue.
Some of the Quartz features that are not supported directly by Cocoa include the following:
Arbitrary patterns (other than images)
In each case, you are free to use Quartz functions to take advantage of these features. Some features can produce data types that you can then incorporate back into a Cocoa object. (For example, you can use an image data source to obtain a Quartz image (CGImageRef
), which you can then use to create an NSImage
object.) In some cases, however, you may need to perform the entire operation using Quartz functions.
For information on how to use Quartz features, see Quartz 2D Programming Guide.
When going back and forth between Cocoa and Quartz code, some conversion of data types may be necessary. Table 9-1 shows the Cocoa equivalents of some basic Quartz types.
Cocoa type |
Quartz type |
---|---|
Although in each case the structure layout is the same, you cannot pass the Quartz data type directly to a method expecting the Cocoa type. To convert, you must cast from one type to another, as shown in the following example:
NSRect cocoaRect = *(NSRect*)&myCGRect; |
Table 9-2 lists the Cocoa classes that approximate the behavior of specific Quartz data types. In some cases, the Cocoa class wraps an instance of its Quartz counterpart, but that is not always true. In the case of shadows, Quartz provides no direct data type for managing the shadow parameters; you must set shadows attributes in Quartz using several different functions. In the case of layers, there are no Cocoa equivalents.
Cocoa type |
Quartz type |
---|---|
|
|
No equivalent |
Because Cocoa types often wrap equivalent Quartz types, you should look at the Cocoa reference documentation for information about how to get equivalent Quartz objects, if any. In many cases, Cocoa classes do not offer direct access to their Quartz equivalent and you may need to create the Quartz type based on information in the Cocoa object, such as in the following cases:
To create a CGPathRef
object from an NSBezierPath
object, you must redraw the path using Quartz function calls. Use the elementAtIndex:associatedPoints:
method of NSBezierPath
to retrieve the path’s point information.
To convert back and forth between CGColorRef
and NSColor
objects, get the color component values from one object and use those values to create the other object. When creating colors, you may also need to specify the color space for that color. For the most part, Quartz and Cocoa support the same color spaces. If a color uses a custom color space, you can use the available ICC profile data to create the appropriate color space object.
To create an NSImage
object from a Quartz image, you need to create the image object indirectly. For information on how to do this, see “Using a Quartz Image to Create an NSImage.”
To create Quartz shadows, you can use the methods of NSShadow
to retrieve the color, offset, and blur radius values prior to calling CGContextSetShadow
or CGContextSetShadowWithColor
.
Before using any Quartz features, you need to obtain a Quartz graphics context (CGContextRef
) for drawing. For view-based drawing, you can get the context by sending a graphicsPort
message to the current Cocoa graphics context (NSGraphicsContext
). This method returns a pointer that you can cast to a CGContextRef
data type and use in subsequent Quartz function calls.
In Mac OS X v10.4 and later, if you have an existing Quartz graphics context, you can create a Cocoa graphics context object using the graphicsContextWithGraphicsPort:flipped:
class method of NSGraphicsContext
. You then use the setCurrentContext:
class method to make that context the current context.
When mixing calls to Quartz and Cocoa, remember that many Cocoa classes maintain a local copy of some graphics attributes normally associated with the Quartz graphics context. When such a class is ready to draw its content, it modifies the graphics state to match its local settings, draws its content, and restores the graphics state to its original settings. If you use Quartz to change an attribute that is maintained locally by a Cocoa class, your changes may not be used.
If you make changes to the graphics state using the NSGraphicsContext
class, your changes are immediately conveyed to the Quartz graphics context, and vice versa. If you are not using NSGraphicsContext
to set an attribute, you should assume that the attribute is local to the object. For example, the NSBezierPath
class prefers local copies of graphics attributes over the default (or global) attributes stored in the current context.
OpenGL is an open, cross-platform, three-dimensional (3D) graphics standard with broad industry support. OpenGL eases the task of writing real-time 2D or 3D graphics applications by providing a mature, well-documented graphics processing pipeline that supports the abstraction of current and future hardware accelerators.
The sections that follow provide a glimpse into the techniques used to incorporate OpenGL drawing calls into your Cocoa application. For more on OpenGL support in Mac OS X, and for detailed examples of how to integrate OpenGL into your Cocoa application, see OpenGL Programming Guide for Mac OS X. For general information about OpenGL, see Reference Library > Graphics & Imaging > OpenGL.
One way to do OpenGL drawing is to add an OpenGL view (an instance of NSOpenGLView
) to your window. An OpenGL view behaves like any other view but also stores a pointer to an OpenGL graphics context object (an instance of NSOpenGLContext
). Storing the graphics context in the view eliminates the need for your code to recreate the context during each drawing cycle, which can be expensive.
To use an OpenGL view in your program, you create a subclass of NSOpenGLView
and add that view to your window, either programmatically or using Interface Builder. When creating an OpenGL view programmatically, you specify the pixel format object you want to associate with the view. A pixel format object (an instance of NSOpenGLPixelFormat
) specifies the buffers and other rendering attributes of the OpenGL graphics context. For information on the meaning of different pixel format attributes, see OpenGL Programming Guide for Mac OS X.
If you use Interface Builder to add your view to a window, you specify the pixel format information using the inspector for your view. Interface Builder lets you specify some pixel attributes, but not all. To support other attributes, you must replace the view’s pixel format object at runtime using the setPixelFormat:
method.
Important:
If you set the pixel format attributes programmatically, you must do so before getting the OpenGL graphics context using the openGLContext
method. The graphics context is created with the current pixel format information and is not recreated if that information changes. Alternatively, you can change the OpenGL graphics context at any time using the setOpenGLContext:
method.
As with other views, you use your OpenGL view’s drawRect:
method to draw the content of your view. When your drawRect:
method is invoked, the environment is automatically configured for drawing using the OpenGL graphics context associated with your view.
Unlike with other graphics contexts, you do not need to restore the previous OpenGL graphics context when you are done drawing. OpenGL does not maintain a stack of graphics contexts that need to be popped as they are no longer needed. Instead, it simply uses the most recent context that was made current.
Before creating an OpenGL graphics context object, you first create a pixel format object (NSOpenGLPixelFormat
). The attributes you specify when creating your pixel format object determine the rendering behavior of the graphics context. Once you have a valid pixel format object, you can create and initialize your OpenGL graphics context object.
Listing 9-1 attempts to create an OpenGL graphics context that supports full-screen, double-buffered, 32-bit drawing. If the desired renderer is available, it returns the context; otherwise, it returns nil
.
Listing 9-1 Creating an OpenGL graphics context
- (NSOpenGLContext*)getMyContext |
{ |
// Specify the pixel-format attributes. |
NSOpenGLPixelFormatAttribute attrs[] = |
{ |
NSOpenGLPFAFullScreen, |
NSOpenGLPFADoubleBuffer, |
NSOpenGLPFADepthSize, 32, |
0 |
}; |
// Create the pixel-format object. |
NSOpenGLContext* myContext = nil; |
NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] |
initWithAttributes:attrs]; |
// If the pixel format is valid, create the OpenGL context. |
if (pixFmt != nil) |
{ |
myContext = [[NSOpenGLContext alloc] initWithFormat:pixFmt |
shareContext:NO]; |
} |
[pixFmt release]; |
return myContext; |
} |
Because the creation of OpenGL graphics contexts depends on the currently available renderers, your code should always verify that the desired objects were created before trying to use them. If creating an object fails, you can always try to create it again using a different set of attributes.
QuickTime is Apple's cross-platform multimedia technology designed to help you create and deliver video, sound, animation, graphics, text, interactivity, and music. QuickTime supports dozens of file and compression formats for images, video, and audio, including ISO-compliant MPEG-4 video and AAC audio.
You can incorporate QuickTime features into your Cocoa applications in one of two ways. The easiest way is through the QuickTime Kit, which is a full-featured Objective-C based framework for the QuickTime interfaces. If you are already familiar with the C-based QuickTime interfaces, you can use those instead.
The QuickTime Kit framework (QTKit.framework
) works with QuickTime movies in Cocoa applications in Mac OS X. The QuickTime Kit framework was introduced in Mac OS X v10.4 and was designed as an alternative to and eventual replacement for the existing NSMovie
and NSMovieView
classes in Cocoa. This new framework provides more extensive coverage of QuickTime functions and data types than had been offered by the Application Kit classes. More importantly, the framework does not require Cocoa programmers to be conversant with Carbon data types such as handles, aliases, file-system specifications, and so on.
The QuickTime Kit framework is available primarily in Mac OS X v10.4 and later, but it is also supported in Mac OS X v10.3 with QuickTime 7 or later installed. For information on how to use the QuickTime Kit, see QuickTime Kit Programming Guide. For a reference of the classes in the QuickTime Kit, see QTKit Framework Reference.
Long before the introduction of the QuickTime Kit framework, QuickTime programs were written using a C-based API. The QuickTime API encompasses thousands of functions and gives you the maximum flexibility in managing QuickTime content. You can use this API in your Cocoa applications like you would any other framework.
For an introduction to QuickTime, see QuickTime Overview. For the complete QuickTime reference, see QuickTime Framework Reference.
If your software runs in Mac OS X v10.4 and later, you can use Quartz Composer to render complex graphical content. Quartz Composer uses the latest Mac OS X graphics technologies to create advanced graphical images and animations quickly and easily. You use the Quartz Composer application to create composition files graphically and then load those compositions into your Cocoa application and run them. Changing the behavior of your Cocoa application is then as simple as updating the composition file.
Quartz Composer is especially suited for applications that want to perform complex image manipulations. Through it, you gain easy access to features of Quartz 2D, Core Image, Core Video, OpenGL, QuickTime, MIDI System Services, and Real Simple Syndication (RSS). Your application can render compositions for display or provide the user with controls for manipulating the composition parameters.
For a detailed example showing you how to run a composition from your Cocoa application, see the chapter “Using QCRenderer to Play a Composition” in Quartz Composer Programming Guide.
Mac OS X includes several different technologies for manipulating images. Although the NSImage
class provide a robust feature set that is sufficient for many developer’s uses, there may be specific times when you need to use other imaging technologies. Table 9-3 lists some of the other imaging technologies available and when you might use each one of them.
Image technology | Description |
---|---|
Quartz Images ( | Quartz images are immutable data types that you use to manipulate bitmap data in Quartz. Although |
Quartz Layers ( | Quartz layers are a mutable alternative to Quartz images. You can draw to layers much like you would draw to an |
Core Image ( | The Core Image framework is geared toward processing image data. You would use this technology to apply visual effects or filters to existing bitmap images. Because it is explicitly designed for manipulating bitmap images, you must convert your images to a |
Image I/O | The Image I/O framework is geared towards developers who need more direct control over reading and writing image data. You might use this framework to convert images from one format to another or you might use it to add metadata to an image created by your program. The features of Image I/O are available in Mac OS X v10.4 and later as part of the Application Services framework. |
Core Animation | While not explicitly an imaging technology, the Core Animation framework is a smart and efficient way to render images and other data inside a view. The framework provides a cached backing store that makes it possible to do animations with a minimal amount of redrawing. You might use this technology in place of |
© 2005, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-01-06)