apple manual

68
High Resolution Guidelines for OS X

Upload: tommaso-scigliuzzo

Post on 16-Apr-2015

116 views

Category:

Documents


4 download

DESCRIPTION

As Title

TRANSCRIPT

Page 1: Apple manual

High ResolutionGuidelines for OS X

Page 2: Apple manual

Contents

About High Resolution for OS X 7At a Glance 8

Get Your App Ready for High Resolution 9Tune Advanced Technologies for High Resolution 9Make Sure Your App Works After Optimizing for High Resolution 9Understand the User Experience If You Don’t Optimize Right Away 9

See Also 9

High Resolution Explained: Features and Benefits 11Points Don’t Correspond to Pixels 11Resolution Can Change Dynamically 12OS X Provides Many Drawing Improvements Automatically 14Image Representations Are Ideal for High Resolution 14Floating-Point Glyph Advancements Result in Improved Text Layout 15OS X Optimizes the High-Resolution User Experience for Existing Apps 16

Framework-Scaled Mode Provides Automatic Scaling 17Magnified Mode Accommodates Apps That Aren’t Yet Ready for High Resolution 18An App’s High-Resolution Capability Is Available in the Info Window 19

Optimizing for High Resolution 21Provide High-Resolution Versions of All App Graphics Resources 21

Adopt the @2x Naming Convention 22Create a Set of Icons That Includes High-Resolution Versions 22Let Xcode Create an icns File Automatically 25Use iconutil to Create an icns File Manually 25Package Multiple Versions of Image Resources into One File 26Use QuickLook to Check Your Packaged Art 28

Load Images Using High-Resolution-Savvy Image-Loading Methods 28Use the Most Recent APIs That Support High Resolution 30

Replace Deprecated APIs 30Update Code That Relies on Old Technologies 30

Advanced Optimization Techniques 32Enable OpenGL for High-Resolution Drawing 32

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

2

Page 3: Apple manual

Set Up the Viewport to Support High Resolution 33Adjust Model and Texture Assets 34Check for Calls Defined in Pixel Dimensions 34Tune OpenGL Performance for High Resolution 34Use a Layer-Backed View to Overlay Text on OpenGL Content 35Use an Application Window for Fullscreen Operation 36Convert the Coordinate Space When Hit Testing 36

Manage Core Animation Layer Contents and Scale 36Layers with NSImage Contents Are Updated Automatically 38Layers with CGImage Contents Are Not Updated Automatically 38

Create and Render Bitmaps to Accommodate High Resolution 38Use the Block-Based Drawing Method for Offscreen Images 41Handle Dynamic Changes in Window Resolution Only When You Must 41Use NSReadPixel to Access Screen Pixels 43Adjust Font Settings to Ensure Document Compatibility 44Remember That Quartz Display Services Returns CGImage Objects Sized in Pixels 44Adjust Quartz Image Patterns to Accommodate High Resolution 45Use the Image I/O Framework for Runtime Packaging of Icons 48

APIs for Supporting High Resolution 50Converting Coordinates 50

Converting to and from Views 50Converting to and from Layers 51Converting to and from the Screen 52Converting to and from the Backing Store 52

Aligning a Rectangle on Pixel Boundaries 52Getting Scale Information 53

CALayer 53NSScreen 53NSWindow 54CGContextRef 54

Drawing Images with NSImage and Core Image 55Additions and Changes for OS X v10.7.4 55

Additions to AppKit 55Additions to Carbon 57

Additions and Changes for OS X v10.8 57NSImage Class 57Quartz Display Services 57

Deprecated APIs 58

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

3

Contents

Page 4: Apple manual

Converting to and from the Base Coordinate System 58Getting Scale Factors 58Creating an Unscaled Window 58Drawing Images 59

Testing and Troubleshooting High-Resolution Content 60Enable High-Resolution Options on a Standard-Resolution Display 60Make Sure @2x Images Load on High-Resolution Screens 62Troubleshooting 64

Controls and Other Window Elements Are Truncated or Show Up in Odd Places 64Images Don’t Look as Sharp as They Should 64OpenGL Drawing Looks Fuzzy 64Objects Are Misaligned 65

Glossary 66

Document Revision History 67

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

4

Contents

Page 5: Apple manual

Figures and Listings

About High Resolution for OS X 7Figure I-1 Drawing is sharper in high resolution 8

High Resolution Explained: Features and Benefits 11Figure 1-1 Objects appear the same size whether on standard resolution (left) or high resolution (right)

12Figure 1-2 A backing store changes dynamically as a window moves to another display 13Figure 1-3 Standard- and high-resolution variants of an image stored in a TIFF file, viewed in Preview 15Figure 1-4 Integral and fractional advancements compared 16Figure 1-5 OS X automatically magnifies graphics for standard-resolution apps 17Figure 1-6 The Principal class setting in Xcode 18Figure 1-7 The resolution option in the app’s Info window 19Figure 1-8 The key that indicates an app is ready for high resolution 20

Optimizing for High Resolution 21Figure 2-1 Customizing the level of detail for different icon sizes 24Figure 2-2 Setting the icns filename in Xcode 26Figure 2-3 Previewing icons in the QuickLook window 28Figure 2-4 @2x image (left) and a standard-resolution image (right) on a high-resolution display 29Listing 2-1 Loading an image into a view 29

Advanced Optimization Techniques 32Figure 3-1 Enabling high-resolution backing for an OpenGL view 33Figure 3-2 A text overlay scales automatically for standard resolution (left) and high resolution (right)

35Figure 3-3 Standard resolution (left) and an unscaled pattern in high resolution (right) 45Listing 3-1 Setting up the viewport for drawing 33Listing 3-2 Overriding viewDidChangeBackingProperties 37Listing 3-3 Setting up a bitmap to support high resolution 39Listing 3-4 Responding to changes in window backing properties 42Listing 3-5 A pixel-reading method 43Listing 3-6 Creating a pattern with an image using the NSColor class 45Listing 3-7 Creating a pattern with an image using Quartz 46

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

5

Page 6: Apple manual

Testing and Troubleshooting High-Resolution Content 60Figure 5-1 A standard-resolution image (left) and the same image tinted (right) 62Figure 5-2 Tinting highlights details that could be overlooked 63Figure 5-3 The tinting option in the Quartz Debug Tools menu 63

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

6

Figures and Listings

Page 7: Apple manual

Important: This is a preliminary document for an API or technology in development. Although this documenthas been reviewed for technical accuracy, it is not final. Apple is supplying this information to help youplan for the adoption of the technologies and programming interfaces described herein. This informationis subject to change, and software implemented according to this document should be tested with finaloperating system software and final documentation. Newer versions of this document may be providedwith future seeds of the API or technology.

High-resolution displays provide a rich visual experience, allowing users to see sharper text and more detailsin photos than on standard-resolution displays. The high-resolution model for OS X is based on Quartz.Introduced in OS X v10.0, Quartz allows developers to draw into an abstract coordinate space—userspace—without regard for the characteristics of the final drawing destination: printer, screen, bitmap, PDF.The OS X implementation of high resolution extends this flexible imaging model throughout the system, tothe level of the display.

When you run a high-resolution-savvy app on a high-resolution device, the text, vector drawing, and UI controlsare sharp. This is due to the increased pixel density—pixels are smaller and there are more of them per unitarea. Each point in user space is backed by four pixels. The increase in pixel density results in higher detailsfor drawing and text rendering. As shown in Figure I-1, a standard-resolution display has fewer pixels availableto approximate the shape of a curve, resulting in a jagged look when magnified. But a high-resolution display

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

7

About High Resolution for OS X

Page 8: Apple manual

has quadruple the pixels available to approximate the curve, resulting in a much smoother-looking curve.Magnified or not, when you look at the same shape on a standard-resolution display and a high-resolutionone, the difference is obvious immediately.

Figure I-1 Drawing is sharper in high resolution

At a GlanceThe guidelines in this document describe how to optimize your app for high resolution. At the core of mostguidelines in this document is that you should think in points most of the time, but understand the exceptionswhen you must be aware of pixels. You’ll need to free your code from relying on device coordinates, exceptin perhaps the most extreme edge cases. You’ll also need to increase the resolution of all the graphics resourcesyour app uses.

About High Resolution for OS XAt a Glance

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

8

Page 9: Apple manual

Get Your App Ready for High ResolutionOS X does much of the work required to handle the different resolutions, but there are some tasks you mustperform, such as providing specially named high-resolution images and updating icon assets. You’ll also needto update your code to use the most recent APIs, especially in cases where you are currently using deprecatedAPIs.

Relevant Chapters: “High Resolution Explained: Features and Benefits” (page 11), “Optimizing forHigh Resolution” (page 21), “APIs for Supporting High Resolution” (page 50)

Tune Advanced Technologies for High ResolutionIf your app uses pixel-based technologies (such as OpenGL, Quartz image patterns), needs low-level access todisplay information, must examine pixels directly, or supports other specialized tasks or technologies, you’llneed to perform some work to ensure your app works well in high resolution. At the very least, scan throughthe list of advanced techniques to see which ones, if any, apply to your app.

Relevant Chapter: “Advanced Optimization Techniques” (page 32)

Make Sure Your App Works After Optimizing for High ResolutionYou don’t need a high-resolution display to start optimizing your app and testing the code. Quartz Debug hasfeatures you can use to make sure your app is working as expected. When things don’t work as expected, thetroubleshooting section can help you figure out the issue.

Relevant Chapter: “Testing and Troubleshooting High-Resolution Content” (page 60)

Understand the User Experience If You Don’t Optimize Right AwayIf you aren’t able to update your app immediately for high resolution, it’s important to understand how userswill experience your app as they wait for you to release the optimized version.

Relevant Section: “OS X Optimizes the High-Resolution User Experience for Existing Apps” (page16)

See AlsoThese documents provide additional details for using many of the technologies referred to in this document:

About High Resolution for OS XSee Also

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

9

Page 10: Apple manual

● OS X Human Interface Guidelines provides advice on designing high-resolution artwork for app icons.

● Cocoa Drawing Guide provides important conceptual information for understanding drawing and imagehandling. It also contains numerous examples that show how to use AppKit drawing technologies.

About High Resolution for OS XSee Also

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

10

Page 11: Apple manual

The two defining characteristics of high resolution for OS X are high pixel density and the virtual screen. InOS X, there are four times as many pixels for a given area on a high-resolution display. An increase in pixeldensity means that drawing is more precise, resulting in sharper text, extremely detailed photos, and a moredefined user interface.

The virtual screen decouples the physical pixels drawn in device space from the user space your app draws to,so you don’t need to concern yourself with the characteristics of the display on which your app runs. Thesystem frameworks are optimized and updated to perform the work needed to map user space to device space.Most of the time, your app won’t need to be aware of whether it is drawing to a standard- or a high-resolutiondisplay, or whether the user drags a window from one resolution display to another.

The high-resolution implementation on OS X brings with it several features and benefits. Understanding thesewill help as you optimize your app.

Points Don’t Correspond to PixelsOS X refers to screen size in points, not pixels. A point is one unit in user space, prior to any transformationson the space. Because, on a high-resolution display, there are four onscreen pixels for each point, points canbe expressed as floating-point values. Values that are integers in standard resolution, such as mouse coordinates,are floating-point values on a high-resolution display, allowing for greater precision for such things as graphicsalignment.

Note: The term points has its origin in the print industry, which defines 72 points as to equal 1 inchin physical space. When used in reference to high resolution in OS X, points in user space do nothave any relation to measurements in the physical world.

Your app draws to a view using points in user space. The window server composites drawing operations to anoffscreen buffer called the backing store. When it comes time to display the contents of the backing storeonscreen, the window server scales the content appropriately, mapping points to onscreen pixels. The result

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

11

High Resolution Explained: Features and Benefits

Page 12: Apple manual

is that if you draw the same content on two similar devices, and only one of them has a high-resolution screen,the content appears to be about the same size on both devices, as shown in Figure 1-1. Size invariance is akey feature of high resolution.

Figure 1-1 Objects appear the same size whether on standard resolution (left) or high resolution (right)

In your own drawing code you will use points most of the time, but there are instances when you might needto know how points are mapped to pixels. For example, on a high-resolution screen, you might want to providemore detail in your content or adjust the position or size of content in subtle ways. For those cases, it is possibleto obtain the backing scale factor, which tells you the relationship between points and pixels for a particularobject (a view, window, or screen). The backing scale factor is not global—it is a property of the object (layer,view, window) and is influenced by the display on which it is placed. In all cases, this value will be either 1.0or 2.0, depending on the resolution of the underlying device. (For more information, see “Getting ScaleInformation” (page 53)). The fact that the backing scale factor is always a whole number is another key featureof high resolution.

Resolution Can Change DynamicallyOS X supports a dynamic environment that can include more than one display, of which one or both can bestandard or high resolution. Because of this, users can:

● Connect or disconnect a second display

● Close the lid of a laptop and use it with an external display

● Drag an app window from one display to another

High Resolution Explained: Features and BenefitsResolution Can Change Dynamically

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

12

Page 13: Apple manual

The backing store of a window is owned by the display on which the window is drawn. If a user drags thewindow from one display to another, the ownership of the backing store changes as soon as the destinationdisplay has more than 50% of the window’s content (as shown in Figure 1-2). When ownership changes, OS Xhandles as many of these dynamic changes as it can.

Figure 1-2 A backing store changes dynamically as a window moves to another display

Most of the time, OS X automates dynamic resolution changes, seamlessly switching content from standardto high resolution. There are some cases for which your app will need to take action when a change in resolutionoccurs (see “Handle Dynamic Changes in Window Resolution Only When You Must” (page 41)).

Tip: Avoid caching or making any size calculations for custom content that does not allow for on-the-fly resolutionchanges. If you must use caches, you’ll need to devise an invalidation strategy that supports resolution changes.

High Resolution Explained: Features and BenefitsResolution Can Change Dynamically

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

13

Page 14: Apple manual

OS X Provides Many Drawing Improvements AutomaticallyRegardless of the underlying screen’s resolution, the drawing technologies in OS X provide support for makingyour rendered content look good. For example:

● Standard AppKit views (text views, buttons, table views, and so on) automatically render correctly at anyresolution.

● Vector-based content (NSBezierPath, CGPathRef, PDF, and so on) automatically takes advantage ofany additional pixels to render sharper lines for shapes.

● Cocoa text automatically renders sharper at higher resolutions.

● AppKit supports the automatic loading of high-resolution variants of your images.

Most of your existing drawing code will work without modification because the window server automaticallyaccounts for the size of the backing store for a window graphics context. Any content you draw in thedrawRect: method will be at the appropriate resolution for the underlying device. However, any drawingcode that uses memory you create, such as Quartz bitmaps, will require you to manage the content.

For bitmapped images to appear sharp on a high-resolution display, you will need to create versions of yourimage resources that have twice the resolution as before. But after you provide those versions, AppKit willmanage loading the appropriate version for the resolution. For more information on updating your imageresources, see “Provide High-Resolution Versions of All App Graphics Resources” (page 21).

Image Representations Are Ideal for High ResolutionThe notion of image representation is important for high resolution. An image representation object(NSImageRep) represents an image at a specific user size and pixel density, using a specific color space, andin a specific data format. NSImage objects use image representations to manage image data. An NSImageobject can contain multiple image representation objects.

For file-based images, NSImage creates an image representation object for each separate image stored in afile. Although most image formats support only a single image, formats such as TIFF can store multiple images.To support high resolution, you can provide pairs of images—one standard resolution and the other highresolution—in the same file, as shown in Figure 1-3. When it comes time to display the image in your app,

High Resolution Explained: Features and BenefitsOS X Provides Many Drawing Improvements Automatically

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

14

Page 15: Apple manual

NSImage chooses the smallest image representation that has more pixels than the destination. For informationon how to package and load images, see “Package Multiple Versions of Image Resources into One File” (page26) and “Load Images Using High-Resolution-Savvy Image-Loading Methods” (page 28).

Figure 1-3 Standard- and high-resolution variants of an image stored in a TIFF file, viewed in Preview

Important: While NSImage objects support multiple representations, CGImage does not. A CGImageRefis limited to one image at one resolution. For that reason, NSImage is the class of choice for supportingimages on high-resolution displays.

Floating-Point Glyph Advancements Result in Improved Text LayoutUsing screen fonts (for font sizes 16 pt and smaller) optimizes text layout for a standard-resolution display. Forscreen font, text is laid out using integral glyph advancements. Because the higher pixel density on ahigh-resolution display allows for floating-point glyph advancements even at small font sizes, screen font isno longer required. Floating-point advancements result in more precise layout, as shown in Figure 1-4, and

High Resolution Explained: Features and BenefitsFloating-Point Glyph Advancements Result in Improved Text Layout

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

15

Page 16: Apple manual

allows for kerning and ligatures for smaller font sizes. If your app is document-based and supports text editingand layout, you should familiarize yourself with the default text settings. See “Adjust Font Settings to EnsureDocument Compatibility” (page 44).

Figure 1-4 Integral and fractional advancements compared

OS X Optimizes the High-Resolution User Experience for ExistingAppsHow well an existing app runs in high resolution depends on the frameworks and graphics resources it uses.An app whose code base has not yet been optimized for high-resolution graphics will either run inframework-scaled mode or magnified mode. Most Cocoa apps will run in framework-scaled mode; other appswill run in magnified mode. The difference between the modes is the size of the backing store. In magnifiedmode (shown in Figure 1-5), the backing store has one-fourth the number of pixels as a high-resolution display

High Resolution Explained: Features and BenefitsOS X Optimizes the High-Resolution User Experience for Existing Apps

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

16

Page 17: Apple manual

(half the width and height of the display). The system must magnify the contents of the backing store to fillthe display. In framework-scaled mode, the backing store has the same number of pixels as the display. Eachmode is explained in more detail in the sections that follow.

Figure 1-5 OS X automatically magnifies graphics for standard-resolution apps

Framework-Scaled Mode Provides Automatic ScalingMost existing Cocoa apps are scaled automatically. In framework-scaled mode, the application frameworkautomatically adjusts the drawing size to ensure sharp graphics whether the display is standard or highresolution. The size of the backing store adjusts to accommodate the actual number of pixels onscreen.Application frameworks draw all standard user interface elements—such as buttons, menus, and the windowtitle bar—to the correct size for the resolution.

When the framework detects that the controls need to be drawn on a high-resolution display, it adjusts thebacking store to accommodate scaling each dimension by 2x. Whether standard or high resolution, the usersees high-quality rendering of the controls. The controls appear the same size to the user regardless of thebacking store size, but on a high-resolution display, the controls look sharper due to the density of the backingpixels.

Any vector-based drawing performed by an app is scaled for high resolution and will look as sharp as thestandard user interface elements.

Bitmapped images are magnified for high-resolution display. Images will be the correct user size, but willappear slightly fuzzy due to the magnification. Apps need to provide high-resolution versions of images toget the best user experience.

High Resolution Explained: Features and BenefitsOS X Optimizes the High-Resolution User Experience for Existing Apps

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

17

Page 18: Apple manual

Tip: Make sure your Cocoa app has a Principal class setting. Figure 1-6 shows the setting as viewed in Xcode.

Figure 1-6 The Principal class setting in Xcode

Magnified Mode Accommodates Apps That Aren’t Yet Ready for High ResolutionIn magnified mode (as shown in Figure 1-5 (page 17)), the window backing store remains at 1x scaling. Thesystem scales the contents using nearest-neighbor interpolation to draw the content on a high-resolutiondisplay. The user interface is sized as you expect, with no additional detail, and might look slightly blurry as aresult.

All apps that are not Cocoa apps run in magnified mode. However, a Cocoa app can also run in magnifiedmode if:

● The user sets the option to open the app in low resolution (see Figure 1-7 (page 19)).

● The app is known to have significant issues when running in framework-scaled mode, so the system makesan exception and instead runs the app in magnified mode.

Because of the loss of detail, you should rely on magnified mode only until you make the necessary changesto support high-resolution graphics in your app.

High Resolution Explained: Features and BenefitsOS X Optimizes the High-Resolution User Experience for Existing Apps

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

18

Page 19: Apple manual

An App’s High-Resolution Capability Is Available in the Info WindowUsers can find out whether an app is running in low resolution by opening its Info window and looking at the“Open in Low Resolution” checkbox, as shown in Figure 1-7. Apps that aren’t Cocoa apps have this checkboxselected and unavailable (dimmed). Most Cocoa apps have this checkbox available, but not selected. A usercan choose to run a Cocoa app in magnified mode if the app has usability issues related to high resolution.

Figure 1-7 The resolution option in the app’s Info window

High Resolution Explained: Features and BenefitsOS X Optimizes the High-Resolution User Experience for Existing Apps

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

19

Page 20: Apple manual

Some Cocoa apps that are not fully optimized for high resolution might have the checkbox selected andavailable by default. These apps will run in magnified mode unless the user overrides the default setting. Usersmight want to override the default if the issues related to high resolution are tolerable.

If the “Open in Low Resolution” checkbox is selected by default for your app—whether the checkbox is available(dimmed) or not—you can change the default by:

● Fixing all bugs related to high resolution

● Setting the NSHighResolutionCapable attribute to YES, in the Info.plist for the app, as shown in Figure1-8.

Figure 1-8 The key that indicates an app is ready for high resolution

When users update to the revised version of your app, they will be able to enjoy the high-resolution version.

If your app is optimized for high resolution, you can request that the “Open in Low Resolution” checkbox isnot displayed by adding the NSHighResolutionMagnifyAllowed key to the Info.plist for your app. Then,set the key’s value to NO (Boolean value). A value of YES (the default) means that checkbox should be shownas usual.

High Resolution Explained: Features and BenefitsOS X Optimizes the High-Resolution User Experience for Existing Apps

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

20

Page 21: Apple manual

After you optimize your app for high resolution, users will enjoy its detailed drawings and sharp text. Anddepending on how you’ve designed and coded your app, you might not have that much optimization toperform. If your app is a Cocoa app and uses only the standard controls, doesn’t require custom graphicsresources, and doesn’t use pixel-based APIs, your work is over. OS X handles the scaling for you.

If your app is like many apps, however, you probably need to perform some work to ensure your users willhave a great visual experience. At a minimum, you will need to provide high-resolution versions of customartwork, including the app icon. If your app uses a lot of graphics resources, creating these assets could requirea significant amount of designer time.

You’ll also need to make sure your code uses the correct image-loading methods and other APIs that supporthigh resolution.

The tasks listed in the following sections outline the work that most apps need to perform:

● “Provide High-Resolution Versions of All App Graphics Resources” (page 21)

● “Load Images Using High-Resolution-Savvy Image-Loading Methods” (page 28)

● “Use the Most Recent APIs That Support High Resolution” (page 30)

After you complete this work, look at “Advanced Optimization Techniques” (page 32) to see if your app requiresfurther adjustments for special scenarios, such as using pixel-based technologies (OpenGL, Quartz bitmaps)or custom Core Animation layers.

Provide High-Resolution Versions of All App Graphics ResourcesYour app’s icons, custom controls, custom cursors, custom artwork, and any images you want to display needto have high-resolution versions in addition to their standard-resolution versions. Each version needs to bescaled so that it displays in the same point size. For example, if you supply a standard-resolution image sizedat 50x50 pixels, the high-resolution version must be sized at 100x100 pixels. You can check for correct scalingusing the tiffutil command (see “Run the TIFF Utility Command in Terminal” (page 27)).

In some cases, scaling custom content does not result in the same perceptual effect that the content has atstandard resolution. Shadows or outlines might look too heavy, or some graphics might require more detailadded to them. For example, on a high-resolution display, using an NSBezierPath object to draw a line with

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

21

Optimizing for High Resolution

Page 22: Apple manual

a width of 1.0 point would result in a line that is 2 pixels wide. If the 2-pixels-wide line looks too heavy, consideradjusting the graphic to show a 1-pixel-wide line, regardless of whether it appears on a standard- or ahigh-resolution display. You might need to experiment to ensure the perceptual effect is equivalent acrossresolutions.

Adopt the @2x Naming ConventionWhen you create a high-resolution version of an image, follow this naming convention for the image pair:

● Standard: <ImageName>.<filename_extension>

Example: circle.png

● High resolution: <ImageName>@2x.<filename_extension>

Example: [email protected]

The <ImageName> and <filename_extension> portions specify the name and extension for the file. Theinclusion of the @2x modifier for the high-resolution image lets the system know that the image is thehigh-resolution variant of the standard image. The two component images should be in the same folder inthe app’s sources. Ideally, package the image pairs into one file (see “Package Multiple Versions of ImageResources into One File” (page 26)).

Create a Set of Icons That Includes High-Resolution VersionsYou should create a set of icons that consist of pairs of icons (standard and high resolution) for each iconsize—16x16, 32x32, 128x128, 256x256, 512x512. The naming convention is:

icon_<sizeinpoints>x<sizeinpoints>[@<scale>].png

where <sizeinpoints> is the size of the icon in points, and <scale> is @2x for the high-resolution version.(Don’t add a scale for standard resolution.) Additionally, the filename must use the icon_ prefix.

The images must be square and have the dimensions that match the name of the file.

Ideally, you would supply a complete set of icons. However, it is not a requirement to have a complete set; thesystem will choose the best representation for sizes and resolutions that you don’t supply. Each icon in the setis a hint to the system as to the best representation to use. A complete set consists of the following:

icon_16x16.png

[email protected]

icon_32x32.png

[email protected]

Optimizing for High ResolutionProvide High-Resolution Versions of All App Graphics Resources

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

22

Page 23: Apple manual

icon_128x128.png

[email protected]

icon_256x256.png

[email protected]

icon_512x512.png

[email protected]

Note: There is no longer a 1024x1024 size. That’s replaced by 512x512@2x.

You might be wondering whether some of these icons are redundant. But, from a perceptual standpoint, a16x16@2x version isn’t equivalent to a 32x32 version. Although they might have the same number of pixels,the user size is different. You might need to make adjustments to achieve the optimal look for an icon at aparticular user size and pixel density.

The set needs to be put into a folder whose name is <folder name>.iconset, where <folder name> iswhatever name you’d like. The folder must have the .iconset extension. It might seem a little unusual for afolder to have an extension, but this extension is a signal to the system that the folder contains a set of icons.

Tip: If you have an existing icns file but have misplaced the sources, you can use the “Export to Icon Set”

command in Icon Composer to retrieve the source icons.

For new icons, it’s easiest to design the large icons first and then decide how to scale them down. When scalingup existing icons, the enlarged versions should look like close-ups of the existing icons, with the appropriatelevel of detail. For example, a house icon could show shingles or shutters in the larger sizes, while a large book

Optimizing for High ResolutionProvide High-Resolution Versions of All App Graphics Resources

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

23

Page 24: Apple manual

icon might actually contain readable text. Do not simply create a pixel-for-pixel upscaled version of the existingicon. Figure 2-1 shows the changes in detail for different icon sizes. The larger icon has much more detail; youcan see the bolts holding the mail slot on the door.

Figure 2-1 Customizing the level of detail for different icon sizes

Optimizing for High ResolutionProvide High-Resolution Versions of All App Graphics Resources

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

24

Page 25: Apple manual

For detailed information on designing icons, see OS X Human Interface Guidelines .

Let Xcode Create an icns File AutomaticallyXcode 4.4 automatically validates and converts an iconset folder to an icns file. All you need to do is add theiconset folder to your project and build the project. The generated icns file is added automatically to the builtproduct.

Use iconutil to Create an icns File ManuallyThe iconutil command-line tool converts iconset folders to deployment-ready, high-resolution icns files.(You can find complete documentation for this tool by entering man iconutil in Terminal.) Using this toolalso compresses the resulting icns file, so there is no need for you to perform additional compression.

Note: Don’t use Icon Composer—it can’t create high-resolution icns files.

To convert a set of icons to an icns file

● Enter this command into the Terminal window:

iconutil -c icns <iconset filename>

where <iconset filename> is the path to the folder containing the set of icons you want to convertto icns.

The output is written to the same location as the iconset file, unless you specify an output file asshown:

iconutil -c icns -o <icon filename> <iconset filename>

To convert an icns file to an iconset

● Enter this command into the Terminal window:

iconutil -c iconset <icns filename>

where <icns filename> is the path to the icns file you want to convert to an iconset.

The output is written to the same location as the icns file, unless you specify an output file as shown:

Optimizing for High ResolutionProvide High-Resolution Versions of All App Graphics Resources

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

25

Page 26: Apple manual

iconutil -c iconset -o <iconset filename> <icns filename>

Note: Toolbar graphics are not icons. Don’t use iconutil to package them. Instead, use tiffutil(see “Package Multiple Versions of Image Resources into One File” (page 26)). For information onmanaging toolbar items, see “Toolbar Management Checklist” in Toolbar Programming Topics for Cocoa .For design tips, see “Designing Toolbar Icons” in OS X Human Interface Guidelines .

After creating the icns file, enter the filename in Xcode for the Icon file key located in Custom OS X ApplicationTarget Properties.

Figure 2-2 Setting the icns filename in Xcode

Package Multiple Versions of Image Resources into One FileThere are two options for packaging standard- and high-resolution versions of app image resources. You can:

● Set up Xcode to combine high-resolution artwork into one file.

● Use the tiffutil command-line tool.

Set Up Xcode to Combine ArtThe easiest way to package art is to let Xcode perform the work for you.

To set up Xcode to combine high-resolution artwork into one file

1. Open the Target Build Settings.

Optimizing for High ResolutionProvide High-Resolution Versions of All App Graphics Resources

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

26

Page 27: Apple manual

2. Under Deployment, set the option Combine High Resolution Artwork to Yes.

Run the TIFF Utility Command in TerminalYou can use the man command tiffutil with the option -cathidpicheck. The command lets youmanipulate TIFF files using the specified options. The -cathidpdicheck option writes a single output filecontaining the files supplied as arguments to the option. This option also checks to make sure that the standard-and high-resolution files you supply are sized correctly. That is, the dimensions of the high-resolution imagemust be twice that of the standard-resolution image. Running tiffutil explicitly changes the dpi. Usingtiffutil also compresses the resulting output file, so there is no need for you to perform additionalcompression.

Running the following command creates a single file from the two input files:

tiffutil -cathidpicheck infile1 infile2 -out outfile

For example, if the input files are:

myimage.png with width = 32 pixels, height = 32 pixels

[email protected] with width = 64 pixels, height = 64 pixels

running this command:

tiffutil -cathidpicheck myimage.png [email protected] -out myimage.tiff

will produce a single TIFF file that contains the two input images.

See the tiffutilman pages documentation in Terminal for more information, including options for extractingan image from a multirepresentation TIFF file.

Optimizing for High ResolutionProvide High-Resolution Versions of All App Graphics Resources

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

27

Page 28: Apple manual

Use QuickLook to Check Your Packaged ArtYou can check an iconset or multirepresentation TIFF file by choosing its icon in the Finder and pressing theSpace bar. As shown in Figure 2-3, the QuickLook window that appears has a slider that allows you to lookthrough each image contained in the file.

Figure 2-3 Previewing icons in the QuickLook window

Load Images Using High-Resolution-Savvy Image-Loading MethodsAn NSImage object can contain multiple representations of an image, making it ideal for supportinghigh-resolution graphics. You can use NSImage to load standard- and high-resolution versions of an image,but you can also use it to load multiple representations from a single TIFF file. (For details on creating TIFF filesfor multiple representations, see “Package Multiple Versions of Image Resources into One File” (page 26).)

Optimizing for High ResolutionLoad Images Using High-Resolution-Savvy Image-Loading Methods

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

28

Page 29: Apple manual

If you follow the naming convention described in “Adopt the @2x Naming Convention” (page 22), there aretwo methods available that will load standard- and high-resolution versions of an image into an NSImageobject, even if you don’t provide a multirepresentation image file.

● The imageNamed: method of the NSImage class finds resources located in the main application bundle,but not in frameworks or plug-ins.

● The imageForResource: method of the NSBundle class will also look for resources outside the mainbundle. Framework authors should use this method.

If you do not provide a high-resolution version of a given image, the NSImage object loads only thestandard-resolution image and scales it during drawing. Figure 2-4 shows a comparison of an image on ahigh-resolution display when an @2x version is available and when it is not. Note that the @2x version hasmuch more detail.

Figure 2-4 @2x image (left) and a standard-resolution image (right) on a high-resolution display

When you draw the image, the NSImage object automatically chooses the best representation for the drawingdestination. For images with the @2x suffix in the filename, it calculates the user size to be half the width andheight of the pixels, which renders the image correctly.

Listing 2-1 shows how to use imageNamed: to load an image into a view. The system displays the correctimage for the resolution, provided a pair of images—myPhoto.png and [email protected]—are available.Keep in mind that the @2x version must have dimensions that are twice the size as its standard-resolutioncounterpart.

Listing 2-1 Loading an image into a view

- (id)initWithFrame:(NSRect)frame

{

self = [super initWithFrame:frame];

if (self) {

Optimizing for High ResolutionLoad Images Using High-Resolution-Savvy Image-Loading Methods

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

29

Page 30: Apple manual

[self setImage:[NSImage imageNamed:@"myPhoto"]];

}

return self;

}

Here are a few additional tips for working with high-resolution images:

● If your app uses an NSImageView object for both an image and a highlight image, or to animate severalimages, it’s advisable that all images in the view have the same resolution.

● If you want to create an NSImage object from a CGImageRef data type, use the initWithCGImage:size:method, specifying the image size in points, not pixels. For the image to be sharp on a high-resolutiondisplay, make sure that the pixel height and pixel width of the image are twice that of the image heightand width in points.

● For custom cursors, you can pass a multirepresentation TIFF to the NSCursor class methodinitWithImage:hotSpot:.

● If your app tiles or stretches images to fill a space, you should use the NSDrawThreePartImage functionor the NSDrawNinePartImage function instead of using imageNamed:. AppKit treats the parts as agroup, matching the parts appropriately and handling pixel cracks. These methods are more performantthan stretching an image.

Use the Most Recent APIs That Support High ResolutionCocoa apps must replace deprecated APIs with their newer counterparts. Apps that use older Carbontechnologies need to replace those technologies with newer ones.

Replace Deprecated APIsA number of methods that support high resolution are available for converting geometry, detecting scaling,and aligning pixels (see “APIs for Supporting High Resolution” (page 50)). These more recent methods supportthe Quartz-based, high-resolution imaging model. Earlier APIs do not and are deprecated; these APIs are listedin “Deprecated APIs” (page 58), which also provides advice as to what to use in their place.

Update Code That Relies on Old TechnologiesCheck to make sure that your app—or any code it calls into, such as a plug-in—does not use any of thefollowing:

Optimizing for High ResolutionUse the Most Recent APIs That Support High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

30

Page 31: Apple manual

● QuickDraw or any API, such as the NSMovieView class, that calls into QuickDraw

● QuickTime Movie Toolbox—instead, use AVFoundation (if you can’t migrate to AVFoundation, use theQTKit framework)

● The Display Manager

● Carbon windows that are not composited

If your app uses any of these, the system will magnify your app when it runs on a high-resolution device,regardless of whether you provide @2x image resources. For details on this user experience, see “MagnifiedMode Accommodates Apps That Aren’t Yet Ready for High Resolution” (page 18).

Optimizing for High ResolutionUse the Most Recent APIs That Support High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

31

Page 32: Apple manual

This chapter provides guidance for specialized tasks that not every app performs. If your app uses OpenGL,creates Quartz bitmaps, accesses screen pixels, or performs a handful of other less common tasks, you mightneed to follow the optimization advice in some of these sections.

Enable OpenGL for High-Resolution DrawingOpenGL is a pixel-based API. The NSOpenGLView class does not provide high-resolution surfaces by default.Because adding more pixels to renderbuffers has performance implications, you must explicitly opt in to supporthigh-resolution screens.

You can opt in to high resolution by calling the method setWantsBestResolutionOpenGLSurface:whenyou initialize the view, and supplying YES as an argument:

[self setWantsBestResolutionOpenGLSurface:YES];

If you don’t opt in, the system magnifies the rendered results.

The wantsBestResolutionOpenGLSurface property is relevant only for views to which anNSOpenGLContext object is bound. Its value does not affect the behavior of other views. For compatibility,wantsBestResolutionOpenGLSurface defaults to NO, providing a 1-pixel-per-point framebuffer regardlessof the backing scale factor for the display the view occupies. Setting this property to YES for a given viewcauses AppKit to allocate a higher-resolution framebuffer when appropriate for the backing scale factor andtarget display.

To function correctly with wantsBestResolutionOpenGLSurface set to YES, a view must perform correctconversions between view units (points) and pixel units as needed. For example, the common practice ofpassing the width and height of [self bounds] to glViewport()will yield incorrect results at high resolution,because the parameters passed to the glViewport() function must be in pixels. As a result, you’ll get onlypartial instead of complete coverage of the render surface. Instead, use the backing store bounds:

[self convertRectToBacking:[self bounds]];

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

32

Advanced Optimization Techniques

Page 33: Apple manual

You can also opt in to high resolution by enabling the Supports Hi-Res Backing setting for the OpenGL viewin Xcode, as shown in Figure 3-1.

Figure 3-1 Enabling high-resolution backing for an OpenGL view

Set Up the Viewport to Support High ResolutionThe viewport dimensions are in pixels relative to the OpenGL surface. Pass the width and height to glViewPortand use 0,0 for the x and y offsets. Listing 3-1 shows how to get the view dimensions in pixels and take thebacking store size into account.

Listing 3-1 Setting up the viewport for drawing

- (void)drawRect:(NSRect)rect // NSOpenGLView subclass

{

// Get view dimensions in pixels

NSRect backingBounds = [self convertRectToBacking:[self bounds]];

GLsizei backingPixelWidth = (GLsizei)(backingBounds.size.width),

backingPixelHeight = (GLsizei)(backingBounds.size.height);

// Set viewport

glViewport(0, 0, backingPixelWidth, backingPixelHeight);

// draw…

}

You don’t need to perform rendering in pixels, but you do need to be aware of the coordinate system youwant to render in. For example, if you want to render in points, this code will work:

glOrtho(NSWidth(bounds), NSHeight(bounds),...)

Advanced Optimization TechniquesEnable OpenGL for High-Resolution Drawing

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

33

Page 34: Apple manual

Adjust Model and Texture AssetsIf you opt in to high-resolution drawing, you also need to adjust the model and texture assets of your app. Forexample, when running on a high-resolution display, you might want to choose larger models and moredetailed textures to take advantage of the increased number of pixels. Conversely, on a standard-resolutiondisplay, you can continue to use smaller models and textures.

If you create and cache textures when you initialize your app, you might want to consider a strategy thataccommodates changing the texture based on the resolution of the display.

Check for Calls Defined in Pixel DimensionsThese functions use pixel dimensions:

● glViewport (GLint x, GLint y, GLsizei width, GLsizei height)

● glScissor (GLint x, GLint y, GLsizei width, GLsizei height)

● glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, ...)

● glLineWidth (GLfloat width)

● glRenderbufferStorage (..., GLsizei width, GLsizei height)

● glTexImage2D (..., GLsizei width, GLsizei height, ...)

Tune OpenGL Performance for High ResolutionPerformance is an important factor when determining whether to support high-resolution content. Thequadrupling of pixels that occurs when you opt in to high resolution requires more work by the fragmentprocessor. If your app performs many per-fragment calculations, the increase in pixels might reduce its framerate. If your app runs significantly slower at high resolution, consider the following options:

● Optimize fragment shader performance. (See “Tuning Your OpenGL Application” in OpenGL ProgrammingGuide for Mac .)

● Choose a simpler algorithm to implement in your fragment shader. This reduces the quality of eachindividual pixel to allow for rendering the overall image at a higher resolution.

● Use a fractional scale factor between 1.0 and 2.0. A scale factor of 1.5 provides better quality than a scalefactor of 1.0, but it needs to fill fewer pixels than an image scaled to 2.0.

● Multisampling antialiasing can be costly with marginal benefit at high resolution. If you are using it, youmight want to reconsider.

The best solution depends on the needs of your OpenGL app; you should test more than one of these optionsand choose the approach that provides the best balance between performance and image quality.

Advanced Optimization TechniquesEnable OpenGL for High-Resolution Drawing

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

34

Page 35: Apple manual

Use a Layer-Backed View to Overlay Text on OpenGL ContentWhen you draw standard controls and Cocoa text to a layer-backed view, the system handles scaling thecontents of that layer for you. You need to perform only a few steps to set and use the layer. Compare thecontrols and text in standard and high resolutions, as shown in Figure 3-2. The text looks the same on bothwithout any additional work on your part.

Figure 3-2 A text overlay scales automatically for standard resolution (left) and high resolution (right)

To set up a layer-backed view for OpenGL content

1. Set the wantsLayer property of your NSOpenGLView subclass to YES.

Enabling the wantsLayer property of an NSOpenGLView object activates layer-backed rendering ofthe OpenGL view. Drawing a layer-backed OpenGL view proceeds mostly normally through the view’sdrawRect:method. The layer-backed rendering mode uses its own NSOpenGLContext object, whichis distinct from the NSOpenGLContext that the view uses for drawing in non-layer-backed mode.

AppKit automatically creates this context and assigns it to the view by invoking thesetOpenGLContext: method. The view’s openGLContext accessor will return the layer-backedOpenGL context (rather than the non-layer-backed context) while the view is operating in layer-backedmode.

2. Create the layer content either as a XIB file or programmatically.

The controls shown in Figure 3-2 were created in a XIB file by subclassing NSBox and using static textwith a variety of standard controls. Using this approach allows the NSBox subclass to ignore mouseevents while still allowing the user to interact with the OpenGL content.

3. Add the layer to the OpenGL view by calling the addSublayer: method.

Advanced Optimization TechniquesEnable OpenGL for High-Resolution Drawing

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

35

Page 36: Apple manual

Use an Application Window for Fullscreen OperationFor the best user experience, if you want your app to run full screen, create a window that covers the entirescreen. This approach offers two advantages:

● The system provides optimized context performance.

● Users will be able to see critical system dialogs above your content.

You should avoid changing the display mode of the system.

Convert the Coordinate Space When Hit TestingAlways convert window event coordinates when performing hit testing in OpenGL. The locationInWindowmethod of the NSEvent class returns the receiver’s location in the base coordinate system of the window. Youthen need to call the convertPoint:fromView: method to get the local coordinates for the OpenGL view(see “Converting to and from Views” (page 50)).

NSPoint aPoint = [theEvent locationInWindow];

NSPoint localPoint = [myOpenGLView convertPoint:aPoint fromView:nil];

Manage Core Animation Layer Contents and ScaleViews (NSView) and layers (CALayer) can be integrated in two ways—through layer backing or layer hosting.When you configure a layer-backed view by invoking setWantsLayer: with a value of YES, the view classautomatically creates a backing layer. The view caches any drawing it performs to the backing layer. When itcomes to high resolution, layer-backed views are scaled automatically by the system. You don’t have any workto do to get content that looks great on high-resolution displays.

Layers hosted by views are different. A layer-hosting view is a view that contains a Core Animation layer thatyou intend to manipulate directly. You create a layer-hosting view by instantiating a Core Animation layer classand supplying that layer to the view’s setLayer: method. Then, invoke setWantsLayer: with a value ofYES.

When using a layer-hosting view you should not rely on the view for drawing, nor should you add subviewsto the layer-hosting view. The root layer (the layer set using setLayer:) should be treated as the root layerof the layer tree, and you should only use Core Animation drawing and animation methods. You still use theview for handling mouse and keyboard events, but any resulting drawing must be handled by Core Animation.

Because layers hosted by views are custom CALayer objects, you are responsible for:

Advanced Optimization TechniquesManage Core Animation Layer Contents and Scale

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

36

Page 37: Apple manual

● Setting the initial contents property of the layer

● Keeping the value of the contentsScale property updated

● Providing high-resolution content

To make updating the layers that you manage easier, implementlayer:shouldInheritContentsScale:fromWindow:. This CALayer delegate method allows you tomanage scale and contents for a hosted layer whose content is not an NSImage object (you don’t need tomanage NSImage contents). For additional details, see NSLayerDelegateContentsScaleUpdating ProtocolReference .

When a resolution change occurs for a given window, the system traverses the layer trees in that window todecide what action, if any, to take for each layer. The system will query the layer’s delegate to determinewhether to change the layer’s contentsScale property to the new scale (either 2.0 or 1.0).

If the delegate returns YES, it should make any corresponding changes to the layer’s properties, as requiredby the resolution change. For example, a layer whose contents contain a CGImage object needs to determinewhether an alternate CGImage object is available for the new scale factor. If the delegate finds a suitableCGImage object, then in addition to returning YES, it should set the appropriate CGImage object as the layer’snew contents.

For layers that do not have a delegate, your app must either:

● Set a suitable delegate that can handle the resolution change (the recommended approach).

● Provide a means of updating the layers as needed when a resolution change notification is posted (if youprefer this approach, see “Handle Dynamic Changes in Window Resolution Only When You Must” (page41)).

The Core Animation compositing engine looks at each layer’s contentsScale property to determine whetherits contents need to be scaled during compositing. If your app creates layers without an associated view, thecontentsScale property of each new layer object is initially set to 1.0. If you subsequently draw the layer ona high-resolution display, the layer’s contents are magnified automatically, which results in a loss of detail.However, you can set the value of the layer’s contentsScale property appropriately and providehigh-resolution content, as shown in Listing 3-2.

Listing 3-2 Overriding viewDidChangeBackingProperties

- (void)viewDidChangeBackingProperties

{

[super viewDidChangeBackingProperties];

[[self layer] setContentsScale:[[self window] backingScaleFactor]];

Advanced Optimization TechniquesManage Core Animation Layer Contents and Scale

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

37

Page 38: Apple manual

// Your code to provide content

}

Layers with NSImage Contents Are Updated AutomaticallyWhen you set an NSImage object as the contents of a layer, the system automatically chooses the imagerepresentation most appropriate for the screen on which the layer resides. There are two situations for whichyou’ll need to override the automatic choice:

● The layer has additional scaling due to layer bounds changes or transforms.

● The contentsGravity property is not one of the following: kCAContentsGravityResize,kCAContentsGravityResizeAspect, or kCAContentsGravityResizeFill.

This property is set to the value kCAGravityResize by default, which scales the layer content to fill thelayer bounds, without regard to the natural aspect ratio. Changing the gravity to a nonresizing optioneliminates the automatic scaling that would otherwise occur.

For either of these cases, use these methods of the NSImage class to manage the content and scaling of thelayer:

● recommendedLayerContentsScale: provides the system with the optimal scaling for a layer

● layerContentsForContentsScale: provides the contents for a layer at a given size

Layers with CGImage Contents Are Not Updated AutomaticallyOS X doesn’t handle dynamic changes for standalone layers that have CGImage contents because it doesn’thave knowledge of how layer contents were provided. As such, the system is not able to substituteresolution-appropriate alternatives, even if they are available. Your app must manage these layers and modifythe layer properties as appropriate for changes between resolutions. The same is true for any standalone layersthat you add to a layer-backed view tree. Unless you use NSImage objects as layer contents, your app mustupdate the layer properties and contents when needed.

Create and Render Bitmaps to Accommodate High ResolutionBitmap contexts are always sized using pixels, not points. When you create a bitmap context, you need tomanually determine the right scale based on the destination to which the bitmap will be drawn, and create alarger buffer when appropriate. Any existing bitmap caches (glyph caches, bitmap-based art caches—possiblyincluding caches of rasterized PDF content—or similar) might need separate caches for each resolution. Because

Advanced Optimization TechniquesCreate and Render Bitmaps to Accommodate High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

38

Page 39: Apple manual

the need for a particular resolution can come and go dynamically, the resolutions supported by the cachesshould be dynamic. In other words, don’t assume your cache needs to be only 1x (or needs to be only 2x)based on its first use, because a subsequent use could need a cache entry for a different resolution. For example,a user could drag a window from a standard- to high-resolution display (or vice versa) in a multiple-displaysystem (see “Resolution Can Change Dynamically” (page 12)). You’ll want to maintain a consistent userexperience if that happens.

Listing 3-3 shows how to use AppKit to create a bitmap that’s scaled to accommodate the device’s resolution.There are many other ways to create bitmaps in Cocoa. For more information, see “Creating a Bitmap” in CocoaDrawing Guide .

Tip: Using NSBitmapImageRep and NSGraphicsContext for offscreen rendering automatically scales

bitmaps appropriately, whereas the CGBitmapContextCreate function does not.

Regardless of how you choose to create a bitmap, there are two critical items illustrated in Listing 3-3 that youmust make sure you include in your own code.

● Set the width (pixelsWide) and height (pixelsHigh) of the bitmap for the number of pixels you need.Don’t make the mistake of basing the pixel count on the view (or other object) bounds because the view’sdimensions are specified in points.

● Set the user size of the bitmap, which is its width and height in points. The user size communicates thedpi, which you need to correctly size the bitmap to support high resolution.

Listing 3-3 Setting up a bitmap to support high resolution

- (id)myDrawToBitmapOfWidth:(NSInteger)width

andHeight:(NSInteger)height

withScale:(CGFloat)scale

{

NSBitmapImageRep *bmpImageRep = [[NSBitmapImageRep alloc]

initWithBitmapDataPlanes:NULL

pixelsWide:width * scale

pixelsHigh:height * scale

bitsPerSample:8

samplesPerPixel:4

hasAlpha:YES

isPlanar:NO

colorSpaceName:NSCalibratedRGBColorSpace

bitmapFormat:NSAlphaFirstBitmapFormat

Advanced Optimization TechniquesCreate and Render Bitmaps to Accommodate High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

39

Page 40: Apple manual

bytesPerRow:0

bitsPerPixel:0

];

// There isn't a colorspace name constant for sRGB so retag

// using the sRGBColorSpace method

bmpImageRep = [bmpImageRep bitmapImageRepByRetaggingWithColorSpace:

[NSColorSpace sRGBColorSpace]];

// Setting the user size communicates the dpi

[bmpImageRep setSize:NSMakeSize(width, height)];

// Create a bitmap context

NSGraphicsContext *bitmapContext =

[NSGraphicsContext graphicsContextWithBitmapImageRep:bmpImageRep];

// Save the current context

[NSGraphicsContext saveGraphicsState];

// Switch contexts for drawing to the bitmap

[NSGraphicsContext setCurrentContext:

[NSGraphicsContext graphicsContextWithBitmapImageRep:bmpImageRep]];

// *** Your drawing code here ***

[NSGraphicsContext restoreGraphicsState];

// Send back the image rep to the requestor

return bmpImageRep;

}

- (void)drawRect:(NSRect)dirtyRect

{

// Bounds are in points

NSRect bounds = [self bounds];

// Figure out the scale of pixels to points

CGFloat scale = [self convertSizeToBacking:CGSizeMake(1,1)].width;

// Supply the user size (points)

NSBitmapImageRep *myImageRep = [self myDrawToBitmapOfWidth:bounds.size.width

andHeight:bounds.size.height

Advanced Optimization TechniquesCreate and Render Bitmaps to Accommodate High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

40

Page 41: Apple manual

withScale:scale];

// Draw the bitmap image to the view bounds

[myImageRep drawInRect:bounds];

}

Use the Block-Based Drawing Method for Offscreen ImagesIf your app uses the lockFocus and unlockFocus methods of the NSImage class for offscreen drawing,consider using the method imageWithSize:flipped:drawingHandler: instead (available in OS X v10.8).If you use the lock focus methods for drawing, you can get unexpected results—either you’ll get a low resolutionNSImage object that looks incorrect when drawn, or you’ll get a 2x image that has more pixels in its bitmapthan you are expecting.

Using the imageWithSize:flipped:drawingHandler: method ensures you’ll get correct results understandard and high resolution. The drawing handler is a block that can be invoked whenever the image is drawnto, and on whatever thread the drawing occurs. You should make sure that any state you access within theblock is done in a thread-safe manner.

The code in the block should be the same code that you would use between the lockFocus and unlockFocusmethods.

Handle Dynamic Changes in Window Resolution Only When YouMustListening for NSWindowDidChangeBackingPropertiesNotification is something only a fewapps—primarily those apps that specialize in video or graphics work, and for which color matching andhigh-quality rendering fidelity are especially important—will need to do.

If your app must handle resolution changes manually, it should respond to the notificationNSWindowDidChangeBackingPropertiesNotification when the backing store resolution of a givenNSWindow object changes. If the window has a delegate that responds to thewindowDidChangeBackingProperties: message, its delegate will receive the notification through thatmethod.

Your app receives NSWindowDidChangeBackingPropertiesNotificationwhenever a resolution or colorspace change occurs. To determine which of the two changed (or both could change), use these keys:

● NSBackingPropertyOldScaleFactorKey, which is an NSNumber object

Advanced Optimization TechniquesUse the Block-Based Drawing Method for Offscreen Images

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

41

Page 42: Apple manual

● NSBackingPropertyOldColorSpaceKey, which is an NSColorSpace object

Listing 3-4 shows how to use the keys to obtain backing scale and color space information from the notification.In response to changes in resolution or color space, your implementation ofwindowDidChangeBackingProperties: will need to load or generate bitmapped image resourcesappropriate to the characteristics of the new window. You might also need to purge the old counterparts ifthey are no longer needed.

Listing 3-4 Responding to changes in window backing properties

- (void)windowDidChangeBackingProperties:(NSNotification *)notification {

NSWindow *theWindow = (NSWindow *)[notification object];

NSLog(@"windowDidChangeBackingProperties: window=%@", theWindow);

CGFloat newBackingScaleFactor = [theWindow backingScaleFactor];

CGFloat oldBackingScaleFactor = [[[notification userInfo]

objectForKey:@"NSBackingPropertyOldScaleFactorKey"]

doubleValue];

if (newBackingScaleFactor != oldBackingScaleFactor) {

NSLog(@"\tThe backing scale factor changed from %.1f -> %.1f",

oldBackingScaleFactor, newBackingScaleFactor);

}

NSColorSpace *newColorSpace = [theWindow colorSpace];

NSColorSpace *oldColorSpace = [[notification userInfo]

objectForKey:@"NSBackingPropertyOldColorSpaceKey"];

if (![newColorSpace isEqual:oldColorSpace]) {

NSLog(@"\tThe color space changed from %@ -> %@", oldColorSpace,newColorSpace);

}

}

Advanced Optimization TechniquesHandle Dynamic Changes in Window Resolution Only When You Must

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

42

Page 43: Apple manual

Note: If your code currently relies on the notificationNSWindowDidChangeScreenProfileNotification to receive color profile changes, it shouldinstead use NSWindowDidChangeBackingPropertiesNotification for that purpose.

Use NSReadPixel to Access Screen PixelsMost of the time you shouldn’t need to access pixels, but if your app performs tasks such as finding out thecolor of a pixel that the user is pointing to, you should use the NSReadPixel function.

To examine a pixel directly

1. Get the event that contains the pixel that the user is pointing to.

The location value will be in points relative to the view or window that has focus.

2. Call a conversion method to get the location of the pixel.

3. Lock focus on the view.

4. Use NSReadPixel to get the pixel.

5. Unlock focus on the view.

6. Get the color component values.

Listing 3-5 shows a complete sample pixel-reading method. For additional details, see “Drawing Outside of

drawRect:” in View Programming Guide .

Listing 3-5 A pixel-reading method

- (void) examinePixelColor:(NSEvent *) theEvent

{

NSPoint where;

NSColor *pixelColor;

CGFloat red, green, blue;

where = [self convertPoint:[theEvent locationInWindow] fromView:nil];

// NSReadPixel pulls data out of the current focused graphics context,

// so you must first call lockFocus.

[self lockFocus];

pixelColor = NSReadPixel(where);

// Always balance lockFocus with unlockFocus.

Advanced Optimization TechniquesUse NSReadPixel to Access Screen Pixels

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

43

Page 44: Apple manual

[self unlockFocus];

red = [pixelColor redComponent];

green = [pixelColor greenComponent];

blue = [pixelColor blueComponent];

// Your code to do something with the color values

}

Adjust Font Settings to Ensure Document CompatibilityIn OS X v10.8, the default value of the NSFontDefaultScreenFontSubstitutionEnabled setting is NO.This setting determines whether or not text APIs (such as NSLayoutManager, NSCell, and theNSStringDrawing categories on NSString and NSAttributedString) substitute screen fonts whencalculating layout and display of text.

Although screen font substitution will no longer be the default, using screen font might still be appropriateto support:

● Compatibility with documents created with previous versions of your app. The difference in glyphadvancement measurements between integral and floating-point values can cause a change in text layout.

● Fixed-pitch plain text style output—for example, the Plain Text mode in Text Edit.

To keep the OS X v10.7 screen font substitution behavior as the default, set the NSUserDefaults keyNSFontDefaultScreenFontSubstitutionEnabled to YES.

To maintain the screen font setting on a per-document basis, specifyNSUsesScreenFontsDocumentAttribute as a document attribute when you initialize an attributed stringobject.

Remember That Quartz Display Services Returns CGImage ObjectsSized in PixelsCGImage objects are always sized in pixels; they do not contain any metadata concerning the drawing size inpoints. So if you access the screen pixels to create an image using the functions CGDisplayCreateImage orCGDisplayCreateImageForRect, you’ll need to know whether the display is running in standard- orhigh-resolution mode to properly interpret what the pixel size means. If the display is running in high-resolutionmode, the images will have a 2x backing store.

Advanced Optimization TechniquesAdjust Font Settings to Ensure Document Compatibility

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

44

Page 45: Apple manual

Adjust Quartz Image Patterns to Accommodate High ResolutionIf you use the NSColor class to draw an image as a pattern, OS X automatically scales the image patternappropriately for the resolution of the device. If you use Quartz to draw an image pattern, you will need toadjust your code so the pattern draws correctly for high resolution. Quartz patterns (CGPatternRef) offercontrol over all aspects of pattern creation such as pattern cell size and spacing between patterns. If you don’tneed that level of control, consider using NSColor instead. Not only does the system take care of choosingthe correctly sized image for you (as long as you supply standard- and high-resolution versions), but the codeis much simpler. Compare the code in Listing 3-6 (page 45) with that in Listing 3-7 (page 46). Each createsthe pattern as shown on the left side of Listing 3-7 (page 46).

Listing 3-6 Creating a pattern with an image using the NSColor class

NSColor *myPattern = [NSColor colorWithPatternImage:[NSImage imageNamed:@"heart"]];

[myPattern setFill];

NSRectFill(myRect);

Quartz patterns are drawn in base space, which means the automatic scaling performed by the frameworkswhen drawing into a window or view is not applied to them. So when you use the CGPatternRef API tocreate a pattern using an image, you need to account for the resolution of the window into which you drawthe pattern, in addition to providing standard- and high-resolution versions of the image. If you don’t scalethe image pattern for high resolution, your pattern will occupy one-fourth of the space it should (as shown inFigure 3-3), which is incorrect.

Figure 3-3 Standard resolution (left) and an unscaled pattern in high resolution (right)

Listing 3-7 shows how to create an image pattern so that it draws correctly for high resolution. The drawRect:method passes the scale to the pattern-drawing function. That function applies the scale prior to drawing thepattern. Also note that the image-drawing callback uses the imageNamed: method to load the appropriateversion of the image.

Advanced Optimization TechniquesAdjust Quartz Image Patterns to Accommodate High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

45

Page 46: Apple manual

Listing 3-7 Creating a pattern with an image using Quartz

@implementation PatternView

#define PATTERN_CELL_WIDTH 32

#define PATTERN_CELL_HEIGHT 32

- (id)initWithFrame:(NSRect)frame

{

self = [super initWithFrame:frame];

if (self) {

// Initialization code here.

}

return self;

}

void MyDrawImage (void *info,CGContextRef myContext)

{

// Provide two versions of the image—standard and @2x

NSImage *myImage = [NSImage imageNamed:@"heart_32"];

[myImage drawAtPoint:NSMakePoint(0.0,0.0)

fromRect:NSMakeRect(0.0,0.0, PATTERN_CELL_WIDTH, PATTERN_CELL_HEIGHT)

operation:NSCompositeSourceOver

fraction:1.0];

}

void MyDrawPatternWithImage (CGContextRef myContext, CGRect rect, CGFloat scale)

{

CGPatternRef pattern;

CGColorSpaceRef patternSpace;

CGFloat alpha = 1.0;

static const CGPatternCallbacks callbacks = {0, &MyDrawImage, NULL};

Advanced Optimization TechniquesAdjust Quartz Image Patterns to Accommodate High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

46

Page 47: Apple manual

patternSpace = CGColorSpaceCreatePattern (NULL);

CGContextSetFillColorSpace (myContext, patternSpace);

CGColorSpaceRelease (patternSpace);

pattern = CGPatternCreate (NULL,

CGRectMake (0, 0, PATTERN_CELL_WIDTH,

PATTERN_CELL_HEIGHT),

CGAffineTransformMake (1/scale, 0, 0,

1/scale, 0, 0),

PATTERN_CELL_WIDTH,

PATTERN_CELL_HEIGHT,

kCGPatternTilingConstantSpacingMinimalDistortion,

true,

&callbacks);

CGContextSetFillPattern (myContext, pattern, &alpha);

CGPatternRelease (pattern);

CGContextFillRect (myContext, rect);

}

- (void)drawRect:(NSRect)dirtyRect

{

NSGraphicsContext *nsctx = [NSGraphicsContext currentContext];

CGContextRef cgctx = (CGContextRef)[nsctx graphicsPort];

NSRect bounds = [self bounds];

NSRect backingBounds = [self convertRectToBacking:bounds];

CGFloat scale = backingBounds.size.width/bounds.size.width;

// Draw the pattern into the view bounds

MyDrawPatternWithImage(cgctx, bounds, scale);

}

@end

Advanced Optimization TechniquesAdjust Quartz Image Patterns to Accommodate High Resolution

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

47

Page 48: Apple manual

Use the Image I/O Framework for Runtime Packaging of IconsIf your app supports editing or creating icon images, you might need to package icons programmatically usingthe Image I/O framework. Otherwise, you should follow the simple procedures outlined in “ProvideHigh-Resolution Versions of All App Graphics Resources” (page 21) for packaging icons.

To programmatically package a set of icons into one source

1. Create a set of images that represent each size of the resource, supplying standard and @2x resolutionsfor each.

2. Create an image destination that is large enough to accommodate the number of images in the array:

CGImageDestinationRef destination =

CGImageDestinationCreateWithURL(myURL, kUTTypeAppleICNS,

myNumberOfImages, NULL);

where myURL is the URL to write the data to.

3. Create a dictionary for each image and add key-value pairs for the image dpi height and width.

The image dpi should reflect the resolution. That is, the high-resolution version should have twice thedpi as the standard-resolution version.

NSDictionary* properties = [NSDictionary dictionaryWithObjectsAndKeys:

[NSNumber numberWithUnsignedInteger:imageDPI],

kCGImagePropertyDPIHeight,

[NSNumber numberWithUnsignedInteger:imageDPI],

kCGImagePropertyDPIWidth,

nil];

4. Add each image and its property dictionary to the image destination.

CGImageDestinationAddImage(destination,

oneOfMyImages, (CFDictionaryRef)properties);

5. Finalize the image destination.

You will not be able to add any more data to the destination after performing this step.

Advanced Optimization TechniquesUse the Image I/O Framework for Runtime Packaging of Icons

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

48

Page 49: Apple manual

BOOL success = CGImageDestinationFinalize(destination);

To retrieve the underlying representations from a file that contains multiple versions of an image resource,use the Image I/O framework to create an image source. Then, iterate through the image source using thefunction CGImageSourceCreateImageAtIndex to retrieve each image. For details, see CGImageSourceReference and Image I/O Programming Guide .

After extracting an individual image, you can draw it using one of the methods of the NSImage class.

Advanced Optimization TechniquesUse the Image I/O Framework for Runtime Packaging of Icons

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

49

Page 50: Apple manual

This chapter highlights the APIs you should use, and points out the older methods and functions you shouldno longer use. You’ll also find information on APIs added or modified to support high resolution. Please alsosee the appropriate reference documentation for each API mentioned in this chapter.

Converting CoordinatesThere are very few, if any, situations for which you need to use device coordinates directly. You should be ableto 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 managevalues 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, suchas 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 ViewsTo support high resolution, you might need to convert rectangles or points from the coordinate system of oneNSView instance to another (typically the superview or subview), or from one NSView instance to the containingwindow. The NSView class defines six methods that convert rectangles, points, and sizes in either direction.

Convert from the receiver to the specified viewConvert to the receiver from the specified view

convertPoint:toView:convertPoint: fromView:

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

50

APIs for Supporting High Resolution

Page 51: Apple manual

Convert from the receiver to the specified viewConvert to the receiver from the specified view

convertRect:toView:convertRect: fromView:

convertSize:toView:convertSize: fromView:

The convert...:fromView:methods convert values to the receiver’s coordinate system from the coordinatesystem of the view passed as the second parameter. If you pass nil as the view, the values are assumed to bein the window coordinate system and are converted to the receiver coordinate system. Theconvert..:toView: methods perform the inverse operation—converting values in the receiver coordinatesystem to the coordinate system of the view passed as a parameter. If the view parameter is nil, the valuesare 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 tothe receiver’s coordinate system (points). Although this method works well for high resolution, some situationsmight require more precise control over the rounding behavior of the alignment operation on each edge ofa rectangle. If you need a high level of control, consider using backingAlignedRect:options: (see “Aligninga Rectangle on Pixel Boundaries” (page 52)).

For more information about coordinate conversion in views, see:

● “Working with the View Hierarchy” in View Programming Guide

● “Coordinate Systems and Transforms” in Cocoa Drawing Guide

Converting to and from LayersThe NSView class provides methods for converting between a view’s local coordinate system and the interiorcoordinate system of the layer (for layer-backed views). Use these methods when you have custom layer treesand 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 viewcoordinate system. For example, Core Animation layers always use an unflipped coordinate system, whereasthe NSView class allows a given view class to choose whether or not it is flipped. For the case of a flippedNSView object that is layer-backed, the following conversion methods account for this difference.

Convert from the view’s layer coordinate systemConvert to the view’s layer coordinate system

convertPointFromLayer:convertPointToLayer:

convertSizeFromLayer:convertSizeToLayer:

convertRectFromLayer:convertRectToLayer:

APIs for Supporting High ResolutionConverting Coordinates

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

51

Page 52: Apple manual

Converting to and from the ScreenThe NSWindow class provides these methods for converting between window local coordinates and screenglobal coordinates:

● convertRectToScreen:

● convertRectFromScreen:

Use them instead of the deprecated convertBaseToScreen: and convertScreenToBase: methods.

Converting to and from the Backing StoreViews, windows, and screens each have their own backing coordinate system. In other words, backing storecoordinates are relative to an object; they do not refer to absolute positions onscreen. By default, coordinatevalues 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 sameobject 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-alignedcoordinate system that matches the characteristics of the backing store for that object. In the case of theNSScreen 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 from backing store coordinatesConvert to backing store coordinates

convertPointFromBacking: (NSView)convertPointToBacking: (NSView)

convertSizeFromBacking: (NSView)convertSizeToBacking: (NSView)

convertRectFromBacking: (NSView)

convertRectFromBacking: (NSWindow)

convertRectFromBacking: (NSScreen)

convertRectToBacking: (NSView)

convertRectToBacking: (NSWindow)

convertRectToBacking: (NSScreen)

Aligning a Rectangle on Pixel BoundariesAchieving consistent pixel alignment for high resolution often requires more control over rounding behaviorsthan the NSView class centerScanRect: method offers. The NSView, NSWindow, and NSScreen classes allprovide a backingAlignedRect:options: method.

APIs for Supporting High ResolutionAligning a Rectangle on Pixel Boundaries

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

52

Page 53: Apple manual

The backingAlignedRect:options: method accepts rectangles in local coordinates and ensures that theresult is aligned on backing store pixel boundaries, subject to specific rounding hints given in the optionsargument. Use NSAlignmentOptions constants to specify how to treat each edge of the rectangle. You canpush a rectangle’s width and height 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 InformationObjects in an app, such as custom layers, windows, and screens, might not have the same resolution. Whenyou need to find out scaling information for an object, choose the API that’s appropriate for that object.

CALayerThe contentsScale property of the CALayer class defines the mapping between the coordinate space ofthe layer (measured in points) and the backing store (measured in pixels). You can change this value as neededto 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 thecontentsScale property to specify a text-layer bitmap at twice the layer size, with mipmaps enabled.

NSScreenThe backingScaleFactormethod of the NSScreen class returns the scale factor that represents the numberof backing store pixels that correspond to each linear unit in screen space on the NSScreen object. You shouldnot use this method except in the rare case when the explicit scale factor is needed. Instead, use the backingstore conversion methods (see “Converting to and from the Backing Store” (page 52)).

APIs for Supporting High ResolutionGetting Scale Information

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

53

Page 54: Apple manual

Note that the value returned by backingScaleFactor does not represent anything concrete, such as pixeldensity or physical size, because it can vary based on the configured display mode. For example, the displaymight be in a mirrored configuration that is still scaled for high resolution, resulting in pixel geometry thatmight not match the native resolution of the display device.

NSWindowThe backingScaleFactor method of the NSWindow class returns the scale factor for a specific window. Aswith its NSScreen counterpart, it is preferable that you use the backing store conversion methods.

CGContextRefThe preferred way to get the scaling information for a CGContext object is to call the conversion functionCGContextConvertRectToDeviceSpace:

deviceRect = CGContextConvertRectToDeviceSpace(context, userRect);

Then you can divide deviceRect.size.height by userRect.size.height. This works for both implicitlyscaled window contexts and explicitly scaled bitmap contexts.

An alternative is to get the transform applied to the CGContext object by calling the functionCGContextGetUserSpaceToDeviceSpaceTransform. The scaling information is in the a and d componentsof 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 functionreports a scale for the implicitly scaled window contexts, and it does not handle bitmap contexts becausethose are not implicitly scaled.

For simple conversions between user space and device space, you can also use one of the conversion functionslisted below (for details, see CGContext Reference ). However, they convert only global coordinates, so you needto perform additional calculations to translate the results to view-centric coordinates.

● CGContextConvertPointToDeviceSpace and CGContextConvertPointToUserSpace

● CGContextConvertSizeToDeviceSpacee and CGContextConvertSizeToUserSpace

● CGContextConvertRectToDeviceSpace and CGContextConvertRectToUserSpace

APIs for Supporting High ResolutionGetting Scale Information

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

54

Page 55: Apple manual

Drawing Images with NSImage and Core ImageWhen drawing images, the system needs to know about the source and destination resolution in order toapply the appropriate scaling. For that reason, you should use methods that provide information about thesource rectangle.

When working with NSImage objects, choose one of these methods, which allow you to specify a sourcerectangle. That method will then draw all or part of the image in the current coordinate system:

● drawAtPoint:fromRect:operation:fraction:

● drawInRect:fromRect:operation:fraction:

● drawInRect:fromRect:operation:fraction:respectFlipped:hints:

NSImagedrawing methods whose names do not begin with “draw” are deprecated (see “Deprecated APIs” (page58)).

When working with a Core Image context, use the method drawImage:inRect:fromRect: and specify theexact 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: parameteris 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 thedimensions, 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 ClassThe default behavior for NSImage is to choose the smallest image representation that has at least as manypixels as the destination rectangle on both the horizontal and vertical axes. The default works well for mostcases. If you find the default doesn’t work well for your app, use the matchesOnlyOnBestFittingAxisproperty of the NSImage class to adjust the image-choosing behavior.

-(BOOL)matchesOnlyOnBestFittingAxisControls how NSImage chooses an image representation for a destination rectangle. Returns the currentsetting. The default setting is NO. When set to YES, NSImage chooses the smallest image representationthat has at least as many pixels as the destination rectangle on either the horizontal or vertical axis.

APIs for Supporting High ResolutionDrawing Images with NSImage and Core Image

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

55

Page 56: Apple manual

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 ClassFor more details, see “Handle Dynamic Changes in Window Resolution Only When You Must” (page 41) and“Manage Core Animation Layer Contents and Scale” (page 36).

NSLayerDelegateContentsScaleUpdatingThis protocol defines an optional CALayer delegate method for handling resolution changes, allowingyou 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.

viewDidChangeBackingPropertiesIs invoked when the view’s backing properties change. The default implementation does nothing. Yourapp can provide an implementation if it needs to swap assets when a view’s backing properties change.

NSWindow ClassFor more details, see “Handle Dynamic Changes in Window Resolution Only When You Must” (page 41).

NSWindowDidChangeBackingPropertiesNotificationIs 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 propertieschange.

NSBackingPropertyOldColorSpaceKeyIndicates the color space of the window prior to the change in backing store.

NSBackingPropertyOldScaleFactorKeyIndicates the backing properties of the window prior to the change in backing store.

APIs for Supporting High ResolutionAdditions and Changes for OS X v10.7.4

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

56

Page 57: Apple manual

Additions to Carbon

HIWindowGetBackingScaleFactorReplaces the HIGetScaleFactor function; see “Getting Scale Factors” (page 58).

kHIWindowBitHighResolutionCapableRepresents the bit that sets the high-resolution-capable attribute.

kWindowHighResolutionCapableAttributeDesignates a window as being capable of supporting high-resolution content.

Additions and Changes for OS X v10.8

NSImage ClassUse this method for offscreen drawing. See “Use the Block-Based Drawing Method for Offscreen Images” (page41).

+ (id)imageWithSize:(NSSize)sizeflipped:(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 whateverthread the drawing occurs. You should make sure that any state you access within the block is done ina thread-safe manner.

The code in the block is the same code that you would use between the lockFocus and unlockFocusmethods.

Quartz Display ServicesThese 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.

APIs for Supporting High ResolutionAdditions and Changes for OS X v10.8

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

57

Page 58: Apple manual

Deprecated APIsIf your code uses any of the methods or constants listed in these sections, you need to replace them to allowyour app to support high resolution.

Converting to and from the Base Coordinate SystemThe following methods of the NSView class are deprecated:

● convertPointToBase: and convertPointFromBase:

● convertSizeToBase: and convertSizeFromBase:

● convertRectToBase: and convertRectFromBase:

The following methods of the NSWindow class are deprecated:

● convertBaseToScreen: and convertScreenToBase:

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” (page 51).

● To convert to window coordinates, use the appropriate convertXXXToView: method, specifying a nilview. See “Converting to and from Views” (page 50).

Getting Scale FactorsThese are not compatible with the high-resolution model in OS X:

● The userSpaceScaleFactor methods of the NSScreen and NSWindow classes

● The HIGetScaleFactor function; use HIWindowGetBackingScaleFactor instead

Creating an Unscaled WindowThe 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 windowis placed. If you currently use this mask to achieve pixel-precise rendering, you should replace it with thebacking store conversion methods (see “Converting to and from the Backing Store” (page 52)).

APIs for Supporting High ResolutionDeprecated APIs

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

58

Page 59: Apple manual

Drawing ImagesThe NSImage class methods compositeToPoint:... and dissolveToPoint:... operate on the basecoordinate system. The behavior of these methods is not compatible with high resolution in OS X becausethere is no way to specify the source rectangle.

Instead, you should use one of the methods that begin with draw, such as:

● drawAtPoint:fromRect:operation:fraction:

● drawInRect:fromRect:operation:fraction:

● drawInRect:fromRect:operation:fraction:respectFlipped:hints:

These methods allow you to specify a source rectangle, and they draw all or part of the image in the currentcoordinate system.

APIs for Supporting High ResolutionDeprecated APIs

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

59

Page 60: Apple manual

As you update an app for a high-resolution environment, you’ll need to test it to ensure you get the expectedresults. Although you’ll want to test the app on high-resolution hardware prior to releasing it, you can emulatea high-resolution display on a standard-resolution display as an intermediate step.

Enable High-Resolution Options on a Standard-Resolution DisplayBefore you can set the high-resolution options in Quartz Debug, you first need to download it (if you don'talready have a copy).

To download Quartz Debug

1. Open Xcode.

2. Choose Xcode > Open Developer Tool > More Developer Tools...

Choosing this item will take you to developer.apple.com.

3. Sign in to developer.apple.com.

You should then see the Downloads for Apple Developers webpage.

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

60

Testing and Troubleshooting High-ResolutionContent

Page 61: Apple manual

4. Download the Graphics Tools for Xcode package, which contains Quartz Debug.

To enable high-resolution display modes

1. Launch Quartz Debug.

2. Choose UI Resolution from the Window menu.

3. Select “Enable HiDPI display modes”.

4. Log out and then log in to have the change take effect.

This updates the Resolutions list in System Preferences.

5. Open System Preferences > Displays, and choose a resolution that is marked as HiDPI.

Testing and Troubleshooting High-Resolution ContentEnable High-Resolution Options on a Standard-Resolution Display

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

61

Page 62: Apple manual

Make Sure @2x Images Load on High-Resolution ScreensBefore releasing your app you’ll want to make sure that @2x images load as expected. Users can configure asystem with multiple displays such that one display is high resolution and another is standard resolution. Notonly must your app be prepared to run on systems with different screen resolutions, but you need to ensurethat your app’s windows work as expected when dragged from one display to another. When a window movesfrom a standard- to a high-resolution display, the window’s content should update to show the appropriatelyscaled image.

One way to check whether an image is loading correctly in high resolution is to tint it. You can do this by usingthe image-tinting option in Quartz Debug. After you turn on image tinting any @2x image that is not correctlysized for high resolution will appear tinted (as shown in the image on the right in Figure 5-1).

Figure 5-1 A standard-resolution image (left) and the same image tinted (right)

Testing and Troubleshooting High-Resolution ContentMake Sure @2x Images Load on High-Resolution Screens

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

62

Page 63: Apple manual

Tinting is especially useful for finding graphics resources that might have been overlooked during your upscalingwork, as shown in Figure 5-2. Note that the curved ends of the scroll control are tinted, which shows thesedetails still need to be upscaled.

Figure 5-2 Tinting highlights details that could be overlooked

The easiest way to turn on the image-tinting option is from the Tools menu in Quartz Debug v4.2.

Figure 5-3 The tinting option in the Quartz Debug Tools menu

You can also access the feature from the command line using Terminal.

Testing and Troubleshooting High-Resolution ContentMake Sure @2x Images Load on High-Resolution Screens

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

63

Page 64: Apple manual

To turn on the tinting option for all apps for a given user (that is, global domain)

● Enter the following:

defaults write -g CGContextHighlight2xScaledImages YES

To restrict tinting to a particular app

● Replace -g with that app’s bundle identifier (for example, com.mycompany.myapp):

defaults write com.mycompany.myapp CGContextHighlight2xScaledImages YES

TroubleshootingThis section addresses some common problems you might encounter as you modify your app for high resolution.

Controls and Other Window Elements Are Truncated or Show Up in Odd PlacesMisplaced or truncated drawing almost certainly results from code that assumes a 1:1 relationship betweenpoints and pixels. In a high-resolution environment, there is no guarantee that this is the case. You might needto use the functions described in “Converting to and from the Backing Store” (page 52) to perform appropriateconversions between points and pixels.

Images Don’t Look as Sharp as They ShouldIf you supplied standard- and high-resolution versions of images in your app but don’t think the correct versionis being loaded, you can check whether it is by using the tinting option in Quartz Debug (see “Make Sure @2xImages Load on High-Resolution Screens” (page 62)). If you see a tinted image instead, use tiffutil to checkthe sizing (see “Run the TIFF Utility Command in Terminal” (page 27)). You should also make sure thehigh-resolution version is named correctly. For example, make sure you use a lowercase x for @2x.

OpenGL Drawing Looks FuzzyIf OpenGL drawing looks slightly out of focus, make sure that:

● Your code opts in for getting the best resolution for your OpenGL view (see “Enable OpenGL forHigh-Resolution Drawing” (page 32)).

Testing and Troubleshooting High-Resolution ContentTroubleshooting

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

64

Page 65: Apple manual

● You have not mixed point-based and pixel-based routines (see the example shown in “Set Up the Viewportto Support High Resolution” (page 33)).

Objects Are MisalignedThe solution is to make sure that your drawing aligns on pixel boundaries rather than relying on points. Youmight also consider using Auto Layout for constraint-based, pixel-precise layout that works well for dynamicwindow changes. For more details, see Cocoa Auto Layout Guide .

To adjust the position of an object to fall on exact pixel boundaries

1. Convert the object’s origin and size values from user space to device space.

2. Normalize the values to fall on exact pixel boundaries in device space.

Tip: Avoid using rounding functions on view coordinates, because rounding skips every other

pixel and can result in an undesired effect. You can achieve more precise alignment by using

the backingAlignedRect:options: method (see “Aligning a Rectangle on Pixel

Boundaries” (page 52)).

3. Convert the normalized values back to user space to obtain the coordinates required to achieve thedesired pixel boundaries.

4. Draw your content using the adjusted values.

Testing and Troubleshooting High-Resolution ContentTroubleshooting

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

65

Page 66: Apple manual

backing scale factor The relationship betweenpoints in a virtual object (view, window, or screen)and the pixels that represent that object onscreen.In OS X this value is either 1.0 or 2.0, depending onthe resolution of the underlying device.

backing store An offscreen buffer used for drawingoperations.

base space The default coordinate system for agraphics context.

current transformation matrix An affine transformthat the system uses to map points from onecoordinate space to another for the current graphicscontext.

device space A fixed coordinate system thatcorresponds to individual pixels on a physical device,such as a display or printer. One unit in device spaceequals one pixel.

framework-scaled mode The way the applicationframework automatically adjusts Cocoa app contentonscreen to ensure sharp graphics whether thedisplay is standard or high resolution. Applicationframeworks draw all standard user interfaceelements—such as buttons, menus, and the windowtitle bar—to the correct size for the resolution.

magnified mode An accommodation OS X makesto allow apps that aren’t high resolution to runacceptably on a high-resolution display. The systemmagnifies the contents of the backing store to fillthe display.

pixel The smallest picture unit on a display device.

point One unit in user space, prior to anytransformations on the space. The term point hasits origin in the print industry, which defines 72points as equal to 1 inch in physical space. Whenused in reference to high resolution in OS X, pointsin user space do not have any relation tomeasurements in the physical world.

user size The size, in points, of an object onscreen.

user space A device-independent coordinatesystem that an application draws into. One unit inuser space equals one point. You can transform userspace by applying scaling, rotation, and translation.The mapping from user space to device spacedepends on: (1) The mapping between default userspace and device space; (2) The coordinatetransformations applied to user space either by thesystem API or your own API.

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

66

Glossary

Page 67: Apple manual

This table describes the changes to High Resolution Guidelines for OS X .

NotesDate

Added a plist key.2012-09-19

Guidelines for building an app to take advantage of the increasedresolution for Retina displays; updated for OS X v10.8.

2012-07-23

2012-09-19 | © 2012 Apple Inc. All Rights Reserved.

67

Document Revision History

Page 68: Apple manual

Apple Inc.© 2012 Apple Inc.All rights reserved.

No part of this publication may be reproduced,stored in a retrieval system, or transmitted, in anyform or by any means, mechanical, electronic,photocopying, recording, or otherwise, withoutprior written permission of Apple Inc., with thefollowing exceptions: Any person is herebyauthorized to store documentation on a singlecomputer for personal use only and to printcopies of documentation for personal useprovided that the documentation containsApple’s copyright notice.

No licenses, express or implied, are granted withrespect to any of the technology described in thisdocument. Apple retains all intellectual propertyrights associated with the technology describedin this document. This document is intended toassist application developers to developapplications only for Apple-labeled computers.

Apple Inc.1 Infinite LoopCupertino, CA 95014408-996-1010

Apple, the Apple logo, Carbon, Cocoa, Finder,Mac, OS X, Quartz, QuickDraw, QuickTime, andXcode are trademarks of Apple Inc., registered inthe U.S. and other countries.

Retina is a trademark of Apple Inc.

OpenGL is a registered trademark of SiliconGraphics, Inc.

Even though Apple has reviewed this document,APPLE MAKES NO WARRANTY OR REPRESENTATION,EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THISDOCUMENT, ITS QUALITY, ACCURACY,MERCHANTABILITY, OR FITNESS FOR A PARTICULARPURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED“AS IS,” AND YOU, THE READER, ARE ASSUMING THEENTIRE RISK AS TO ITS QUALITY AND ACCURACY.

IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIALDAMAGES RESULTING FROM ANY DEFECT ORINACCURACY IN THIS DOCUMENT, even if advised ofthe possibility of such damages.

THE WARRANTY AND REMEDIES SET FORTH ABOVEARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORALOR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,agent, or employee is authorized to make anymodification, extension, or addition to this warranty.

Some states do not allow the exclusion or limitationof implied warranties or liability for incidental orconsequential damages, so the above limitation orexclusion may not apply to you. This warranty givesyou specific legal rights, and you may also have otherrights which vary from state to state.