Whenever an **iOS** application goes to background, the system takes a snapshot of it to present it in the multitask switcher. Is there any chance to get access to this screenshot? I know it corresponds to the top window, and this could be edited from
- (void)applicationDidEnterBackground:(UIApplication *)application
But the results are not the one expected, and would like to know what exactly is iOS snapshotting.
use this code to capture snapshot:
#import <QuartzCore/QuartzCore.h>
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * imgData = UIImagePNGRepresentation(image);
if(imgData)
[imgData writeToFile:#"screenshot.png" atomically:YES];
else
NSLog(#"error while taking screenshot");
In the App Programming Guide for iOS, Apple says:
obscuring/replacing sensitive information, you might also want to tell iOS 7 to not take the screen snapshot via ignoreSnapshotOnNextApplicationLaunch. According to the documentation for this method:
Hope this will be helpful.
Related
I am using the below code to take a screenshot of the screen, but it replaces the camera view with all black (though all other UI elements are fine-- I need the Camera View as well as UI elements).
All answers to similar questions that I've found are either extremely old/deprecated, or in Swift. If anyone has a simple, Obj-C solution to this problem, it would be much appreciated.
Thanks!
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(self.view.window.bounds.size, NO, [UIScreen mainScreen].scale);
} else {
UIGraphicsBeginImageContext(self.view.window.bounds.size);
}
[self.view.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imageData = UIImagePNGRepresentation(image);
if (imageData) {
[imageData writeToFile:#"Screenshot.png" atomically:YES];
NSLog(#"Screenshot write successful");
} else {
NSLog(#"Error while taking screenshot");
}
If i understand correct, it can help you get video screen - https://stackoverflow.com/a/37789235/1678018
And you can add this image in screen image (which you have with UIGraphicsGetImageFromCurrentImageContext).
Example way for add UIImage on top of another UIImage: Add UIImage on top of another UIImage
I have a feature, I want to take a screenshot of a UIView(called "arrangeView" in my codes). and send the picture to my server, and then I will print it, so I want a high quantity picture..
My codes:
UIGraphicsBeginImageContext(arrangeView.frame.size);
[arrangeView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
//save and send method
[self saveImage:newImage WithName:imgTitle];
With these codes I have 2 issues:
the picture quality is too low. because after I uploaded to the
server, I will print it. but the picture I got with the codes only
20~40k, it is too small to print.
one friend told me that the app store don't alow app take a screenshot and send it to the server. he told me to use bitmap.
And I searched in google, I don't find a good solution for it. Would someone help?
Thank you very much.
Screen shot you get will be of same resolution as you main screen size i.e If it is iPhone 5s it will be 640 x 1136. Best way to get screen shot is:
UIView *screenShotView = [arrangeView snapshotViewAfterScreenUpdates:YES];
Please try to use the code below.you may save first in photo album and then you can send to server
UIView* captureView = self.view;
/* Capture the screen shoot at native resolution */
UIGraphicsBeginImageContextWithOptions(captureView.bounds.size, captureView.opaque, 0.0);
[captureView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Render the screen shot at custom resolution */
CGRect cropRect = CGRectMake(0 ,0 ,1435 ,1435);
UIGraphicsBeginImageContextWithOptions(cropRect.size, captureView.opaque, 1.0f);
[screenshot drawInRect:cropRect];
UIImage * customScreenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
/* Save to the photo album */
UIImageWriteToSavedPhotosAlbum(customScreenShot , nil, nil, nil);
I had to alter the navigation on certain circumstances, and due to complexity of the transitions I had take an paint and screenshot until the transition is finished. In almost cases, that works pretty well, but there is a point that disturb me. I have a view controller with two picker views:
But the screenshot is not working well on this VC. I get this:
The code that takes the screenshot is the following in both cases:
- (UIImage *)takeScreenshot {
CALayer *layer = [[UIApplication sharedApplication] keyWindow].layer;
UIGraphicsBeginImageContext(layer.frame.size);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
return screenshot;
}
Anyone knows how could be happened?
You could try to use a different method for screenshot. Apple introduced in iOS 7 some methods for fast view screenshot.
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
UIImage *im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Here is an answer from Apple that provides more info on how the 2 methods works. While the respective user encountered some pb and was advised to use the old way of snapshotting the view, I never had any problem with it. Maybe they fixed it since then.
UIGraphicsBeginImageContext(self.window.bounds.size);
[self.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:#"image.png" atomically:YES];
if you have a retina display then replace the first line with the below code:-
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.window.bounds.size, NO,[UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(self.window.bounds.size);
I was converting a project from iOS7 to iOS8 which uses custom transitions and needs to capture the modal after it finishes loading afterScreenUpdates:YES and was seeing that the entire screen scale up for a second and scale back down. I also see this happening in the Flickr app for iOS between sections and on Yelp app when transitioning to a photo on iOS8.
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, YES, 22.0);
[self.view drawViewHierarchyInRect:self.view.frame afterScreenUpdates:YES];
UIGraphicsEndImageContext();
Adding a larger scale factor helps emphasize the glitch more... but i'm just calling this on a button press in the example.
EDIT This appears to happen on iPhone 6 and 6 plus not on the 5.
Sample project github
Do you NEED it to draw after the screen updates? because I'm using:
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
and it seems to work fine on iOS7 and iOS8. I imagine this isn't a great solution for capturing images regularly (like multiple times a second) but it seems to work for a once off blur.
You have to provide #3x launch images for the 6 and 6 plus. The 6 being scaled at 750x1334, and the 6 plus image being scaled at 1242x2208.
Even it looks like bug in API, you can call drawViewHierarchyInRect with afterScreenUpdates set to NO to build snapshot AFTER screen updates if you use cunstruction like this:
typedef void (^CompletionHandlerWithId)(id result);
-(void)imageContaining:(CGRect)rect afterScreenUpdates:(bool)afterScreenUpdates opaque:(BOOL)opaque completion:(CompletionHandlerWithId)completion
{
bool success __block;
UIImage *snapshotImage __block = nil;
CompletionHandler block = ^{
// Create the image
UIGraphicsBeginImageContextWithOptions(self.bounds.size, opaque, [[UIScreen mainScreen] scale]);
success = [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
if (success)
{
snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
CGImageRef imageRef = CGImageCreateWithImageInRect(
[snapshotImage CGImage],
CGRectMake(
snapshotImage.scale*rect.origin.x,
snapshotImage.scale*rect.origin.y,
snapshotImage.scale*rect.size.width,
snapshotImage.scale*rect.size.height));
// or use the UIImage wherever you like
snapshotImage = [UIImage imageWithCGImage:imageRef scale:snapshotImage.scale orientation:UIImageOrientationUp];
CGImageRelease(imageRef);
}
UIGraphicsEndImageContext();
if (completion)
{
if (! success)
{
NSLog(#"Error: [UIView drawViewHierarchyInRect] failed on %#", self);
(completion)(nil);
}
else
{
NSLog(#"Success: [UIView drawViewHierarchyInRect] on %#", self);
(completion)(snapshotImage);
}
}
};
if (afterScreenUpdates)
[CATransaction setCompletionBlock:^{
(block)();
}];
else
(block)();
}
This bug also exists when you run on an iPad2 running iOS7.
Fix: set afterScreenUpdates: to NO
My app has some moving UIButtons, so I don't allow the blur transition until after the movement has stopped. As far as I have found so far, there is no difference in YES or NO.
Appears to be fixed in iOS9 / XCODE 7 builds
I found a solution for me to solve this problem.
I add #3x launch images to my project. And choose launch Screen file to "Main".
This will make app run at original resolution, smaller bounds when run at iphone6, but not glitch when calling drawViewHierarchyInRect. Like this.
Then, scale my view to fullscreen when viewDidLoad.
- (void)viewDidLoad{
[super viewDidLoad];
UIScreen *mainScreen = [UIScreen mainScreen];
CGRect tempFrame=mainScreen.bounds;
double aspect=tempFrame.size.width/320;
self.view.transform = CGAffineTransformScale(CGAffineTransformIdentity, aspect, aspect);
}
Hope helpful :)
The entire block of code consists of the following:
CGSize layerSize = [webview sizeThatFits:CGSizeZero];
if ([UIScreen instancesRespondToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2.0f) {
UIGraphicsBeginImageContextWithOptions(layerSize, NO, 2.0f);
}
else {
UIGraphicsBeginImageContext(layerSize);
}
[webview.layer renderInContext:UIGraphicsGetCurrentContext()];
screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
but after testing, this line is the one causing the problem:
[webview.layer renderInContext:UIGraphicsGetCurrentContext()];
The app crashes with no reason listed in the console, and using #try #catch #finally comes up with nothing. I imported Quartzcore in AppDelegate.h, if that has anything to do with it. The app works fine in the simulator, but crashes when run on a real device.
#Greg : seems like a memory overflow issue on device since device is memory constrained while simulator runs with different memory configuration , i am running into the same - this can happen for long web pages , any ideas how to solve it ?
does anyone what is max width and height [CALayer renderInContext] can handle on actual device (iphone retina or non-retina) before it crashes ?
try
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();