web-dev-qa-db-fra.com

Comment puis-je prendre une capture d'écran en plein écran dans Swift?

J'ai trouvé ce code :

func screenShotMethod() {
    //Create the UIImage
    UIGraphicsBeginImageContext(view.frame.size)
    view.layer.renderInContext(UIGraphicsGetCurrentContext())
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    //Save it to the camera roll
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}

Que dois-je faire pour obtenir tous les autres éléments, tels que la barre de navigation, dans les captures d'écran?

56
Pietro La Spada

Au lieu de simplement donner la réponse, laissez-moi vous expliquer ce que fait votre code actuel et comment le modifier pour capturer tout l'écran.

UIGraphicsBeginImageContext(view.frame.size)

Cette ligne de code crée un nouveau contexte d'image de la même taille que view. La principale chose à retenir ici est que le nouveau contexte d'image est la même taille que view. À moins que vous ne souhaitiez capturer une version basse résolution (sans rétine) de votre application, vous devriez probablement utiliser UIGraphicsBeginImageContextWithOptions à la place. Ensuite, vous pouvez passer 0.0 pour obtenir le même facteur d'échelle que l'écran principal du périphérique. 

view.layer.renderInContext(UIGraphicsGetCurrentContext())

Cette ligne de code rendra la couche de la vue dans le contexte graphique actuel (qui est le contexte que vous venez de créer). La principale chose à retenir ici est que seules view (et ses sous-vues) sont dessinées dans le contexte de l'image.

let image = UIGraphicsGetImageFromCurrentImageContext()

Cette ligne de code crée un objet UIImage à partir de ce qui a été dessiné dans le contexte graphique. 

UIGraphicsEndImageContext()

Cette ligne de code termine le contexte de l'image. C'est le nettoyage (vous avez créé le contexte et vous devriez également le supprimer. 


Le résultat est une image de la même taille que view, avec view et ses sous-vues dessinées.

Si vous souhaitez tout dessiner dans l'image, vous devez créer une image de la taille de l'écran et y dessiner tout ce qui y est affiché. En pratique, vous ne faites probablement que parler de tout ce qui se trouve dans la "fenêtre clé" de votre application. UIWindow étant une sous-classe de UIView, elle peut également être dessinée dans un contexte d'image.

66
David Rönnqvist

Swift 4

    /// 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
    }

Mise à jour pour Swift 2

Le code que vous fournissez fonctionne, mais ne vous permet pas de capturer les NavigationBar et StatusBar dans votre capture d'écran. Si vous voulez prendre une capture d'écran de votre appareil qui inclura la NavigationBar, vous devez utiliser le code suivant:

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)
}

Avec ce code:

  • La première fois que vous lancez l'application et appelez cette méthode, l'appareil iOS vous demandera la permission d'enregistrer votre image dans la pellicule.
  • Le résultat de ce code sera une image .JPG.
  • La StatusBar n'apparaîtra pas dans l'image finale.
49
Imanou Petit

Exemple de Swift 3:

func captureScreen() -> UIImage? {
    guard let context = UIGraphicsGetCurrentContext() else { return .none }
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, UIScreen.main.scale)
    view.layer.render(in: context)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}
21
Daniel Storm

Détails

Xcode 9.3, Swift 4.1

Testé sur iOS: 9, 10, 11

Solution

import UIKit

extension UIApplication {

    var screenShot: UIImage?  {
        return keyWindow?.layer.screenShot
    }
}

extension CALayer {

    var screenShot: UIImage?  {
        let scale = UIScreen.main.scale
        UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)
        if let context = UIGraphicsGetCurrentContext() {
            render(in: context)
            let screenshot = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return screenshot
        }
        return nil
    }
}

Usage

 imageView.image = UIApplication.shared.screenShot

Détails

Xcode 8.2.1, Swift 3

Version 1 pour iOS 10x

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

Version 2 pour iOS 9x, 10x

Si vous essayez d'utiliser le code Version 1 dans iOS 9x vous aurez l'erreur suivante: CGImageCreateWithImageProvider: fournisseur d'image non valide: 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
    }
}

Usage

let screenShot = UIApplication.shared.screenShot!
19
Vasily Bodnarchuk

Pour plus de facilité, j'ajouterais une extension dans son propre fichier.

import UIKit

  public extension UIWindow {

    func capture() -> UIImage {

      UIGraphicsBeginImageContextWithOptions(self.frame.size, self.opaque, UIScreen.mainScreen().scale)
      self.layer.renderInContext(UIGraphicsGetCurrentContext()!)
      let image = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()

      return image
  }
}

appelez l'extension comme suit ...

let window: UIWindow! = UIApplication.sharedApplication().keyWindow

let windowImage = window.capture()

De même, on pourrait utiliser UIView pour capturer une image de cela .... 

9
Damo

La méthode recommandée pour créer un contexte dans iOS 10 consiste à utiliser UIGraphicsImageRenderer.

extension UIView {
    func capture() -> UIImage? {
        var image: UIImage?

        if #available(iOS 10.0, *) {
            let format = UIGraphicsImageRendererFormat()
            format.opaque = isOpaque
            let renderer = UIGraphicsImageRenderer(size: frame.size, format: format)
            image = renderer.image { context in
                drawHierarchy(in: frame, afterScreenUpdates: true)
            }
        } else {
            UIGraphicsBeginImageContextWithOptions(frame.size, isOpaque, UIScreen.main.scale)
            drawHierarchy(in: frame, afterScreenUpdates: true)
            image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
        }

        return image
    }
}
4
neave

J'utilise cette méthode:

func captureScreen() -> UIImage {
    var window: UIWindow? = UIApplication.sharedApplication().keyWindow
    window = UIApplication.sharedApplication().windows[0] as? UIWindow
    UIGraphicsBeginImageContextWithOptions(window!.frame.size, window!.opaque, 0.0)
    window!.layer.renderInContext(UIGraphicsGetCurrentContext())
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image;
}

Il capture tout sauf la barre d'état et ne demande pas la permission d'enregistrer des images dans le film.

J'espère que ça aide!

3
diegomen

Extension Swift 3 pour UIWindow

public extension UIWindow {

  func capture() -> UIImage? {

    UIGraphicsBeginImageContextWithOptions(self.frame.size, self.isOpaque, UIScreen.main.scale)
    self.layer.render(in: UIGraphicsGetCurrentContext()!)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return image

  }
}]
1
Gregg

C'est semblable, j'espère que cela aidera quelqu'un dans le futur.

self.view.image() //returns UIImage

Voici une solution Swift 3

https://Gist.github.com/nitrag/b3117a4b6b8e89fdbc12b98029cf98f8

1
Ryan G
  // Full Screen Shot function. Hope this will work well in Swift.
  func screenShot() -> UIImage {                                                    
    UIGraphicsBeginImageContext(CGSizeMake(frame.size.width, frame.size.height))
    var context:CGContextRef  = UIGraphicsGetCurrentContext()
    self.view?.drawViewHierarchyInRect(frame, afterScreenUpdates: true)
    var screenShot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext();  
    return screenShot
  }
1
Rex

Ma version capture également un clavier. Swift 4.2

extension UIApplication {

    var screenshot: UIImage? {
        UIGraphicsBeginImageContextWithOptions(UIScreen.main.bounds.size, false, 0)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        for window in windows {
            window.layer.render(in: context)
        }
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

}
0
Alexander Khitev

view.snapshotView (afterScreenUpdates: true)

0
Adam Smaka

Voici comment je le fais dans Swift 4

let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);                 
layer.render(in: UIGraphicsGetCurrentContext()!)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

maintenant la capture d'écran sera de type UIImage

Swift 4 ou supérieur.

Pour extension et appel par UIView que vous avez capturé.

Déclaration

extension UIView {

    func viewCapture() -> UIImage? {

        UIGraphicsBeginImageContext(self.frame.size)

        guard let cgContext = UIGraphicsGetCurrentContext() else {
        print("Fail to get CGContext")
        return nil

    }
    self.layer.render(in: cgContext)

    guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
        print("Fail to get Image from current image context")
        return nil
    }
    UIGraphicsEndImageContext()

    return image

    }
}

Utilisation

var m_image = UIImage()

if let tempCaptureImg = self.m_Capture_View.viewCapture() {
    viewController.m_image = tempCaptureImg
}

// m_Capture_View est le type de UIView

0