I am looking for a way to capture a screenshot on the iPhone with the top status bar included, I am currently using the following code:
UIGraphicsBeginImageContext(self.view.bounds.size); //self.view.window.frame.size
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);
The above code sucessfully takes a screenshot of the iPhone UIView but does not include the top status bar (In its place is just a blank 20px space).
As of iOS 7, you can do this without the use of private APIs using
UIView *screenshotView = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
See my answer to this question:
Moving status bar in iOS 7
You can get the entire contents of the screen by calling the private API UIGetScreenImage. See my previous answer to a similar question for details.
As of Oct 8, 2009, the use of UIGetScreenImage got my app rejected! :( I would not advise using it. I believe Apple is trying to clean up all the apps and make them conform to the new 3.x OS/APIs. I'm looking for an alternative. If anyone has any suggestions. The video API?
Instead of using private API, why not render the entire UIWindow into the image context? It might be enough to replace self.view with self.view.window in your code.
You can also get the current window(s) as a property of the [UIApplication sharedApplication] instance. It's possible the status bar is on a separate window layer and maybe you'll have to render the windows in order.
Something like this:
UIGraphicsBeginImageContext(self.view.window.frame.size);
for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
[window.layer renderInContext:UIGraphicsGetCurrentContext()];
}
UIImage *screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);
At any rate, you probably don't need to resort to private API.
Related
I have the following code:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(mainView.bounds.size, NO, [UIScreen mainScreen].scale);
}
else {
UIGraphicsBeginImageContext(mainView.bounds.size);
}
[mainView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *saveImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
In mainView, there is a masked subview that does not appear in saveImage when using this method. However, I understand there used to be a UIGetScreenImage method pre iOS 4 that did capture such activity. My question is, what is the best way to capture CALayer activities in iOS 6? Is UIGetScreenImage still private?
I think there was a similar question about a week ago: Mask does not work when capturing a uiview to a uiimage
On iOS6 there is a problem capturing a UIView with the mask applied (btw, in iOS 7 it has been fixed): you capture the image but the mask is not applied.
I posted a lengthy solution which involved applying the mask manually to the captured image. It's not very difficult and I also made a demo project of this. You can download it here:
https://bitbucket.org/reydan/so_imagemask
If I did not understand your problem correctly, please tell me so I can remove this answer.
try getting the presentation layer instead, as it will contain the layer's state.
[mainView.layer.presentationLayer renderInContext:UIGraphicsGetCurrentContext()];
https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CALayer_class/Introduction/Introduction.html#//apple_ref/occ/instm/CALayer/presentationLayer
I have a specific function on an app that is intended to work on iPhone 4 and iPad. I don't have an iPad yet (because Apple forgot my country), so I have to test it on simulator.
I have a method that needs to grab the contents of the main screen as a CGImageRef.
I have this method:
- (CGImageRef)takeScreenshot {
UIWindow *theScreen = [[UIApplication sharedApplication].windows objectAtIndex:0];
UIGraphicsBeginImageContext(theScreen.frame.size);
[[theScreen layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenshot.CGImage;
}
When I compile and test the iPhone version of my app for the iPhone, it works perfectly. But when I compile and test the iPad version on iPad simulator, it returns a black screen.
For it to work, I have to change the "objectAtIndex:0" to "objectAtIndex:1" on the second line.
Is there any logic for this or it is just a simulator bug? As far as I know, index 0 is always the main screen.
Is there any other way to capture the main screen content from another class?
thanks in advance.
Maybe use the keyWindow to get the correct window directly?
UIWindow *theScreen = [[UIApplication sharedApplication] keyWindow];
For the country problem - consider ordering one from another country. ;-)
I'd like to get the image that is being displayed on the UIImagePickerController when user uses the camera. And when I get I want to process the image and display instead of regular camera view.
But the problem is when I want to get the camera view, the image is just a black rectangle.
Here's my code:
UIView *cameraView = [[[[[[imagePicker.view subviews] objectAtIndex:0]
subviews] objectAtIndex: 0]
subviews] objectAtIndex: 0];
UIGraphicsBeginImageContext( CGSizeMake(320, 427) );
[cameraView.layer renderInContext: UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageToDisplay.image = [PixelProcessing processImage: viewImage]; //In this case the image is black
//imageToDisplay.image = viewImage; //In this case the image is black too
//imageToDisplay.image = [UIImage imageNamed: #"icon.png"]; //In this case image is being displayed properly
What am I doing wrong?
Thanks.
This one is also working quite good. Use it when the camera preview is open:
UIImage *viewImage = [[(id)objc_getClass("PLCameraController")
performSelector:#selector(sharedInstance)]
performSelector:#selector(_createPreviewImage)];
But as far as I found out it brings the same results than the following solution which takes a 'screenshot' of the current screen:
extern CGImageRef UIGetScreenImage();
CGImageRef cgoriginal = UIGetScreenImage();
CGImageRef cgimg = CGImageCreateWithImageInRect(cgoriginal, rect);
UIImage *viewImage = [UIImage imageWithCGImage:cgimg];
CGImageRelease(cgoriginal);
CGImageRelease(cgimg);
A problem I didn't still find a fix for is, how can one get the camera image very fast without any overlays?
The unofficial call is:
UIGetScreenImage()
which you declare above the #implementation as:
extern CGImageRef UIGetScreenImage();
There may be a documented way to do this in 3.1, but I'm not sure. If not, please please file a Radar with Apple asking them to make some kind of screen grab access public!!!
That uses your same AppleID you log in to the iPhone development portal with.
Update: This call is not yet documented, but Apple explicitly has given the OK to use it with App Store apps.
at least for now, there's no way to do this. (certainly no official documented way, and as far as I know nobody's figured out an unofficial way either.)
the camera preview data is being drawn by the OS in some way that bypasses the normal graphics methods.
with fw 2.2 i was able to get a screenshot using the private method _createCGImageRefRepresentationInFrame of UIWindow. In 3.0 doesn't exist anymore.
I used that method with the PLCameraView over a window to take a small video just by get as much screenshot as possible. Now i tried with the CALayer of the PLPreviewView and -renderInContext: method, but it always render the view as it has the iris closed.
How can i take a screenshot of what the cameraView is showing?
Thanks
Marco
Try for following code snippet to get
CGImageRef imageRef = [[UIApplication sharedApplication] _createDefaultImageSnapshot];
UIImage* img = [UIImage imageWithCGImage:imageRef];
//Now you can save it the way you want
//May as following
//oops yes this image is just the screenshot so better take care of unwanted image side
//So cut crap out from the image captured
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);
I need to capture a screen shot of a video playing in mpmovieplayer controller, but all I get is a red screen (I made the coverView with red background and 0.5 alpha).
Here is the code:
NSArray *windows = [[UIApplication sharedApplication] windows];
if ([windows count] > 1)
{
UIWindow *moviePlayerWindow = [[UIApplication sharedApplication] keyWindow];
UIView *coverView = [[UIView alloc] initWithFrame:moviePlayerWindow.bounds];
[mainController.moviePlayer pause]; //Without that it won't work either!
coverView.backgroundColor = [UIColor redColor];
coverView.alpha = 0.5;
[moviePlayerWindow addSubview:coverView];
UIGraphicsBeginImageContext(coverView.bounds.size);
[coverView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenShot;
screenShot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(screenShot, self, nil, nil);
}
Any ideas???
Thanks
I was curious about his myself. I believe there are similar issues with taking screenshots of OpenGL stuff too.
If you look at this blog post http://getsetgames.com/2009/07/30/5-ways-to-take-screenshots-of-your-iphone-app/, they have a method that works for an EAGLView, it might be worth giving it a go for your issue.
Follow up to the question:
Recently I have a project that requires the functionality that was asked in this thread again, and I am glad to say there is already an apple provided solution to this. I am posting this so that people that visit this thread can get an answer.
MPMoviePlayerController now has a method that return a UIImage of the moment you want to capture.
- (UIImage *)thumbnailImageAtTime:(NSTimeInterval)playbackTime timeOption:(MPMovieTimeOption)option
Just put in the playbackTime you want to capture, and bingo, UIImage.
Looking at your codes, I would like to advise that you should look for an alternative method of getting the image rather than from the mpmovieplayer itself. The reason being that the method you are using is a private framework code, and second, getting screenshots off a video is highly prone to crashes.
Instead of getting a screenshot from the video, how about tagging the video beforehand? The codes looks highly vulnerable to an app rejection by apple.
Sounds like you're taking a shot of the video overlay mask
http://en.wikipedia.org/wiki/Hardware_overlay