Answered Aug 22, 2014 · 88 votes
Instead of just throwing the answer out there, let me explain what your current code does and how to modify it to capture the full screen.
UIGraphicsBeginImageContext(view.frame.size)-
This line of code creates a new image context with the same size as view. The main thing to take away here is that the new image context is the same size as view
. Unless you want to capture a low resolution (non-retina) version of your application, you should probably be using UIGraphicsBeginImageContextWithOptions instead. Then you can pass 0.0 to get the same scale factor as the devices main screen.
view.layer.renderInContext(UIGraphicsGetCurrentContext())-
This line of code will render the view's layer into the current graphics context (which is the context you just created). The main thing to take away here is that only view (and its subviews) are being drawn into the image context.
let image = UIGraphicsGetImageFromCurrentImageContext()-
This line of code creates an UIImage object from what has been drawn into the graphics context.
UIGraphicsEndImageContext()-
This line of code ends the image context. It's clean up (you created the context and should remove it as well.
The result is an image that is the same size as view, with view and its subviews drawn into it.
If you want to draw everything into the image, then you should create an image that is the size of the screen and draw everything that is on screen into it. In practice, you are likely just talking about everything in the "key window" of your application. Since UIWindow is a subclass of UIView, it can be drawn into a image context as well.
Answered Mar 28, 2018 · 71 votes
/// Takes the screenshot of the screen and returns the corresponding image /// /// - Parameter shouldSave: Boolean flag asking if the image needs to be saved to user's photo library. Default set to 'true' /// - Returns: (Optional)image captured as a screenshot open func takeScreenshot(_ shouldSave: Bool = true) -> UIImage? { var screenshotImage :UIImage? let layer = UIApplication.shared.keyWindow!.layer let scale = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale); guard let context = UIGraphicsGetCurrentContext() else {return nil} layer.render(in:context) screenshotImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() if let image = screenshotImage, shouldSave { UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil) } return screenshotImage }
The code you provide works but doesn't allow you to capture the NavigationBar and the StatusBar in your screenshot. If you want to take a screenshot of your device that will include the NavigationBar, you have to use the following code:
func screenShotMethod() { let layer = UIApplication.sharedApplication().keyWindow!.layer let scale = UIScreen.mainScreen().scale UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale); layer.renderInContext(UIGraphicsGetCurrentContext()!) let screenshot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil)}
- The first time you launch the app and call this method, the iOS device will ask you the permission to save your image in the camera roll.
- The result of this code will be a .JPG image.
- ["The StatusBar "," will not appear in the final image."]
Answered Feb 26, 2020 · 44 votes
- Xcode 9.3, Swift 4.1
- Xcode 10.2 (10E125) and 11.0 (11A420a), Swift 5
Tested on iOS: 9, 10, 11, 12, 13
import UIKit-extension UIApplication {- func getKeyWindow() -> UIWindow? { if #available(iOS 13, *) { return windows.first { $0.isKeyWindow } } else { return keyWindow } } func makeSnapshot() -> UIImage? { return getKeyWindow()?.layer.makeSnapshot() }}extension CALayer { func makeSnapshot() -> UIImage? { let scale = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(frame.size, false, scale) defer { UIGraphicsEndImageContext() } guard let context = UIGraphicsGetCurrentContext() else { return nil } render(in: context) let screenshot = UIGraphicsGetImageFromCurrentImageContext() return screenshot }}extension UIView { func makeSnapshot() -> UIImage? { if #available(iOS 10.0, *) { let renderer = UIGraphicsImageRenderer(size: frame.size) return renderer.image { _ in drawHierarchy(in: bounds, afterScreenUpdates: true) } } else { return layer.makeSnapshot() } }}extension UIImage { convenience init?(snapshotOf view: UIView) { guard let image = view.makeSnapshot(), let cgImage = image.cgImage else { return nil } self.init(cgImage: cgImage, scale: image.scale, orientation: image.imageOrientation) }}
imageView.image = UIApplication.shared.makeSnapshot()-// orimageView.image = view.makeSnapshot()// orimageView.image = view.layer.makeSnapshot()// orimageView.image = UIImage(snapshotOf: view)
import UIKit-extension UIApplication {- var screenShot: UIImage? { if let layer = keyWindow?.layer { let scale = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale); if let context = UIGraphicsGetCurrentContext() { layer.render(in: context) let screenshot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return screenshot } } return nil }}
If you will try to use Version 1 code in iOS 9x you will have error: CGImageCreateWithImageProvider: invalid image provider: NULL.
import UIKit-extension UIApplication {- var screenShot: UIImage? { if let rootViewController = keyWindow?.rootViewController { let scale = UIScreen.main.scale let bounds = rootViewController.view.bounds UIGraphicsBeginImageContextWithOptions(bounds.size, false, scale); if let _ = UIGraphicsGetCurrentContext() { rootViewController.view.drawHierarchy(in: bounds, afterScreenUpdates: true) let screenshot = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return screenshot } } return nil }}
let screenShot = UIApplication.shared.screenShot!-