Capture screenshot from another ViewController - Obj C - ios

I am currently using:
CGRect rect = [self.view bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.view.layer renderInContext:context];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
This retrieves a screen shot of the current view once a UITabBarItem is selected. The problem is, this will always capture the view of the current view the user is active on before switching to the next view.
To better understand this. I have a UITabBarController that manages my navigation for my app. The walk in View controller is a table that I want to always capture a picture of when the user selects the Share UITabBarItem on the navigation. So I have this linked to a method that checks to see if Share has been clicked and creates an image of the current view as shown above.
My roadblock is, how can I capture an image of that first view(walk in view) every time no matter what view the user is currently on?
I am handling my capturing functionality within a custom class that initates the UITabBarController
Suggestions thoughts?

Will this help you?
CGRect rect = [yourTabController.viewControllers[walkInViewIndex].view bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[yourTabController.viewControllers[walkInViewIndex].view.layer renderInContext:context];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

[self.view.layer renderInContext:context];
This explicitly takes a snapshot of the current view (self.view). What you'll want to do is more or less the same procedure, but by specifying your walk in view instead:
[self.walkingController.view.layer renderInContext:context];

Related

how to use drawViewHierarchyInRect

I want to create a snapshot image for a UIView, I used to use renderInRect, but it is slow, and I found that drawViewHierarchyInRect is a newer API since iOS 7, so I want to try it.
I write below code, but it never create a valid image, just a blank image.
-(void)drawRect:(CGRect)rect {
UIGraphicsBeginImageContextWithOptions(_mapView.bounds.size, _mapView.opaque, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
// Used to use renderInContext, but it's slow
// [mapView.layer renderInContext:context];
[_mapView drawViewHierarchyInRect:_mapView.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.thumbImageView = [[UIImageView alloc] initWithImage:image];
[self addSubview:self.thumbImageView];
}
The -drawViewHierarchyInRect:afterScreenUpdates:, which lets you render a snapshot of the complete view hierarchy as visible onscreen into a bitmap context.
renderInContext: renders directly from a CALayer's render tree to valid Core Graphics context.
If you want to render the view to a UIImage rather than having it on the View Hierarchy, you should using renderInContext.

How to get a screenshot of a CATiledLayer based TilingView

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?

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

Taking a screenshot of a view that is currently not on screen on iOS

I'm trying to make a transition between two ViewControllers. My Transition class has a property for the destination view controller. When I try to get a screenshot of the destination's view, I use this method:
+ (UIImage *)renderImageFromView:(UIView *)view withRect:(CGRect)frame {
// Create a new context the size of the frame
UIGraphicsBeginImageContextWithOptions(frame.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// Render the view
[view.layer renderInContext:context];
// Get the image from the context
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
// Cleanup the context you created
UIGraphicsEndImageContext();
return renderedImage;
}
So when I want the image, I'll do this:
UIImage *image = [UIImage renderImageFromView:destinationController.view withRect:destinationController.view.bounds];
I tried it on a blank UIViewController with an orange background color and a label. I get the orange background color, but I do not get the label that was created in IB. Is there a way to get a proper screenshot of the new view I plan on showing? Thanks!
You need to make sure the view's layer is drawn to first. Calling renderInContext on a CALayer will only recursively call additional child CALayers. You need your child UIViews to draw themselves, not just using the CALayer.
Try calling
[view drawrect:frame];
instead of
[view.layer renderInContext:context];
As long as you have an open graphics context(which you do at that point), drawrect should draw directly into that.

Save a view as image in original size

there are many threads about how to save a view as an image. And all of them give the same answer:
CGRect rect = [myView bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,[[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
[myView.layer renderInContext:context];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
my problem is that I have a view that contains several joined imageViews that contain images. I want to save that "holder" view in a size that corresponds to the size of images residing inside it. So if i have 2 images 400x400 side by side, I'd like to save 400x800 image, regardless that they are displayed lets say 30x60.
Plus the above code only captures what's on the screen and leaves out the rest. For instance if i wanted to get the entire scrollview with its content size, it's not possible.
any ideas?
If you want to get an image of the entire contentSize of a UIScrollView, take a look at this.

Resources