Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to take screenshot of portion of UIView?

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 UIGraphicsGetImageFromCurrentImageContext() takes a screenshot but I don't want a picture of the entire screen. I want a rectangle to pop up (sort of like a crop tool) and the user can drag and resize the rectangle to take a screenshot of only a certain part of the screen. I want the rectangle to go over a WKWebView and crop a pic of the web view.

like image 335
Chris Avatar asked Sep 02 '16 03:09

Chris


People also ask

How to screenshot a specific area in Windows 10?

If you are using a laptop, you can find it on the top line or the bottom line of the keyboard. The Print Screen can be shown as Print Screenor PrtSc. How to screenshot a specific area in Windows 10? It is very easy: Press the Print Screen Key and you will see a small menu on the top middle side of your computer screen.

How do I take a screenshot on Windows 10 without any software?

Use Windows Snip & Sketch Method 1: Press Win+Print Screen The shortcut combination of Win+Print Screen can capture the full screen of your computer. your computer will flash once after your press Alt+Print Screen and the screenshot will be automatically saved to This PC > Pictures > Screenshots. Method 2: Press Win+Shift+Print Screen

How to screenshot on Windows 10 with Snip & Sketch?

Snip & Sketch is the new utility on Windows 10 to screenshot a specific area. It is more like the compact version of Snipping Tool. Step 1 When you’d like to screenshot a part of screen, hold down Windows + Shift + S on your keyboard. Then the Snip & Sketch bar will show up.

How to take a full screen photo in Windows 10?

Likewise, you can use Windows Snip & Sketch to capture the full screen in Windows 10. You need to use your mouse to select the full screen to capture after you open the tool. If needed, you can use this tool to edit the image.


2 Answers

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.

like image 94
Rob Avatar answered Oct 03 '22 16:10

Rob


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....

like image 23
Adrian Sluyters Avatar answered Oct 03 '22 16:10

Adrian Sluyters