How to take screenshot of portion of UIView?

后端 未结 2 975
时光取名叫无心
时光取名叫无心 2020-12-08 12:02

I want the user to go on my app and take a screenshot of the app after pressing a button programmatically in Swift. I know that UIGraphicsGetImageFromCurrentImageConte

相关标签:
2条回答
  • 2020-12-08 12:42

    This is a previously asked question at How to capture UIView to UIImage without loss of quality on retina display but to expand in swift (2.3):

    extension UIView {
    
        class func image(view: UIView) -> UIImage? {
            UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0)
            guard let ctx = UIGraphicsGetCurrentContext() else {
                return nil
            }
            view.layer.renderInContext(ctx)
            let img = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return img
        }
    
        func image() -> UIImage? {
            return UIView.image(self)
        }
    }
    

    So you can either get an image from a view with UIView.image(theView) or by asking the view itself let viewImage = self.view.image()

    Do bear in mind though that this is rough and probably needs further looking at for thread safety etc....

    0 讨论(0)
  • 2020-12-08 12:44

    The standard snapshot technique is drawHierarchy(in:afterScreenUpdates:), drawing that to an image context. In iOS 10 and later, you can use UIGraphicsImageRenderer:

    extension UIView {
    
        /// Create image snapshot of view.
        ///
        /// - Parameters:
        ///   - rect: The coordinates (in the view's own coordinate space) to be captured. If omitted, the entire `bounds` will be captured.
        ///   - afterScreenUpdates: A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the value false if you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes. Defaults to `true`.
        ///
        /// - Returns: The `UIImage` snapshot.
    
        func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
            return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { _ in
                drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
            }
        }
    }
    

    And you’d use that like so:

    let image = webView.snapshot(of: rect)
    

    Prior to iOS 10, you would to get portion of an image, you can use CGImage method cropping(to:). E.g.:

    extension UIView {
    
        /// Create snapshot
        ///
        /// - Parameters:
        ///   - rect: The coordinates (in the view's own coordinate space) to be captured. If omitted, the entire `bounds` will be captured.
        ///   - afterScreenUpdates: A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the value false if you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes. Defaults to `true`.
        ///
        /// - Returns: Returns `UIImage` of the specified portion of the view.
    
        func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage? {
            // snapshot entire view
    
            UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
            drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
            let wholeImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            // if no `rect` provided, return image of whole view
    
            guard let image = wholeImage, let rect = rect else { return wholeImage }
    
            // otherwise, grab specified `rect` of image
    
            guard let cgImage = image.cgImage?.cropping(to: rect * image.scale) else { return nil }
            return UIImage(cgImage: cgImage, scale: image.scale, orientation: .up)
        }
    
    }
    

    Which uses this little convenient operator:

    extension CGRect {
        static func * (lhs: CGRect, rhs: CGFloat) -> CGRect {
            return CGRect(x: lhs.minX * rhs, y: lhs.minY * rhs, width: lhs.width * rhs, height: lhs.height * rhs)
        }
    }
    

    And to use it, you can do:

    if let image = webView.snapshot(of: rect) {
        // do something with `image` here
    }
    

    For Swift 2 rendition, see previous revision of this answer.

    0 讨论(0)
提交回复
热议问题