21
votes

I'd like to create a UIImage object from the current graphics context. More specifically, my use case is a view that the user can draw lines on. They may draw incrementally. After they are done, I'd like to create a UIImage to represent their drawing.

Here is what drawRect: looks like for me now:

- (void)drawRect:(CGRect)rect
{
CGContextRef c = UIGraphicsGetCurrentContext();

CGContextSaveGState(c);
CGContextSetStrokeColorWithColor(c, [UIColor blackColor].CGColor);
CGContextSetLineWidth(c,1.5f);

for(CFIndex i = 0; i < CFArrayGetCount(_pathArray); i++)
{
    CGPathRef path = CFArrayGetValueAtIndex(_pathArray, i);
    CGContextAddPath(c, path);
}

CGContextStrokePath(c);

CGContextRestoreGState(c);
}

... where _pathArray is of type CFArrayRef, and is populated every time touchesEnded: is invoked. Also note that drawRect: may be invoked several times, as the user draws.

When the user is done, I'd like to create a UIImage object that represents the graphics context. Any suggestions on how to do this?

3
Both of the answers below work. Note that there is a functional difference between the two, which is that rendering the layer in the image context will also render the layer's background; calling drawRect: directly does not (in my case it doesn't matter). I am going with the CALayer renderInContext approach because of complexities with calling drawRect: directly (See lists.apple.com/archives/Cocoa-dev/2002/Apr/msg01846.html for details). Thanks!figelwump

3 Answers

43
votes

You need to setup the graphics context first:

UIGraphicsBeginImageContext(myView.bounds.size);
[myView.layer renderInContext:UIGraphicsGetCurrentContext()];
viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
7
votes

UIImage * image = UIGraphicsGetImageFromCurrentImageContext();

If you need to keep image around, be sure to retain it!

EDIT: If you want to save the output of drawRect to an image, just create a bitmap context using UIGraphicsBeginImageContext and call your drawRect function with the new context bound. It's easier to do than saving the CGContextRef you're working with within drawRect - because that context may not have bitmap information associated with it.

UIGraphicsBeginImageContext(view.bounds.size);
[view drawRect: [myView bounds]];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

You can also use the approach that Kelvin mentioned. If you want to create an image from a more complex view like UIWebView, his method is faster. Drawing the view's layer does not require refreshing the layer, it just requires moving image data from one buffer to another!

3
votes

Swift Version

    func createImage(from view: UIView) -> UIImage {
        UIGraphicsBeginImageContext(view.bounds.size)
        view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
        let viewImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return viewImage
    }