How to take screenshot of UIScrollView visible area?

前端 未结 8 1615
鱼传尺愫
鱼传尺愫 2021-02-13 16:57

How do I take a 1:1 screenshot of UIScrollView visible area? The content may be larger or smaller than UIScrollView bounds as well as half-hidden (I\'ve implemented custom scrol

相关标签:
8条回答
  • 2021-02-13 17:28

    Another approach would be to use the contentOffset to adjust the layer's visible area and capture only the currently visible area of UIScrollView.

    UIScrollView *contentScrollView;....//scrollview instance
    
    UIGraphicsBeginImageContextWithOptions(contentScrollView.bounds.size, 
                                           YES, 
                                           [UIScreen mainScreen].scale);
    
    //this is the key
    CGPoint offset=contentScrollView.contentOffset;
    CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -offset.x, -offset.y); 
    
    [contentScrollView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *visibleScrollViewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    

    Cheers :)

    0 讨论(0)
  • 2021-02-13 17:29

    I've found a solution myself - I took screenshot of the whole view and then crop it to the size and position of UIScrollView frame.

    -(UIImage *)imageFromCombinedContext:(UIView *)background 
    {
          UIImage *image;
          CGSize size = self.view.frame.size;
          UIGraphicsBeginImageContext(size);
          [background.layer affineTransform];
          [self.view.layer.layer renderInContext:UIGraphicsGetCurrentContext()];
          image = UIGraphicsGetImageFromCurrentImageContext();
          UIGraphicsEndImageContext();
          CGImageRef imgRef = CGImageCreateWithImageInRect([image CGImage],background.frame);
          image = [UIImage imageWithCGImage:imref];
          CGImageRelease(imref);
          return image;
    }
    
    0 讨论(0)
  • 2021-02-13 17:29

    @Abduliam Rehmanius's answer has poor performance, since if the UIScrollView contains a large content area, we will draw that entire content area (even outside the visible bounds). @Concuror's answer has the issue that it will also draw anything that is on top of the UIScrollView.

    My solution was to put the UIScrollView inside a UIView called containerView with the same bounds and then render containerView:

    containerView.renderInContext(context)
    
    0 讨论(0)
  • 2021-02-13 17:30

    Update swift 3+, 4 on @Concuror code

    func getImage(fromCombinedContext background: UIView) -> UIImage {
            var image: UIImage?
            let size: CGSize = view.frame.size
            UIGraphicsBeginImageContext(size)
            background.layer.affineTransform()
            view.layer.render(in: UIGraphicsGetCurrentContext()!)
            image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            let imgRef = image?.cgImage?.cropping(to: background.frame)
            image = UIImage(cgImage: imgRef!)
            // CGImageRelease(imgRef!) // Removing on Swift - 'CGImageRelease' is unavailable: Core Foundation objects are automatically memory managed
            return image ?? UIImage()
        }
    
    0 讨论(0)
  • 2021-02-13 17:34

    Jeffery Sun has the right answer. Just put your scroll view inside another view. Get container view to render in context. done.

    In the code below, cropView contains the scroll view to be captured. The solution is really just that simple.

    As I understand the question and why I found this page, the whole content of the scroll view isn't wanted - just the visible portion.

    func captureCrop() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.cropView.frame.size, true, 0.0)
        self.cropView.layer.renderInContext(UIGraphicsGetCurrentContext())
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image;
    }
    
    0 讨论(0)
  • 2021-02-13 17:35

    Swift version of Abduliam Rehmanius answer.

    func screenshot() -> UIImage {
    
            UIGraphicsBeginImageContextWithOptions(self.scrollCrop.bounds.size, true, UIScreen.mainScreen().scale);
            //this is the key
            let offset:CGPoint = self.scrollCrop.contentOffset;
            CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -offset.x, -offset.y);
            self.scrollCrop.layer.renderInContext(UIGraphicsGetCurrentContext()!);
            let visibleScrollViewImage: UIImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            return visibleScrollViewImage;
        }
    

    Swift 4 version:

    func screenshot() -> UIImage {
    UIGraphicsBeginImageContextWithOptions(self.scrollCrop.bounds.size, false, UIScreen.main.scale)
            let offset = self.scrollCrop.contentOffset
            let thisContext = UIGraphicsGetCurrentContext()
            thisContext?.translateBy(x: -offset.x, y: -offset.y)
            self.scrollCrop.layer.render(in: thisContext!)
            let visibleScrollViewImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    return visibleScrollViewImage
    }
    
    0 讨论(0)
提交回复
热议问题