The standard snapshot technique is drawHierarchy(in:afterScreenUpdates:) , which draws this in the context of the image. In iOS 10 and later, you can use UIGraphicsImageRenderer :
extension UIView { /// Create image snapshot of view. /// /// - Parameters: /// - rect: The coordinates (in the view 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 hierarchys 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 would use it like this:
let image = webView.snapshot(of: rect)
Prior to iOS 10, you would like to get a portion of the image, you can use the cropping(to:) CGImage cropping(to:) method. For instance:
extension UIView { /// Create snapshot /// /// - Parameters: /// - rect: The coordinates (in the view 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 hierarchys 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 handy statement:
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 }
To play Swift 2, see the previous version of this answer .