I occasionally come across the need to grab the contents of a view as an image. This is often the result of needing to perform some non-stock, animated transition between views, but there are a variety of reasons why this might be useful. Thanks to the Core Animation framework’s
CALayer class, this is easy to do.
UIView instances have an underlying instance of a
CALayer. The layer is responsible for rendering the view’s contents and performing any view-related animations. CALayer defines a method called
renderInContext: which allows you to render the layer, and its sublayers, into a given graphics context:
UIGraphicsContext context = // some graphics context
Before you can access any layer-specific APIs, you’ll need to make sure you’re linking against the QuartzCore framework. Xcode’s default templates don’t link against this framework so you’ll need to select Target Name > Build Phases > Link Binary With Libraries and select
Additionally, you’ll need to add the following import to your code wherever you are calling the layer’s properties or methods:
With the necessary project configuration out of the way, the next question is where do we get a graphics context into which we can render the view’s content? This can be created using UIKit’s
UIGraphicsBeginImageContextWithOptions function which will create a new bitmap-based graphics context for us.
UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);
This function takes a
CGSize (you view’s size), a
BOOL indicating if your view is opaque, and a
CGFloat specifying the scaling factor. If you’re rendering a fully opaque, rectangular view you can pass YES for the
opaque argument so the alpha channel can be discarded from the context.
Now that we’ve created a graphics context we can use the
UIGraphicsGetImageFromCurrentImageContext() functions to get reference to this new context and retrieve the rendered image data from it. Finally, we’ll want to call the
UIGraphicsEndImageContext() function to clean up this context and remove it from the stack. Putting all this together we end up with the following:
// Render the views layer contents into the current Graphics context
CGSize viewSize = viewToCapture.bounds.size;
UIGraphicsBeginImageContextWithOptions(viewSize, NO, 1.0);
// Read the UIImage object
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
To see this code in action I’ve put together a simple demo app. You can tap on Archer, Lana, or the background to capture the contents of the view and write the image to your Photo Library.
Note: Before running the demo be sure to open the “Photos” app on the Simulator so it can initialize its database or the images won’t be written. Enjoy!