Establishing Contexts in UIKit
UIKit provides friendly entry points for building contexts. The simplest image drawing pattern is shown in Listing 1-1. This involves nothing more than starting a new context (you specify the size of that context), drawing to it, retrieving a new image, and ending the context. This pattern produces images at a base 1:1 scale, where every drawing operation corresponds to exact pixels within the bitmap context.
Listing 1-1 Creating a Basic Bitmap Context in UIKit
UIGraphicsBeginImageContext(size); // Perform drawing here UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
Device Scale
Listing 1-2 shows a more sophisticated (and recommended) entry point. It enables you to build images that respect device scale. The with-options variant used here to create the bitmap context specifies the scale for drawing the image. Scale refers to the relationship between logical space (measured in points) and physical displays (measured in pixels).
An image created with a scale of 2 produces Retina-ready graphics. The pixel extent doubles in each direction, producing an image that stores four times the data compared to an image drawn at the base scale of 1. The opacity parameter allows you to ignore the alpha channel to optimize bitmap storage. You need only 3 bytes per pixel versus 4 with alpha.
Listing 1-2 Context Options Enable Drawing at Device Scale
UIGraphicsBeginImageContextWithOptions( targetSize, isOpaque, deviceScale); // Perform drawing here UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
I strongly encourage you to use the approach shown in Listing 1-2 for images you use in your application. For example, when drawing an image for a UIImageView, always use the with-options approach.
You can supply a screen scale to the third parameter by querying the UIScreen class. For images drawn to the primary screen, use the mainScreen method, as in this example:
UIGraphicsBeginImageContextWithOptions( targetSize, isOpaque, [UIScreen mainScreen].scale);
You may also pass 0.0 as the third parameter. This automatically determines the scaling, based on the device’s main screen.
When working with video out, where you have connected a monitor to an iOS device using a cable or when you’re using AirPlay to wirelessly present a second screen, use the scale of that particular destination. Query UIScreen for that information.
Creating PDF Contexts
With PDF context creation, you must draw either to a file path or to a mutable data object, which is supplied to a data consumer. Listing 1-3 shows an example of the former. You supply a bounds rectangle (pass CGRectZero for an A-sized page) and a dictionary where you specify metadata and security information for the new document. For example, you might specify the author, owner and user passwords, printing and copying permission, keywords, and so on.
As with the bitmap context, Core Graphics implementations (specifically, CGPDFContext) have been around a lot longer than their UIKit equivalents. If you want to dive into the C-based classes and functions, you’ll discover another take on PDF production.
Listing 1-3 Drawing an Image into a PDF File
UIGraphicsBeginPDFContextToFile(pathToFile, theBounds, documentInfo); UIGraphicsBeginPDFPage(); // Perform drawing here UIGraphicsEndPDFContext();
You begin each page of drawing by calling UIGraphicsBeginPDFPage(). This establishes a new page in the document for you to write to. You do not have to end each page explicitly, but you do have to end the PDF context, just as you end any other context, when you are done creating your output.