Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

renderInContext does not work correctly when changing layer Z position

My application allow user to switch UIImageView back and front and then user can capture that screen. Here is my code to capture the screen into UIImage

-(UIImage *)imageWithView:(UIView *)view
{
   UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 2.0f);

// I even tried view.layer.presentationLayer but still not working
[view.layer renderInContext:UIGraphicsGetCurrentContext()];

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


return image;

}

I do not use [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES] because it is slower and sometimes (when view is not visible) drawn the screenshot in black.

But problem with renderInContext is the Z position that change between UIImageView ( imageView.layer.zPosition = 0.01;etc ). In my iPhone screen this work correctly when I assigned value to zPosition but in the capture screen it turns out wrong.

Are there anyway I can resolve this problem ? Thanks in advance

Edited: Here is what I tried to do before capture the screenshot. I use this code to make one ImageView display in front of another one.

-(void)bringOneLevelUp:(UIImageView*)imageView
{
//_imgArray is sorted by Z position order (small to big)
    NSUInteger currentObjectIndex = [_imgArray indexOfObject:imageView];


if(currentObjectIndex+1< _imgArray.count){

UIImageView *upperImageView = [_imgArray objectAtIndex:currentObjectIndex+1];


    CGFloat currentZIndex = imageView.layer.zPosition;
    CGFloat upperZIndex= upperImageView.layer.zPosition;

    imageView.layer.zPosition = upperZIndex;
    upperImageView.layer.zPosition = currentZIndex;


// swap position in array 
[_imgArray exchangeObjectAtIndex:currentObjectIndex withObjectAtIndex:currentObjectIndex+1];

}

}

And liked I explained earlier the result of this code in the phone screen is correct. The newImageView is in front of lastImageView. But when I captured screenshot by renderInContext. They are not.

like image 446
Kong Hantrakool Avatar asked Apr 27 '26 15:04

Kong Hantrakool


1 Answers

Swift 4.2

The answer of @RameshVel worked for me translating it to Swift, maybe someone needs this:

 UIGraphicsBeginImageContext(drawingCanvas.frame.size)
 self.renderInContext(ct: UIGraphicsGetCurrentContext()!)

 guard let image = UIGraphicsGetImageFromCurrentImageContext() else {return}
 UIGraphicsEndImageContext()

And in the renderInContext function:

 func renderInContext(ct:CGContext){

    ct.beginTransparencyLayer(auxiliaryInfo: nil)

    // descendant ordered list of views based on its z-position
    let orderedLayers = self.view.subviews.sorted(by: {
        $0.layer.zPosition < $1.layer.zPosition
    })

    for l in orderedLayers {
        l.layer.render(in: ct)
    }
    ct.endTransparencyLayer()
}

The same can be donde with CALayers if you are drawing and adding layers:

 UIGraphicsBeginImageContext(drawingCanvas.frame.size)
 //Canvas is a custom UIView for drawing
 self.renderInContext(ct: UIGraphicsGetCurrentContext()!, canvas: canvas)

 guard let image = UIGraphicsGetImageFromCurrentImageContext() else {return}
 UIGraphicsEndImageContext()

renderInContext function:

func renderInContext(ct:CGContext, canvas:CustomCanvas){

    ct.beginTransparencyLayer(auxiliaryInfo: nil)
    let layers:[CALayer] = canvas.layer.sublayers!

    let orderedLayers = layers.sorted(by: {
        $0.zPosition < $1.zPosition
    })

    for v in orderedLayers {
        v.render(in: ct)
    }
    ct.endTransparencyLayer()
}
like image 50
Ernest Avatar answered Apr 29 '26 06:04

Ernest