Utiliser la caméra dans une application iOS (2/3)

Dans cet article, nous allons capturer les images vues par la caméra et les afficher dans une UIView. Nous utiliserons les classes AVCapture... fournies par le framework AVFoundation.


Interface

L’écran de l’application est composé de deux UIImageView et d’un bouton Capture. La première image contiendra le flux video de la caméra, la seconde contiendra l’image obtenue lorsqu’on appuiera sur le bouton capture. Les deux images sont liées à des variables outlets du ViewController.

    @IBOutlet weak var liveView: UIImageView!
    @IBOutlet weak var resultView: UIImageView!

Le bouton est lié à une function captureAction :

    @IBAction func captureAction() {
    }

 

Préparer la Capture Session

Nous créons une fonction setupCaptureSession() pour paramétrer la capture vidéo. La session est créée avec la classe AVCaptureSession, puis la configuration doit être effectuée entre un begin et un commit. Enfin, on peut démarrer la session de capture avec un appel à startRunning.

    func setupCaptureSession() {
        let captureSession = AVCaptureSession()
        captureSession.beginConfiguration()
        ...
        captureSession.commitConfiguration()
        ...
        captureSession.startRunning()
   }

La captureSesssion nécessite une entrée AVCaptureInput et une sortie AVCaptureOutput. L’entrée est la caméra de l’iPhone, que nous obtenons avec AVCaptureDevice :

        let videoDevice = AVCaptureDevice.default(for: .video)
        guard
            let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice!),
            captureSession.canAddInput(videoDeviceInput)
        else {return}
        captureSession.addInput(videoDeviceInput)

Le code vérifie que la caméra est disponible et l’ajoute à la session si c’est le cas.

 

Pour la sortie, nous voulons prendre une photo, par conséquent nous allons utiliser AVCapturePhotoOutput.
Commençons par créer l’objet en tant que propriété du controller :

...
    let photoOutput = AVCapturePhotoOutput()
...

Puis ajoutons le à la configuration de la session.

        guard captureSession.canAddOutput(photoOutput) else { return }
        captureSession.sessionPreset = .photo
        captureSession.addOutput(photoOutput)
 
        captureSession.commitConfiguration()

Enfin, nous voulons que la liveView affiche ce que voit la caméra. Nous créons pour cela un layer à partir de la captureSession, et l’associons à la vue :

        let videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        videoPreviewLayer.frame = liveView.frame
        liveView.layer.addSublayer(videoPreviewLayer)

Prendre une photo

Lorsqu’on tape le bouton capture, il suffit d’appeler la fonction capturePhoto du photoOutput que nous avons créée.

    @IBAction func captureAction(_ sender: Any) {
 
        let settings = AVCapturePhotoSettings()
 
        photoOutput.capturePhoto(with: settings, delegate: self)
 
    }

Le résultat de la capture sera géré par un delegate qui sera notre controller. Sa définition est donc modifiée.

class ViewController: UIViewController,AVCapturePhotoCaptureDelegate {
...

Il ne reste qu’à ajouter la fonction du delegate qui permet de récupérer la photo prise.

    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        guard let cgImage = photo.cgImageRepresentation()?.takeUnretainedValue()
            else { return }
 
        captureView.image = UIImage(cgImage: cgImage, scale: 1.0, orientation: .right)
 
    }
}

L’objet AVCapturePhoto contient toutes les informations sur la photo prise et fournit une fonction de conversion cgImageRepresentation() vers CGImage, que nous pouvons ensuite convertir en UIImage pour l’afficher dans notre vue.
Cette fonction retourne une valeur Unmanaged, que nous devons également transformer via takeUnretainedValue() (plus de détails dans cet article).

Cet exemple contient le code minimum pour capturer et récupérer une photo sur un iPhone. Les classes utilisées offrent de nombreuses options pour paramétrer les différentes étapes de la capture.

Le code source est disponible ici.