This chapter addresses some problems and questions you may have as you modify your application to take advantage of resolution independence.
Misplaced drawing almost certainly results from code that assumes that 1 Quartz point = 1 pixel. In a resolution-independent system, there is no guarantee that this is the case. See “Coordinate Conversion in Cocoa” or “Coordinate Conversion in Carbon.”
Pixel cracking typically occurs at nonintegral scale factors when tiling images to form a continuous background or fill. The cracks are caused when rounding errors cause points to be mapped to nonadjacent pixel boundaries. The image boundaries may overlap or contain anti-aliasing artifacts. Figure 4-1 illustrates the problem.
The solution is to make sure that your drawing aligns on pixel boundaries rather than relying on Quartz points. To adjust the position of an object to fall on exact pixel boundaries, you must do the following:
Convert the object's origin and size values from user space to device space coordinates.
Round each of the values to fall on exact pixel boundaries in device space.
Convert the values back to user space to obtain the coordinates required to achieve the desired pixel boundaries.
Carbon applications can use the function HIWindowGetScaleMode
to obtain the scale mode, HIRectConvert
to convert coordinates between user and device space, and CGRectIntegral
to manipulate the values in an HIRect
structure that contains the object’s bounds, as shown in Listing 4-1.
Listing 4-1 Aligning on pixel boundaries in Carbon
// myRect contains the bounds of an object that draws a portion of myView |
HIWindowScaleMode scaleMode; |
HIWindowGetScaleMode (window, &scaleMode, NULL); |
if (scaleMode == kHIWindowScaleModeFrameworkScaled) |
{ // window is framework scaled and scale factor is not 1.0 |
// convert coordinates to device space units |
HIRectConvert (&myRect, kHICoordSpaceView, myView, kHICoordSpaceScreenPixel, NULL); |
// outset the rectangle to integer boundaries |
myRect = CGRectIntegral(myRect); |
// convert back to user space |
HIRectConvert (&myRect, kHICoordSpaceScreenPixel, NULL, kHICoordSpaceView, myView); |
} |
Cocoa applications can align a rectangle on pixel boundaries using the convertRect:
method in the NSView
class, as shown in Listing 4-2.
Listing 4-2 Aligning on pixel boundaries in Cocoa
float scaleFactor = [[myView window] userSpaceScaleFactor]; |
if (scaleFactor != 1.0) |
{ |
// convert rect to pixel coordinates |
myRect = [myView convertRect:rect toView:nil]; |
// round the origin and size up to the nearest pixel boundary |
myRect.origin.x = ceilf(myRect.origin.x); |
myRect.origin.y = ceilf(myRect.origin.y); |
myRect.size.width = ceilf(myRect.size.width); |
myRect.size.height = ceilf(myRect.size.height); |
// convert rect back to user space |
myRect = [myView convertRect:myRect fromView:nil]; |
} |
Jaggies or banding result from poor scaling of bitmap images due to interpolation problems, as shown in Figure 4-2.
You can improve interpolation accuracy by adjusting the interpolation quality using the Quartz 2D function CGContextSetInterpolationQuality
or the Cocoa NSGraphicsContext
method setImageInterpolation:
. Higher quality interpolation can incur a performance overhead.
If your Cocoa application needs to scale any artwork, you should specify NSImageInterpolationHigh
when rendering.
If adjusting the interpolation quality does not work, you can supply additional artwork sizes (such as 1.25x and 1.5x) to allow more accurate interpolation.
If your application supports plug-ins, you may need to ensure that they are resolution independence–savvy. If you pass drawing coordinates between the plug-in and the application, you need to make sure that both sides agree on what type of coordinates they are, and who is responsible for scaling (if necessary).
If the plug-in uses QuickDraw to draw, you should update it to use Quartz, or (if you do not have access to the source), coordinate with the plug-in owner to make sure all drawing is properly scaled.
If your application uses Cocoa views or Carbon HIViews and does all of its drawing using Quartz, most scaling should work automatically.
Most standard controls have been available for several OS releases, so they should still work on earlier systems. If the standard control is not available for older systems, draw using the standard control in Mac OS X v10.5 and a custom control in Mac OS X v10.4 and earlier.
The Cocoa class NSImage
supports multi-image TIFF and PDF files in Mac OS X v10.3 and later.
Icon Services supports 256 x 256 and 512x 512 images in .icns
files back to Mac OS X v10.3, although v10.3 does not use the newer images. Mac OS X v10.2 cannot read the .icns
file at all if it contains the larger images, so the only workaround is to install a separate icon file containing only 128 x128 and smaller images.
You should test your application at the following scale factors: 1.0, 1.25, 1.5, 2.0, and 3.0.
Last updated: 2007-05-04