1

I want to take a screenshot. In this screenshot, I want the text and image in it. However, I am having an issue because when I take a screenshot, I only see the text but not the image.

I think the problem is that clearContainerView only contains the text but not the image. I can't put the image inside of clearContainerView because I want the image to stretch the entire screen... and I want the text centered between the title and tab bar (as shown with green square above).

My code and pictures are below:

This is my current layout in Storyboard: enter image description here

This is what I want a screenshot of: enter image description here

This is the screenshot that I get: enter image description here

This is my code:

@IBOutlet weak var clearContainerView: UIView!

@IBAction func takeScreenshotTapped(_ sender: UIButton) {
    let screenshot = clearContainerView.screenshot()
    print(screenshot)
}

extension UIView {
    func screenshot() -> UIImage {
        let image = UIGraphicsImageRenderer(size: bounds.size).image { _ in
            drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
        }

        return image
    }
}

Any suggestions on how to do this?

JEL
  • 1,540
  • 4
  • 23
  • 51
  • @AshishKakkad No, the background image is not inside the UIView called `clearContainerView`. Please read the last paragraph for explanation. – JEL Mar 06 '19 at 04:29
  • @AshishKakkad Please read again, this is not a duplicate. – JEL Mar 06 '19 at 04:30
  • you need to put that image inside your clearContainer. because you are taking a snapshot of clearContainer and that code can only capture contents of clearContainer only – Sahil Manchanda Mar 06 '19 at 04:33
  • 1
    @SahilManchanda Please read my question, it says this: "I think the problem is that `clearContainerView` only contains the text but not the image. I can't put the image inside of `clearContainerView` because I want the image to stretch the entire screen... and I want the text centered between the title and tab bar (as shown with green square above)." Does that make sense to you? Thanks – JEL Mar 06 '19 at 04:34
  • I'll give it a try and let you know if that works – Sahil Manchanda Mar 06 '19 at 04:40
  • @SahilManchanda Ok thanks! Please see my Storyboard screenshot above because it shows you my view hierarchy. – JEL Mar 06 '19 at 04:41
  • Take screen shot of full screen then crop the image with frame of your clearContainerView – Prashant Tukadiya Mar 06 '19 at 05:38
  • @JEL Please Check my answer. it's working I made it right now. – Nikunj Kumbhani Mar 06 '19 at 07:39

6 Answers6

1

You can use the following method on your controller view to get the portion of clearContainerView which will be a snapshot view. Then you can use that view object and take a screenshot of it.

resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:

You have to pass the rect which will is your clearContainerView frame. You can pass zero insets in case you don't want any stretchable content. It return a view object which will contain your imageView portion + your complete clearContainerView. Then you can use the returned view and take its screen shot.

I tried with the following.

My original view.

enter image description here

The screenshot

enter image description here

1

Use this extension.

//USAGE



 let image = self.view.snapshot(of:self.<your view>.frame) 

Here "your view" should be the base view from the hierarchy or your can simply use

 let image = self.view.snapshot(of:self.view.frame)

Extension

// UIView screenshot
extension UIView {

    /// Create snapshot
    ///
    /// - parameter rect: The `CGRect` of the portion of the view to return. If `nil` (or omitted),
    ///                   return snapshot of the whole view.
    ///
    /// - returns: Returns `UIImage` of the specified portion of the view.

    func snapshot(of rect: CGRect? = nil) -> UIImage? {
        // snapshot entire view

        UIGraphicsBeginImageContextWithOptions(bounds.size,  false, 0.0)
        drawHierarchy(in: bounds, afterScreenUpdates: true)
        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

        let scale = image.scale
        let scaledRect = CGRect(x: rect.origin.x * scale, y: rect.origin.y * scale, width: rect.size.width * scale, height: rect.size.height * scale)
        guard let cgImage = image.cgImage?.cropping(to: scaledRect) else { return nil }
        return UIImage(cgImage: cgImage, scale: scale, orientation: .up)
    }

}
SAIF
  • 126
  • 8
0

Main Code:

let frame = containerView.frame
let x: CGFloat = 0
let y = frame.minY.pointsToPixel()
let width = frame.width.pointsToPixel()
let height = frame.height.pointsToPixel()
let rect = CGRect(x: x, y: y, width: width, height: height)
let image = cropImage(image: view.screenshot(), toRect: rect)


extension UIView {
    func screenshot() -> UIImage {
        let image = UIGraphicsImageRenderer(size: bounds.size).image { _ in
            drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
        }

        return image
    }
}
public extension CGFloat {
    func pointsToPixel() -> CGFloat {
        return self * UIScreen.main.scale
    }

}

output: enter image description here

After Screenshot: enter image description here

What I've done: take a screenshot of the whole view with your method and then crop the image by converting CGPoints to pixels.

Sahil Manchanda
  • 9,812
  • 4
  • 39
  • 89
0

You can use the code given below to capture the screenshot. It will capture the whole window not the particular view. But take care of one thing that if you don't want your "Title", "Button" and "Tab Bar" in the screenshot then you need to hide them before the UIGraphicsBeginImageContextWithOptions and show them again after UIGraphicsEndImageContext.

func takeScreenshot() -> UIImage? {
        var screenshotImage: UIImage?
        let layer = UIApplication.shared.keyWindow!.layer
        let scale = UIScreen.main.scale
        // Hide your title label, button and tab bar here
        UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
        guard let context = UIGraphicsGetCurrentContext() else {return nil}
        layer.render(in:context)
        screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        // Unhide your title label, button and tab bar here
        return screenshotImage
}

@IBAction func takeScreenshotTapped(_ sender: UIButton) {
    let screenshot = takeScreenshot()
    print(screenshot)
}
Anshul Bhatheja
  • 673
  • 3
  • 21
0

Everything is fine. I have made a demo for your expected output.

You just need to change your view hierarchy like this:

As pr you say the image if outside of clearContainerView

enter image description here

Code

class VC: UIViewController {

    @IBOutlet weak var mainVw: UIView!
    @IBOutlet weak var clearContainerView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    @IBAction func takeImage(_ sender: Any) {

        if let VC_1 = self.storyboard?.instantiateViewController(withIdentifier: "VC1") as? VC1{
            VC_1.img = mainVw.screenshot()
            self.present(VC_1, animated: false, completion: nil)
        }
    }
}

Output :

enter image description here

Nikunj Kumbhani
  • 3,758
  • 2
  • 26
  • 51
0

Try this! Helper Function

struct UIGraphicsDrawImageHelper {
    static func drawImage(from image: UIImageView) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(image.bounds.size, image.isOpaque, 0.0)
        image.drawHierarchy(in: image.bounds, afterScreenUpdates: false)
        let renderImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return renderImage
    }
}

calling it

guard let image = UIGraphicsDrawImageHelper.drawImage(from: qrcodeImageView) else { return }

ImageView (Clear Container View) is the view that you want to snapshot your screen. you can change it to uiview or whatever is view. Hope this help.

seyha
  • 554
  • 5
  • 16