Posts iOS QRコードの画像からデータを読み取る

QRコードの画像からデータを読み取る

はじめに

QRコードの読み取りはiOSアプリで頻繁に登場する機能です。 カメラをQRコードに向けて読み取る方法一般的です しかし、画面に表示されているQRコードはカメラ向けられず、困った経験のある方もいるのではないでしょうか? 今回は、画像データとしてのQRコードを読み取る方法を紹介します。

環境

  • OS: macOS Sonoma 14.7.1
  • XCode: 16.2.0

実装方針

VisionフレームワークにあるNVImageRequestHandlerVNDetectBarcodesRequestを利用します。 VNDetectBarcodesRequestでは、処理を待つためにクロージャーを利用しなければなりませんが、今回はwithCheckedThrowingContinuationを利用してasync関数として定義することにします。

VNImageRequestHandler

VNImageRequestHandlerを利用すると、単一の画像に対して1つ以上の処理をリクエストできます。 イニシャライザに画像データを渡す形で初期化し、performメゾットを利用することで処理をリクエストできます。 イニシャライザは、渡す画像データの型によって複数種類用意されており、CIImageUIImage, Dataなどを利用できます。

VNDetectBarcodesRequest

VNDetectBarcodesRequestはVisionフレームワークによって提供されており、画像内のバーコード検出機能を提供しています。 このクラスをVNImageRequestHandler.performの引数とすることで、画像データの解析時に任意の処理を指せることができます

実装

サンプルとして、引数にQRコード画像をData型に変換したものを渡すと、QRコードのPayloadを返す関数を作成してみます。

func detectQRCode(imageData: Data) async throws -> String {
    // withCheckedThrowingContinuationを利用して、asyncな関数に変換
    return try await withCheckedThrowingContinuation { continuation in
        // VNDetectBarcodesrequestを利用して、画像解析時の処理を定義する
        let request = VNDetectBarcodesRequest { request, error in
            if let error {
                continuation.resume(throwing: error)
                return
            }

            guard let results = request.results as? [VNBarcodeObservation],
                let payload = results.first?.payloadStringValue else {
                    continuation.resume(throwing: HogeError.payloadNotFound) // 読み込めない場合には任意のえらーをthrowする 
                    return
                }
            continuation.resume(returning: payload)
        }

        // VNImagerequestHandlerのイニシャライザに、解析したいQRコード画像のデータを渡す
        let handler = VNImageRequestHandler(data: imageData, options: [:])
        do {
            // perform関数の実行によって解析を開始し、NVDetectBarcodesRequestに定義した内容に従って処理が行われる
            try handler.perform([request])
        } catch {
            continuation.resume(throwing: error)
        }
    }
}

まとめ

要件によってはカメラからのQRコード読み込みと合わせて実装することで、よりQRコード読み込みを便利にできると思います! 実装コストも低いので是非試してみてください!