9

I use this method for taking a snapshot:

UIView *snapshotView = [someView snapshotAfterScreenUpdates:NO];

This gives me a UIView that I can play with.

But, I need the UIImage of it and not the UIView.

This is the method I use for converting a UIView to an UIImage:

- (UIImage *)snapshotOfView:(UIView *)view
{
    UIImage *snapshot;

    UIGraphicsBeginImageContext(view.frame.size);

    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    snapshot = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return snapshot;
}

It doesn't work, the snapshot is a blank UIImage because the snapshotView isn't rendered.

The obvious thing to do is to directly take a snapshot of the view instead of taking the snapshot in the form of a UIView and then converting it.

The problem with the obvious method is that I'm using a WKWebView that has a huge bug that doesn't allow you to take screenshots. And that's true, I even reported the bug and they said they are trying to fix it.

So, how can I take the snapshot (UIImage) of the snapshotView without rendering it?

Vulkan
  • 1,004
  • 16
  • 44
  • @HussainShabbir - not a dupe, different question, different answer. The other answer might have done the job, but this one is the correct fit with apple's current apis. I understand it is substantially more efficient (although I haven't tested that claim) – foundry Dec 11 '14 at 01:59

2 Answers2

11

drawViewHierarchyInRect will work for you. You can use this directly on your WKWebView.

There is some useful detail on this Apple Technical Q&A. Also I touch on it here in answer to a slightly different question.

I use it in a category on UIView:

@implementation UIView (ImageSnapshot)
- (UIImage*)imageSnapshot {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, 
                                    YES, self.contentScaleFactor);
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
@end

I don't know what you mean by 'the obvious method' - but I have tested this on a WKWebView and it works.

Community
  • 1
  • 1
foundry
  • 31,615
  • 9
  • 90
  • 125
  • Hello @foundry, I'm curious if you still find this a valid solution with iOS 9.2 & Xcode 7.2 (7C68)? I'm getting a white image. – chinjazz Jan 03 '16 at 21:41
  • @chinjazz: i've just tried Xcode 7.2 (7C68) with simulator versions of ios9.2 and ios8.4 (for comparison).. both work fine – foundry Jan 04 '16 at 01:45
  • Thanks for confirming! I'm finding that in Simulator the screen image will render for the WKWebView the first time but not on next loads (where its a white image).. Could be a bug on my end, but I'll check it on a device for consistency. – chinjazz Jan 04 '16 at 02:08
  • I'm finding that with WKWebView adding a delay after webView sucCubus Navigation it works better... – chinjazz Jan 04 '16 at 02:30
  • drawViewHierarchyInRect distorts my image every single time i used it in my project, didn't anyone notice that it distorts and stretches your image? – Reza.Ab Jun 05 '17 at 19:56
9

Since accepter answer didn't worked for me (UIGraphicsGetImageFromCurrentImageContext() returned nil all the time) I found different solution for iOS10+:

let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { _ in view.drawHierarchy(in: view.bounds, afterScreenUpdates: true) }

P.S. You may want to call updateConstraintsIfNeeded() and layoutIfNeeded() before rendering

Alexander Vasenin
  • 11,437
  • 4
  • 42
  • 70