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.
All 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:
|
1 2 |
UIGraphicsContext context = // some graphics context [viewToCapture.layer renderInContext: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 QuartzCore.framework.

Additionally, you’ll need to add the following import to your code wherever you are calling the layer’s properties or methods:
|
1 |
#import <QuartzCore/QuartzCore.h> |
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.
|
1 |
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 UIGraphicsGetCurrentContext() and 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:
|
1 2 3 4 5 6 7 |
// Render the views layer contents into the current Graphics context CGSize viewSize = viewToCapture.bounds.size; UIGraphicsBeginImageContextWithOptions(viewSize, NO, 1.0); [viewToCapture.layer renderInContext:UIGraphicsGetCurrentContext()]; // Read the UIImage object UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); |
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!

[ 9 comments ]
Maye I’m missing something, but how is this different than just pressing Power+Home buttons and capturing the screen to the camera roll?
Yes, you’re missing the point. Power+Home is a handy user feature, but doesn’t do anything for a developer. The intent of this post is to explain how you can capture a view (or any subview’s content) so you can use image data within your app.
This was a great tutorial.. The best that I have seen that captures the screen.. Thanks.. and thanks for making it fun..
I give it a A+ and you got me as a fan.
thanks so much for the tutorial. is it possible that you can achieve the same thing using cocos2d v2.0 without xib file?
im in desperate need to find a solution, ive been awake for 2 days search the internet and have come up empty handed.
thanks in advance
I don’t have any experience with cocos2d, but I don’t see why not. This technique is not limited to NIB-based apps.
thanks for the speedy reply. imma give it a shot. im just so tired of going through examples after examples. if i do eventually come up with a working solution i will post here for anyone that might want it in the future.
kind regards
i finally figured it out, i dont know how but i did. here is the code for cocos2D v2.0
-(void) cocos2DScreenShot {
CGSize size = [[CCDirector sharedDirector] winSize];
//Create un buffer for pixels
int bufferLenght=size.width*size.height*4;
unsigned char buffer[bufferLenght];
//Read Pixels from OpenGL
glReadPixels(0,0,size.width,size.height,GL_RGBA,GL_UNSIGNED_BYTE,&buffer);
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, &buffer, bufferLenght, NULL);
CGImageRef iref = CGImageCreate(size.width,size.height,8,32,size.width*4,CGColorSpaceCreateDeviceRGB(),kCGBitmapByteOrderDefault,ref,NULL,true,kCGRenderingIntentDefault);
uint32_t *pixels = (uint32_t *)malloc(bufferLenght);
CGContextRef context = CGBitmapContextCreate(pixels, size.width, size.height, 8, size.width*4, CGImageGetColorSpace(iref), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGContextTranslateCTM(context,0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0.0, 0.0, size.width, size.height), iref);
UIImage *outputImage = [UIImage imageWithCGImage:CGBitmapContextCreateImage(context)];
UIImageWriteToSavedPhotosAlbum(outputImage, nil, nil, nil);
//Dealloc
CGDataProviderRelease(ref);
CGImageRelease(iref);
CGContextRelease(context);
free(pixels);
}
I’m glad you got it figured out. Thanks for sharing your solution!
my code above works perfectly on the simulator but when testing it on a device i get an error, hee is the error:
glReadPixels(0,0,size.width,size.height,GL_RGBA,GL_UNSIGNED_BYTE,&buffer); -Thread 1: EXC_BAD_ACCESS(code=1, address=0x2fb78120)
i have no idea to debug or even begin to understand whats going on here. can anyone maybe enlighten me?
kind regards