Search code examples
iphonecocoa-touchuiimagecore-animationcore-graphics

When taking screenshot by drawing UIView over UIImage with renderInContext my UIImage is not displayed


I'm using the sample code from http://developer.apple.com/library/ios/#qa/qa1714/_index.html almost verbatim and I can save my background image or my overlay but I can't combine the two. When I try and combine them using the following code the overlay renders the background white and I'm assuming its overwriting the background. Any idea why this is?

Here is my method which tries to combine the view overlay with the image:

-(void) annotateStillImage
{
    UIImage *image = stillImage;

    // Create a graphics context with the target size
    CGSize imageSize = [[UIScreen mainScreen] bounds].size;
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);

    CGContextRef context = UIGraphicsGetCurrentContext();


    // Draw the image returned by the camera sample buffer into the context. 
    // Draw it into the same sized rectangle as the view that is displayed on the screen.
    UIGraphicsPushContext(context);

    [image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
    UIGraphicsPopContext();

    // -renderInContext: renders in the coordinate space of the layer,
    // so we must first apply the layer's geometry to the graphics context
    CGContextSaveGState(context);
    // Center the context around the window's anchor point
    CGContextTranslateCTM(context, [[self view] center].x, [[self view] center].y);
    // Apply the window's transform about the anchor point
    CGContextConcatCTM(context, [[self view] transform]);
    // Offset by the portion of the bounds left of and above the anchor point
    CGContextTranslateCTM(context,
                          -[[self view] bounds].size.width * [[[self view] layer] anchorPoint].x,
                          -[[self view] bounds].size.height * [[[self view] layer] anchorPoint].y);

    // Render the layer hierarchy to the current context
    [[[self view] layer] renderInContext:context];

    // Restore the context
    CGContextRestoreGState(context);

    // Retrieve the screenshot image containing both the camera content and the overlay view
    stillImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
}

Here is a snippet of my method which creates the view in case that's relevant:

CGRect layerRect = [[[self view] layer] bounds];
[[self previewLayer] setBounds:layerRect];
[[self previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),  CGRectGetMidY(layerRect))];
[[[self view] layer] addSublayer:[self previewLayer]];

UIButton *overlayButton = [UIButton buttonWithType:UIButtonTypeCustom];
[overlayButton setImage:[UIImage imageNamed:@"acceptButton.png"] forState:UIControlStateNormal];
[overlayButton setFrame:[self rectForAcceptButton] ];
[overlayButton setAutoresizesSubviews:TRUE];
[overlayButton setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin];
[overlayButton addTarget:self action:@selector(acceptButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[[self view] addSubview:overlayButton];

I'm expecting the image in the annotate method to be the background and the accept button from the view drawing to be added on top. All I get is the accept button and a white background but if I don't run the renderInContext method all I get is the image background and no overlay.

Thanks!


Solution

  • Turns out I was adding the overlay to the same view as the preview layer rather than having it on its own view. I realized this by reviewing this great project which covers all types of screenshots possible: https://github.com/cocoacoderorg/Screenshots

    Fix was to create a separate overlay view in IB with a transparent background and add my overlay elements to this.