swift言語: AVFoundationを使ってQRCodeReaderを作成してみました

概要

QRCode Reader Using Swift Tutorialを参考に、AVFoundationを使ってQRCodeReaderを作成してみました。

QRコード読取処理のライブラリ化を行いながら、AV Foundationについてもう少し調べていく予定です。

AV Foundation

AVFoundationは、時間ベースのオーディオビジュアルメディアの再生と作成に使用できるフレーム ワークで、時間ベースのオーディオビジュアルデータに関する作業を細かいレベルで行うための インターフェイスを提供します。詳細は、以下を参照してください。

AV Foundationの各クラスの説明が、以下にあります。 AV Foundation Framework Reference

AVFoundationのswift実装については、以下のページが参考になります。 AVFoundation Changes for Swift

実装

以下の手順で実装します。

セッションを作成します

キャプチャデバイスを探し、セッションを作成します。

参考。

ソースコード

    func configureVideoCapture() -> AVCaptureSession? {
        do {

            let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
            let deviceInput = try AVCaptureDeviceInput(device: captureDevice) as AVCaptureDeviceInput

            let session  = AVCaptureSession()
            session.addInput(deviceInput as AVCaptureInput)
            let metadataOutput = AVCaptureMetadataOutput()
            session.addOutput(metadataOutput)
            metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
            metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]

            return session

        } catch let error as NSError {
            let alertController: UIAlertController = UIAlertController(title: "Device Error", message: error.localizedFailureReason, preferredStyle: .Alert)
            let defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
            alertController.addAction(defaultAction)
            
            presentViewController(alertController, animated: true, completion: nil)

        }
        return nil
        
    }

VideoPreviewLayerを作成します

キャプチャしている画像を表示するPreviewLayperを作成します。

参考。

ソースコード

    func createVideoPreviewLayer(session: AVCaptureSession) -> AVCaptureVideoPreviewLayer? {
        let captureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
        if let preview = captureVideoPreviewLayer {
            preview.videoGravity = AVLayerVideoGravityResizeAspectFill
            preview.frame = view.layer.bounds
            return preview
        }
        return nil
    }

delegateメソッド実装

AVCaptureMetadataOutputObjectsDelegateプロトコルを実装する必要があります。

    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        if metadataObjects == nil || metadataObjects.count == 0 {
            didnotDetectQRCode();
            return
        }
        let metadata: AVMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
        didFindQRCode(metadata)
    }
    func didnotDetectQRCode() {
        qrcodeView!.frame = CGRectZero
        print("NO QRCode text detacted")
        
    }
    func didFindQRCode(metadata: AVMetadataMachineReadableCodeObject) {
        if metadata.type == AVMetadataObjectTypeQRCode {
            let barCode = captureVideoPreviewLayer!.transformedMetadataObjectForMetadataObject(metadata) as! AVMetadataMachineReadableCodeObject
            qrcodeView!.frame = barCode.bounds;
            if metadata.stringValue != nil {
                qrcodeView!.frame = CGRectZero
                let result = metadata.stringValue
                print(result)
                self.label.text = result

                self.captureVideoPreviewLayer!.removeFromSuperlayer()
                self.captureSession!.stopRunning()
            }
        }
    }

UI作成

QRコードを囲むUIViewを作成します。

    func createQRView() -> UIView {
        let view = UIView()
        view.layer.borderColor = UIColor.redColor().CGColor
        view.layer.borderWidth = 5
        return view
    }

scanボタン作成。

QRコード読取を開始するUIButtonを作成します。UIButtonクリックイベントに以下の処理を追加します。

    @IBAction func doScan(sender: UIBarButtonItem) {
        self.captureSession = self.configureVideoCapture()
        if let session = self.captureSession {
            
            self.captureVideoPreviewLayer = self.createVideoPreviewLayer(session)
            if let preview = captureVideoPreviewLayer {
                self.view.layer.addSublayer(preview)
                
                session.startRunning()
                
                let view = self.createQRView()
                self.view.addSubview(view)
                self.view.bringSubviewToFront(view)
                self.qrcodeView = view
                
            }
        }
    }

ソースコード

ソースコードは、Githubにあります。

関連資料