0

I try to record a screenshot programatically. On the simulator the code snipped works like a charm, but on the iPad it only returns a blank page:

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIGraphicsBeginImageContextWithOptions(keyWindow.frame.size, NO, 0);

UIView* screenshotView = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES];

[screenshotView drawViewHierarchyInRect:keyWindow.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

The following line should return a view (including the statusbar). It works on the simulator but on a real device this view is empty.

UIView* screenshotView = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES];

What' the reason ? Thanks in advance.

belafarinrod91
  • 323
  • 7
  • 17

2 Answers2

0

If you want to get the UIImage object do not call snapshotViewAfterScreenUpdates API, simply call drawViewHierarchyInRect API on keyWindow, but if you want the view already drawn with the image then call snapshotViewAfterScreenUpdates, there you don't need to call drawViewHierarchyInRect API

Mousam
  • 63
  • 6
  • This solution has two problems: on the one hand the status bar is not captured and on the other hand the orientation of the picture is incorrect. Is there any chance to fix this ? – belafarinrod91 Jul 10 '15 at 13:57
  • IF you want status bar as well, call the snapshotViewAfterScreenUpdates on [UIScreen mainScreen]. The point I am trying to make is "do not call drawViewHierarchyInRect on screenshotView as screenshotView is view already drawn with the image. Hence if you want pre rendered view call snapshotViewAfterScreenUpdates API but not drawViewHierarchyInRect but if you want UIImage object call drawViewHierarchyInRect but not snapshotViewAfterScreenUpdates. – Mousam Jul 10 '15 at 14:24
  • `[[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES/NO]` returns just a blank page. No differences ... and yes I want to include the statusbar to the screenshot. – belafarinrod91 Jul 10 '15 at 15:01
  • What is the iOS version you are testing on, I tested it on iPhone (iOS 7.1) and its working fine. [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:YES] – Mousam Jul 11 '15 at 12:08
  • The device has iOS 8.3 and the app is built with iOS 7.1 ... (I think the simulator also has iOS 7.1) – belafarinrod91 Jul 11 '15 at 16:32
0

For anybody who is looking for the correct answer:

NSMutableArray* windows = [[[UIApplication sharedApplication] windows] mutableCopy];

NSString *statusBarString = [NSString stringWithFormat:@"_statusBarWindow"];
UIWindow* statusBarWindow =  [[UIApplication sharedApplication] valueForKey:statusBarString];

/*CGRect statusBarFrame = statusBarWindow.frame;
statusBarFrame.origin.x -= 20;
statusBarFrame.origin.y -= 20;
[statusBarWindow setFrame:statusBarFrame];*/
//statusBarWindow.backgroundColor = [UIColor blackColor];
[windows addObject:statusBarWindow];
[statusBarWindow release];



UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
for (UIWindow *window in windows) {
    CGContextSaveGState(context);
    CGContextTranslateCTM(context, window.center.x, window.center.y);
    CGContextConcatCTM(context, window.transform);
    CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
    if (orientation == UIInterfaceOrientationLandscapeLeft) {
        CGContextRotateCTM(context, M_PI_2);
        if(![window isKindOfClass:[UIStatusBarWindow class]])
        {
            CGContextTranslateCTM(context, 20, -imageSize.width+20);
        }
        else
        {
            CGContextTranslateCTM(context, 0, -imageSize.width);
        }
    } else if (orientation == UIInterfaceOrientationLandscapeRight) {
        CGContextRotateCTM(context, -M_PI_2);
        if(![window isKindOfClass:[UIStatusBarWindow class]])
        {
            CGContextTranslateCTM(context, -imageSize.height+20, 20);
        }
        else
        {
            CGContextTranslateCTM(context, -imageSize.height, 0);
        }
    } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
        CGContextRotateCTM(context, M_PI);
        if(![window isKindOfClass:[UIStatusBarWindow class]])
        {
            CGContextTranslateCTM(context, -imageSize.width+20, -imageSize.height+20);
        }
        else
        {
            CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
        }
    }
    if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
        [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
    } else {
        [window.layer renderInContext:context];
    }
    CGContextRestoreGState(context);
}

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

The answer is taken from here - with the solution above you are allowed to capture the statusbar as well.

PS: check the code for the right orientation and size of the screenshot ...

Community
  • 1
  • 1
belafarinrod91
  • 323
  • 7
  • 17