How to get a screenshot of a CATiledLayer based TilingView - ios

I'm trying in my app to take a screenshot of the current screen contents, where my TilingView (based on CATiledLayers) displays a number of transparent large tiled images.
Also I added some subViews to the TilingView, which are magically captured in the screenshot, however the underlying contents of the TilingView is not captured!??
The following code-snippets takes a snapshot of the visible screen, which seems to work well for a NON CATiledLayer based view-hierarchy, but unfortunately doesn't work for my setup. Even if I pass the topmost superview of the TilingView (being the actual UIViewController.view), I see only in my snapshot the StatusBar, NavigationBar, the TilingViews subViews and the TabBar, but again NOT the TilingViews contents.
- (UIImage*)captureView:(UIView *)viewToCapture {
CGRect rect = [[UIScreen mainScreen] bounds];
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[viewToCapture.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Does anybody know or see here what I'm missing? Do I need to delve deeper into the CG-related display stack with some, for me, unknown CG-API calls? Thanks in advance.

By searching some more in StackOverflow I've found code which seems to do what I wanted. Basically I need to change the above method into:
- (UIImage*)captureView:(UIView*)viewToCapture {
UIGraphicsBeginImageContextWithOptions(viewToCapture.bounds.size, NO, [UIScreen mainScreen].scale);
[viewToCapture drawViewHierarchyInRect:viewToCapture.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Thanks go to the question/answer at: How to get a screenshot of a view containing GPUImageView?

Related

Efficiently take a snapshot of a large UIWebView?

I've tried the following code to take a screenshot of a UIWebView whose bounds are larger than that of the screen (for example, around 1200pts), however the screenshot always comes out as the top part of the web view, stretched vertically downwards to cover the whole rect that it's supposed to draw. Any ideas? I could do it using -renderInContext:, but that's a slower and outdated method. Here's my current code:
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, scale);
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;

Fastest way to take screenShot of UIView

I've searched a lot but only found two methods to take screen shot of UIView.
first renderInContext:
I've used it in a way
CGContextRef context = [self createBitmapContextOfSize:CGSizeMake(nImageWidth, nImageHeight)];
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, nImageHeight);
CGContextConcatCTM(context, flipVertical);
[self.layer setBackgroundColor:[UIColor clearColor].CGColor];
[self.layer renderInContext:context];
CGImageRef cgImage = CGBitmapContextCreateImage(context);
UIImage* background = [UIImage imageWithCGImage: cgImage];
CGImageRelease(cgImage);
Second drawViewHierarchyInRect: which I've used as
UIImage *background = nil;
UIGraphicsBeginImageContextWithOptions (self.bounds.size, NO, self.window.screen.scale);
if ([self respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)])
{
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
}
background = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I know that the second one is faster than first and it work for me for iPhone because the view has low size. but when I capturing from iPad the video become jerky.
Can Any body tell me faster way of taking screen shot.
any help would be highly appreciated
Regarding performance, the Apple Docs state the following:
In addition to -drawViewHierarchyInRect:afterScreenUpdates:, UIView
now provides another two snapshot related methods,
-snapshotViewAfterScreenUpdates: and -resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:. UIScreen also has -snapshotViewAfterScreenUpdates:.
Unlike UIView's -drawViewHierarchyInRect:afterScreenUpdates:, these
methods return a UIView object. If you are looking for a new snapshot
view, use one of
these methods. It will be more efficient than calling
-drawViewHierarchyInRect:afterScreenUpdates: to render the view contents into a bitmap image yourself. You can use the returned view
as a visual stand-in for the current view/screen in your app. For
example, you might use a snapshot view for animations where updating a
large view hierarchy might be expensive.
There is a third method for taking a snapshot that is much much quicker than either of these but it returns a UIView.
- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates
If you are just using the snapshot to place as a background "image" etc... then I'd use this instead.
However, this is only available for iOS8.
To use it just do...
UIView *snapshotView = [someView snapshotViewAfterScreenUpdates:YES];
This Method will return you A snapshot images of particular view
-(UIImage *)createSnapShotImagesFromUIview
{
UIGraphicsBeginImageContext(CGSizeMake(view.frame.size.width,view.frame.size.height));
CGContextRef context = UIGraphicsGetCurrentContext();
[mapView.layer renderInContext:context];
UIImage *img_screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img_screenShot;
}

iOS: renderInContext and Landscape orientation issue

I'm trying to save the currently shown views on my iOS device for a certain app, and this is working properly. But I've got a problem as soon as I'm trying to save a UIImageView in Landscape orientation.
See the following image that describes my problem:
I'm using Auto layout for this app, and it runs on both iPhone and iPad. It seems like the ImageView is always saved as shown in portrait mode, and I'm a little bit stuck right now.
This is the code I use:
CGSize frameSize = self.view.frame.size;
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
frameSize = CGSizeMake(self.view.frame.size.height, self.view.frame.size.width);
}
UIGraphicsBeginImageContextWithOptions(frameSize, NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat scale = CGRectGetWidth(self.view.frame) / CGRectGetWidth(self.view.bounds);
CGContextScaleCTM(ctx, scale, scale);
[self.view.layer renderInContext:ctx];
[self.delegate photoSaved:UIGraphicsGetImageFromCurrentImageContext()];
UIGraphicsEndImageContext();
Looking forward to your help!
I still have no idea what your exact issue is but using your screenshot code makes a bit strange image (not rotated or anything though, just too small). Can you try this code instead please.
+ (UIImage *)imageFromView:(UIView *)view {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, .0f);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
Other then that you must understand there is a huge difference between UIImage and CGImage as the UIImage includes the orientation while CGImage does not. When dealing with image transformations it is usually with the CGImage and getting its width or height will discard the orientation. That means a CGImage will have flipped dimensions when its orientation is not up (UIImageOrientationUp). But usually when dealing with such images you create a CGImage from the context and then use [UIImage imageWithCGImage:ref scale:1.0f orientation:originalOrientation]. Only if you wish to explicitly rotate the image so it has no orientation (being UIImageOrientationUp) you need to rotate and translate the image and draw it onto the context.
Anyway, this orientation issues are quite fixed by now, UIImagePNGRepresentation respects the orientation and you have an image constructor from the CGImage already written above which is what used to be missing in the past if I remember correctly.

Screenshot of iPad detail view orientation wrong

I'm trying to capture a screenshot of the detail view in a landscape master/detail layout on iPad.
This is the code I've tried using.
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
CGRect rect = [self.view bounds];
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[keyWindow.layer renderInContext:context];
UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Two problems occur with this.
- the screen capture orientation is incorrect. I get an image that is on it's side.
- The width=703 & height=768 dimensions are reversed by the screen capture so I end up with some of the master view in the detail screen shot.
What am I doing wrong here? Thanks!
try this way
-(UIImage *)captureScreenForRect:(CGRect)frame
{
CALayer *layer;
layer = self.view.layer;
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextClipToRect (UIGraphicsGetCurrentContext(),self.view.bounds);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenImage;
}
pass your detail view frame rect for above method. hope this will help you
The "official" screenshot method is here:
(https://developer.apple.com/library/ios/qa/qa1703/_index.html)
If you need this for a transition or for a graphical effect and your using iOS 7 - I suggest you don't actually create an image.
An image can be heavy to generate (for example on iPAd Retina 3rd Gen) and heavy on the memory.
Starting iOS 7 Apple gives you a much quicker Snapshot function on UIView (Which by the way is also the way they implement custom transitions in view controllers , blur effect etc) that is done much quicker then creating an actual image.
On a UIView you can perform:
- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates
Or if you need the full view hierarchy for a blurred view:
- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates

iOS Get Screenshot Of Visible Portion of a UITableView

I'm trying to get my app to take a screenshot of a view (a table view). This is the code I use to do this:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.tableView.frame.size, NO, [UIScreen mainScreen].scale); //retina display
else
UIGraphicsBeginImageContext(self.tableView.frame.size);
[self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This works, but only if the table view is scrolled to the very top, if it's not, the image is black. The only solutions to this that I have found is for capturing the entire table view. I only need the visible portion. How would I do this?
Solved by changing self.tableView.layer to self.tableView.superview.layer.

Resources