Why does my programmatically created screenshot look so bad on iOS 7?
Asked Answered
M

5

29

I am trying to implement sharing app with facebook. I used this code to take the screenshot:

CGSize imageSize = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
UIGraphicsBeginImageContext(imageSize);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

It works great on iOS 6, but in iOS 7 the image looks very bad. I used this answer: iOS: what's the fastest, most performant way to make a screenshot programmatically? for trying to fix it, and it helped, still the screenshot looks bad. The screen gets another color, and some objects (like labels) aren't showing on the image taken. Any help?

----Update----

I managed to solve the most objects, by change them to retain instead of weak. My main problem remained my tableview, that shown as a big white block (It supposed to be transparent, with labels with white text, so all we see is white cells). I did try to define the table background as clearcolor,not helps..

----Last Update---

There are wonderful answers here that not really regarding to my issue.. I wanted to make it work on device that runs with iOS7 but without using iOS7 SDK, since it takes to much effort to switch the project SDK in this point, when the project is almost done.

Anyway, I added the peace of code that finally solved my issue:

This change simply solve the problem:

UIGraphicsBeginImageContextWithOptions(imageSize, NO , 0.0f);

instead of:

UIGraphicsBeginImageContext(imageSize);
Mossbunker answered 23/9, 2013 at 10:8 Comment(0)
E
55

New API has been added since iOS 7, that should provide efficient way of getting snapshot

  • snapshotViewAfterScreenUpdates: renders the view into a UIView with unmodifiable content

  • resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets : same thing, but with resizable insets

  • drawViewHierarchyInRect:afterScreenUpdates: : same thing if you need all subviews to be drawn too (like labels, buttons...)

You can use the UIView returned for any UI effect, or render in into an image like you did if you need to export.

I don't know how good this new method performs VS the one you provided (although I remember Apple engineers saying this new API was more efficient)

Ela answered 23/9, 2013 at 10:20 Comment(7)
Thanks for this nice answer. My app is not compatible to iOS 7 SDK now. I have no time to make all necessary changes and replace all deprecated classes. I am running my app on iOS7 with iOS 6 SDK. The only problem I met in the all app, is this screenshot. Do you have an idea what should I do ?Mossbunker
I think, 1 problem with your current code might be that is doesn't take the scale (is the device Retina ?) into account. you could use UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0) (last parameter is the scale of the image, setting 0.0 ensures the function chooses the scale of the device main's screen)Ela
Your comment is the most close to the solution i finnaly used :)Mossbunker
@Vinzzz, thank you for your answer, I think your method can be used to capture screenshot inside my app own, but if I want to capture screenshot of the entire screen no matter which app is active, including the home screen, what can I do.In fact my app is a jailbreak tweak app running inside SpringBoard, I want to capture the screenshot for any app active.Goggin
@Goggin : in this case, this depends on what the jailbreak you use provide. Apple offers no API (that I know of) to access other apps UI.Ela
Above code works well but when try downscale the image little bit the uilabels are blurred even if i maintain the aspect ratio for resizing? what is the reason?Bryson
@Suge, I need same scenario in my app, whatever app is active, i want to capture current device screen. Have you get any solution?Carvajal
H
30

you can try this

- (UIImage *) screenshot {
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);

    [self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
Hecto answered 25/9, 2013 at 1:27 Comment(4)
The same as the first answer here, this is new iOS 7 API. My app is far from be supported iOS 7 SDK. It will in future, but I am need a solution now :)Mossbunker
How to take screenshot at any view of iOS not only inside my app?Goggin
[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES]; Would make the whole screen flicker in my case on iPhone 6. And I have to use "[self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:NO];" instead. Why is that so ?Thumbprint
Scale is important for best qualityShell
D
6

in iOS 8 : this is how i am doing to get ScreenShot

  1. just added one UIImageView and Method to take screenshot in .h file

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

 -(IBAction)takeSnapShot:(id)sender;

2 added code snip for taking screen shot and set on UIImageView in .m file

- (IBAction)takeSnapShot:(id)sender
{
    UIGraphicsBeginImageContext(self.view.bounds.size);
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *snapShotImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    imageView.image = snapShotImage;
}
  1. below is the output i got.

enter image description here

Descendant answered 30/1, 2015 at 12:31 Comment(0)
B
5

On iOS7 you can have glitches if you use

[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES]

during ongoing animation. Set afterScreenUpdates = NO to get rid of glitches.

Briny answered 29/10, 2013 at 15:26 Comment(1)
THANK YOU! I was going insane for the last 3 hours with weird glitches whenever I captured the screen. My code was being called in applicationDidEnterBackground: and it caused any animations to freeze up upon returning to the app.Spinozism
C
0

Make sure that opaque is set to NO

Chemaram answered 26/9, 2013 at 11:10 Comment(1)
renderInContext is pure CPU composition and rendering and it treats opacity flags differently than the regular OpenGL based composition engineChemaram

© 2022 - 2024 — McMap. All rights reserved.