LockFocus

Drawing Between the Lines

Mac OS X has a wealth of graphics frameworks. From the PDF-based Quartz to AppKit to the filter-based Core Image, there’s something for everybody. Unfortunately, these frameworks each do things a little differently, which can lead to trouble when getting them to work with each other. There are system-provided ways to convert between some of these different types, but not for others. I put together a few categories with methods to make it easier for these frameworks to all get along.

View LTConversions code

Geometry

One of the most common mis-matching issues developers run into is the different geometry types in Quartz and Cocoa. Quartz has CGRect, CGPoint and CGSize while Cocoa uses NSRect, NSPoint and NSSize. They have all of the same attributes but are still different.

Luckily this situation is much improved in Leopard with a whole host of conversion functions like NSRectFromCGRect(). Even better, in 64 bit Cocoa all of the NS* types are typedef‘ed as their CG* equivalents! This is a great improvement, and even if you’re not 64 bit only, you can define NS_BUILD_32_LIKE_64 to still use the 64 bit versions of the NS* structures.

Core Image, though, uses yet another representation of geometric values. The CIVector class is used for rectangles, points, sizes and even 3D points. LTConversions includes methods to convert Quartz and Cocoa geometric values to and from their CIVector equivalents.

Color Spaces

Color Spaces are used to specify how to interpret the values in a color. Quartz uses CGColorSpaceRef and Cocoa uses NSColorSpace. NSColorSpace is great for converting color spaces-it can convert to and from CMProfileRef (used by ColorSync) and from ICC profiles (.icc files created with ColorSync Utility). New in Leopard, it can also convert to and from CGColorSpaceRef. Core Image does not have its own color space object, so in Leopard NSColorSpace can convert between pretty much any color space format you might need.

Colors

For colors, there three very similar flavors. NSColor, CGColorRef and CIColor are pretty much the same idea, and with LTConversions you can easily convert between them. Note that it doesn’t handle pattern color conversion since they’re treated a little differently in Quartz and AppKit (and don’t really exist in Core Image).

Paths

The situation with paths is a little strange. Quartz’s CGPathRef actually has (a little) more functionality than AppKit’s NSBezierPath. CGPathRef has cubic and quadratic Bézier curves, while NSBezierPath only has cubic curves. It’s not a major omission, but it seems strange that NSBezierPath is missing this, making it not quite a perfect mirror of CGPathRef. LTConversions has a method to convert a NSBezierPath to a CGPathRef, but not the other way.

Images

There’s also a host of image types. CGImageRef and CIImage don’t share NSImage‘s concept of representations (which use the NSImageRep class), but otherwise they are very similar. LTConversions has methods for converting between these image types, but if you’re doing anything fancy with multiple image representations, you should probably do the conversion yourself.

Wrap Up

Leopard is required because of some of the new Color and Image conversions, and everything should work with (or without) Garbage Collection and in 64 bit. Leopard’s Core Animation doesn’t add any of its own new basic types, and generally uses those from Quartz (so using Core Animation together with Cocoa requires a lot of conversions). Of course, on a (purely hypothetical) platform that had Quartz but no AppKit or Core Image, most of these conversions would be unnecessary…