APIs for Supporting High Resolution
This chapter highlights the APIs you should use, and points out the older methods and functions you should no longer use. You’ll also find information on APIs added or modified to support high resolution. Please also see the appropriate reference documentation for each API mentioned in this chapter.
Converting Coordinates
There are very few, if any, situations for which you need to use device coordinates directly. You should be able to accomplish any task that relates to drawing geometry by using the APIs described in this section.
In all cases it is best to rely on using one of the APIs that support high resolution rather than trying to manage values yourself. Although multiplying by a scale factor (as shown below) might produce the desired result:
NSNumber *myValue = [[NSNumber alloc] initWithDouble:value.y * scaleFactor]; |
the preferred approach is to use a conversion method:
NSNumber *myValue = [[NSNumber alloc] |
initWithDouble:[self convertPointToBacking:value].y]; |
You might be tempted to use device coordinates if your app allows users to choose a screen resolution, such as for a game. However, keep in mind that with high resolution, users will be unaware of the pixel dimensions. You should refer to display dimensions only in points.
Converting to and from Views
To support high resolution, you might need to convert rectangles or points from the coordinate system of one NSView
instance to another (typically the superview or subview), or from one NSView
instance to the containing window. The NSView
class defines six methods that convert rectangles, points, and sizes in either direction.
Convert to the receiver from the specified view | Convert from the receiver to the specified view |
---|---|
The convert...:fromView:
methods convert values to the receiver’s coordinate system from the coordinate system of the view passed as the second parameter. If you pass nil
as the view, the values are assumed to be in the window coordinate system and are converted to the receiver coordinate system. The convert..:toView:
methods perform the inverse operation—converting values in the receiver coordinate system to the coordinate system of the view passed as a parameter. If the view
parameter is nil
, the values are converted to the coordinate system of the receiver’s window.
NSView
also defines the centerScanRect:
method, which converts a given rectangle to device coordinates, adjusts the rectangle to lie in the center of the area (pixels), and then converts the resulting rectangle back to the receiver’s coordinate system (points). Although this method works well for high resolution, some situations might require more precise control over the rounding behavior of the alignment operation on each edge of a rectangle. If you need a high level of control, consider using backingAlignedRect:options:
(see Aligning a Rectangle on Pixel Boundaries).
For more information about coordinate conversion in views, see:
Converting to and from Layers
The NSView
class provides methods for converting between a view’s local coordinate system and the interior coordinate system of the layer (for layer-backed views). Use these methods when you have custom layer trees and need to position the layers appropriately in the parent view.
The coordinate system of a layer that backs an NSView
object is not necessarily identical to its local view coordinate system. For example, Core Animation layers always use an unflipped coordinate system, whereas the NSView
class allows a given view class to choose whether or not it is flipped. For the case of a flipped NSView
object that is layer-backed, the following conversion methods account for this difference.
Convert to the view’s layer coordinate system | Convert from the view’s layer coordinate system |
---|---|
Converting to and from the Screen
The NSWindow
class provides these methods for converting between window local coordinates and screen global coordinates:
Use them instead of the deprecated convertBaseToScreen:
and convertScreenToBase:
methods.
Converting to and from the Backing Store
Views, windows, and screens each have their own backing coordinate system. In other words, backing store coordinates are relative to an object; they do not refer to absolute positions onscreen. By default, coordinate values increase up and to the right in coordinate system units.
The backing coordinate system is suitable for pixel alignment for that specific object. Always use the same object for round-tripping to and from the backing store.
Each of the following methods converts between the object’s local coordinate system and a pixel-aligned coordinate system that matches the characteristics of the backing store for that object. In the case of the NSScreen
class, the backing coordinate system is the native frame buffer of the display.
For more information on each method, see the appropriate reference documentation (NSView Class Reference, NSWindow Class Reference, NSScreen Class Reference.
Convert to backing store coordinates | Convert from backing store coordinates |
---|---|
|
|
Aligning a Rectangle on Pixel Boundaries
Achieving consistent pixel alignment for high resolution often requires more control over rounding behaviors than the NSView
class centerScanRect:
method offers. The NSView
, NSWindow
, and NSScreen
classes all provide a backingAlignedRect:options:
method.
The backingAlignedRect:options:
method accepts rectangles in local coordinates and ensures that the result is aligned on backing store pixel boundaries, subject to specific rounding hints given in the options
argument. Use NSAlignmentOptions
constants to specify how to treat each edge of the rectangle. You can push a rectangle’s width and height to the next inward, outward, or closest pixel boundary.
For example, this code:
NSRect rect = {0.3,0.3,10.0,10.0}; |
NSAlignmentOptions alignOpts = NSAlignMinXOutward | NSAlignMinYOutward | |
NSAlignWidthOutward | NSAlignMaxYOutward ; |
NSRect alignedRect = [self backingAlignedRect:rect options:alignOpts]; |
produces a rectangle with this origin and size:
{{0, 0}, {10, 11}} |
For a complete list of options, see NSAlignmentOptions
in Foundation Constants Reference.
Getting Scale Information
Objects in an app, such as custom layers, windows, and screens, might not have the same resolution. When you need to find out scaling information for an object, choose the API that’s appropriate for that object.
CALayer
The contentsScale
property of the CALayer
class defines the mapping between the coordinate space of the layer (measured in points) and the backing store (measured in pixels). You can change this value as needed to indicate to Core Animation that the bitmap of the backing layer needs to be bigger or smaller.
For example, to avoid blurry text for a layer that is magnified when composited to the screen, use the contentsScale
property to specify a text-layer bitmap at twice the layer size, with mipmaps enabled.
NSScreen
The backingScaleFactor
method of the NSScreen
class returns the scale factor that represents the number of backing store pixels that correspond to each linear unit in screen space on the NSScreen
object. You should not use this method except in the rare case when the explicit scale factor is needed. Instead, use the backing store conversion methods (see Converting to and from the Backing Store).
Note that the value returned by backingScaleFactor
does not represent anything concrete, such as pixel density or physical size, because it can vary based on the configured display mode. For example, the display might be in a mirrored configuration that is still scaled for high resolution, resulting in pixel geometry that might not match the native resolution of the display device.
NSWindow
The backingScaleFactor
method of the NSWindow
class returns the scale factor for a specific window. As with its NSScreen
counterpart, it is preferable that you use the backing store conversion methods.
CGContextRef
The preferred way to get the scaling information for a CGContext object is to call the conversion function CGContextConvertRectToDeviceSpace
:
deviceRect = CGContextConvertRectToDeviceSpace(context, userRect); |
Then you can divide deviceRect.size.height
by userRect.size.height
. This works for both implicitly scaled window contexts and explicitly scaled bitmap contexts.
An alternative is to get the transform applied to the CGContext object by calling the function CGContextGetUserSpaceToDeviceSpaceTransform
. The scaling information is in the a
and d
components of the returned transform. For example:
CGAffineTransform deviceTransform = |
CGContextGetUserSpaceToDeviceSpaceTransform(myContext); |
NSLog(@"x-scaling = %f y-scaling = %f", deviceTransform.a, deviceTransform.d); |
If you applied any additional scaling to the context, that will be reflected in the values. Note that this function reports a scale for the implicitly scaled window contexts, and it does not handle bitmap contexts because those are not implicitly scaled.
For simple conversions between user space and device space, you can also use one of the conversion functions listed below (for details, see CGContext Reference). However, they convert only global coordinates, so you need to perform additional calculations to translate the results to view-centric coordinates.
Drawing Images with NSImage and Core Image
When drawing images, the system needs to know about the source and destination resolution in order to apply the appropriate scaling. For that reason, you should use methods that provide information about the source rectangle.
When working with NSImage
objects, choose one of these methods, which allow you to specify a source rectangle. That method will then draw all or part of the image in the current coordinate system:
NSImage
drawing methods whose names do not begin with “draw” are deprecated (see Deprecated APIs).
When working with a Core Image context, use the method drawImage:inRect:fromRect:
and specify the exact bounds of the destination. If the you create the CIContext
object with a CGContextRef
, the inRect:
parameter is in points. If you create the CIContext
object with a CGLContext
object, the inRect:
parameter is in pixels. The fromRect:
parameter is always in pixel dimensions.
Do not use drawImage:atPoint:fromRect:
because this method is ambiguous as to the units of the dimensions, so it might not work as expected in a high-resolution environment.
Additions and Changes for OS X v10.7.4
Additions to AppKit
NSImage Class
The default behavior for NSImage
is to choose the smallest image representation that has at least as many pixels as the destination rectangle on both the horizontal and vertical axes. The default works well for most cases. If you find the default doesn’t work well for your app, use the matchesOnlyOnBestFittingAxis
property of the NSImage
class to adjust the image-choosing behavior.
-(BOOL)matchesOnlyOnBestFittingAxis
Controls how
NSImage
chooses an image representation for a destination rectangle. Returns the current setting. The default setting isNO
. When set toYES
,NSImage
chooses the smallest image representation that has at least as many pixels as the destination rectangle on either the horizontal or vertical axis.setMatchesOnlyOnBestFittingAxis:
Sets the property that controls how
NSImage
chooses an image representation for a destination rectangle.
Use the following to manage content and scale for custom Core Animation layers.
layerContentsForContentsScale:
Provides the contents for a layer at a given scale.
recommendedLayerContentsScale:
Provides the system with the optimal scaling to use for a layer.
NSView Class
For more details, see Handle Dynamic Changes in Window Resolution Only When You Must and Manage Core Animation Layer Contents and Scale.
NSLayerDelegateContentsScaleUpdating
This protocol defines an optional
CALayer
delegate method for handling resolution changes, allowing you to manage scale and contents for a layer hosted in a view.layer:shouldInheritContentsScale:fromWindow:
Invoked when a resolution changes occurs for the window that hosts the layer.
viewDidChangeBackingProperties
Is invoked when the view’s backing properties change. The default implementation does nothing. Your app can provide an implementation if it needs to swap assets when a view’s backing properties change.
NSWindow Class
For more details, see Handle Dynamic Changes in Window Resolution Only When You Must.
NSWindowDidChangeBackingPropertiesNotification
Is sent when a window’s backing properties change.
windowDidChangeBackingProperties:
Is invoked when the window’s backing properties change. The default implementation does nothing. Your app can provide an implementation if it needs to swap assets when a window’s backing properties change.
NSBackingPropertyOldColorSpaceKey
Indicates the color space of the window prior to the change in backing store.
NSBackingPropertyOldScaleFactorKey
Indicates the backing properties of the window prior to the change in backing store.
Additions to Carbon
HIWindowGetBackingScaleFactor
Replaces the
HIGetScaleFactor
function; see Getting Scale Factors.kHIWindowBitHighResolutionCapable
Represents the bit that sets the high-resolution-capable attribute.
kWindowHighResolutionCapableAttribute
Designates a window as being capable of supporting high-resolution content.
Additions and Changes for OS X v10.8
NSImage Class
Use this method for offscreen drawing. See Use the Block-Based Drawing Method for Offscreen Images.
+ (id)imageWithSize:(NSSize)size flipped:(BOOL)drawingHandlerShouldBeCalledWithFlippedContext drawingHandler:(BOOL (^)(NSRect dstRect))drawingHandler;
The drawing handler is a block that can be invoked whenever the image is drawn to, and on whatever thread the drawing occurs. You should make sure that any state you access within the block is done in a thread-safe manner.
The code in the block is the same code that you would use between the
lockFocus
andunlockFocus
methods.
Quartz Display Services
These functions return points (not pixels) as of OS X v10.8:
size_t CGDisplayModeGetWidth(CGDisplayModeRef mode);
Returns the width in points of the specified display mode.
size_t CGDisplayModeGetHeight(CGDisplayModeRef mode);
Returns the height in points of the specified display mode.
Deprecated APIs
If your code uses any of the methods or constants listed in these sections, you need to replace them to allow your app to support high resolution.
Converting to and from the Base Coordinate System
The following methods of the NSView
class are deprecated:
The following methods of the NSWindow
class are deprecated:
The appropriate replacement depends on the conversion you want to perform:
To convert between view and layer coordinates, use the appropriate
convertXXXToLayer:
method. See Converting to and from Layers.To convert to window coordinates, use the appropriate
convertXXXToView:
method, specifying anil
view. See Converting to and from Views.
Getting Scale Factors
These are not compatible with the high-resolution model in OS X:
Creating an Unscaled Window
The NSUnscaledWindowMask
constant of the NSWindow
class is deprecated. This mask currently does nothing. The scale factor for a window backing store is dynamic and is dependent on the screen on which the window is placed. If you currently use this mask to achieve pixel-precise rendering, you should replace it with the backing store conversion methods (see Converting to and from the Backing Store).
Drawing Images
The NSImage
class methods compositeToPoint:...
and dissolveToPoint:...
operate on the base coordinate system. The behavior of these methods is not compatible with high resolution in OS X because there is no way to specify the source rectangle.
Instead, you should use one of the methods that begin with draw
, such as:
These methods allow you to specify a source rectangle, and they draw all or part of the image in the current coordinate system.
Copyright © 2012 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2012-09-19