16

Like you can see in my code, I take a screenshot and save it to the photo album.

//for retina displays
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
} else {
    UIGraphicsBeginImageContext(self.view.bounds.size);
}
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);

At the beginning I used webview.size instead of self.view.bounds.size and it was working properly because the view was located at 0/0. But now I centered the WebView but the pictures is starts at 0/0 for the given size.

How can I configure that the screenshot starts at another location (e.g. 300/150) for the given size?

Or is there another way to take a picture of an UIWebView?

Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
Sharky
  • 428
  • 5
  • 17

4 Answers4

22

You need to make two changes in order to only grab a portion of the screen:

  1. Create a smaller image - use the size of the rect you'd like to capture.
  2. Move the origin of the context that you're rendering into to be negative x/y of the rect you'd like to capture.

After that, you just render the layer into the context as you were doing, and you should get what you're looking for. Something like this ought to do it:

CGRect grabRect = CGRectMake(40,40,300,200);

//for retina displays
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
    UIGraphicsBeginImageContextWithOptions(grabRect.size, NO, [UIScreen mainScreen].scale);
} else {
    UIGraphicsBeginImageContext(grabRect.size);
}
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, -grabRect.origin.x, -grabRect.origin.y);
[self.view.layer renderInContext:ctx];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);
escrafford
  • 2,373
  • 16
  • 19
  • This crashes my app. Any idea why? I've added the QuartzCore framework and put this code in a function, but still no go. – rebellion Jun 05 '13 at 13:59
  • @rebellion - I've gotten this to work. Albeit not in the photo album. See my adaptation below as a UIView category method. – idStar Jun 20 '13 at 22:02
  • Thanks, this works great for me. Just a little problem the image background color is white, i want it transparent. How can i do that. Please help – iMemon Nov 06 '13 at 14:22
  • 1
    Image background color was white since I was uploading jpeg image instead of png image. Above code is perfect :) – iMemon Nov 06 '13 at 14:47
9

I've taken and tested @escrafford's answer above, and got it to work just fine. I did test it in the context of making it a category method on UIView, so that the 'grabRect' can be paramaterized. Here's that code, as a UIView category that returns you a UIImageView:

/**
 Takes a screenshot of a UIView at a specific point and size, as denoted by
 the provided croppingRect parameter. Returns a UIImageView of this cropped
 region.

 CREDIT: This is based on @escrafford's answer at http://stackoverflow.com/a/15304222/535054
*/
- (UIImageView *)rp_screenshotImageViewWithCroppingRect:(CGRect)croppingRect {
    // For dealing with Retina displays as well as non-Retina, we need to check
    // the scale factor, if it is available. Note that we use the size of teh cropping Rect
    // passed in, and not the size of the view we are taking a screenshot of.
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(croppingRect.size, YES, [UIScreen mainScreen].scale);
    } else {
        UIGraphicsBeginImageContext(croppingRect.size);
    }

    // Create a graphics context and translate it the view we want to crop so
    // that even in grabbing (0,0), that origin point now represents the actual
    // cropping origin desired:
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(ctx, -croppingRect.origin.x, -croppingRect.origin.y);
    [self.layer renderInContext:ctx];

    // Retrieve a UIImage from the current image context:
    UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    // Return the image in a UIImageView:
    return [[UIImageView alloc] initWithImage:snapshotImage];
}
idStar
  • 10,674
  • 9
  • 54
  • 57
2

I solved my problem but didn't answer the question:

I created a subclass of UIView and moved my UIWebView in there, so that it is located 0/0 relative to the subclass. Then use the size of the WebView:

UIGraphicsBeginImageContext(webview.frame.size);

and the other code from above.

Now you can move the subclass to every location you want.

Note: If you have labels like date/time label you have to move them too or you won't see them on the picture.

So create a subclass of UIView and move every IBOutlet you want to be seen on the picture in there.

The question is still open: So is it possible to take a picture of a specific area of the screen?

Kind Regards. $h@rky

Sharky
  • 428
  • 5
  • 17
0
- (void)drawRect:(CGRect)rect {
  UIGraphicsBeginImageContext(self.bounds.size);    
  [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
  UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);  
}

You could call this to your view :]

Nils Munch
  • 8,805
  • 11
  • 51
  • 103
  • The drawRect method is called when the web view is created - so i have an grey pic at the beginning. The idea that I got from this is to drag the code and drop it the my custom UIView class where my web view is located at 0/0. Thats working but I didn't see the label anymore because it is part of the "root view". – Sharky Jan 03 '12 at 07:28