0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Swift UI]正方形のカメラViewでバーコードスキャンしてアラートで表示するまで

Posted at
IMG_5F82400E5BEF-1.jpeg

ちょっと長いですけどコピペで動きます

import SwiftUI
import AVFoundation

struct ContentView2: View {
    
    @ObservedObject private var reader = Reader()
    
    var body: some View {
        VStack{
            
            //QR読み取りViewをセット:レイヤーにカメラプレビューのレイヤーをセット
            QRReaderView(caLayer: reader.videoPreviewLayer)
            //                .edgesIgnoringSafeArea(.all)
            //QRコードを読み込んだらAlertで読み取り結果を出す。読み取ったらAVCaptureSessionを停止しているのでOKボタンを押して再度読み取り開始
                .alert(isPresented: $reader.isdetectQR) {
                    Alert(title: Text("バーコード読み取り成功"),
                          //                      message: Text("読み取りデータ:\(qrReader.qrData)"),dismissButton: .default(Text("OK"),action: {
                          message: Text("読み取りデータ:\(reader.ean13Data)"),dismissButton: .default(Text("OK"),action: {
                        
                        reader.startSession()
                    }))
                }
        }
        .background(Color.white)
    }
}

struct QRReaderView: UIViewControllerRepresentable {
    var caLayer:CALayer
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<QRReaderView>) -> UIViewController {
        let viewController = UIViewController()
//        viewController.view.backgroundColor = .orange
        viewController.view.layer.addSublayer(caLayer)
//        ここでカメラのframe幅を変更する
        viewController.view.frame = CGRect(x: viewController.view.frame.height / 2, y: viewController.view.frame.width / 4, width: 300, height: 300)
        
        return viewController
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<QRReaderView>) {
        caLayer.frame = uiViewController.view.layer.frame
    }
}

class Reader: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, ObservableObject {
    
    @Published var qrData:String = ""
    @Published var ean13Data:String = ""
    
    @Published var isdetectQR = false
    @Published var isdetectean13 = false
    
    //カメラ用のAVsessionインスタンス作成
    private let AVsession = AVCaptureSession()
    //カメラ画像を表示するレイヤー
    var videoPreviewLayer:AVCaptureVideoPreviewLayer!
    // カメラの設定
    // 今回は背面カメラなのでposition: .back
    let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .front)
    
    override init() {
        super.init()
        cameraInit()
    }
    
    func cameraInit(){
        //カメラデバイスの取得
        let devices = discoverySession.devices
        
        //背面のカメラ情報を取得
        if let backCamera = devices.first {
            do {
                //カメラ入力をinputとして取得
                let input = try AVCaptureDeviceInput(device: backCamera)
                
                //Metadata情報(今回はQRコード)を取得する準備
                //AVssessionにinputを追加:既に追加されている場合を考慮してemptyチェックをする
                if AVsession.inputs.isEmpty {
                    AVsession.addInput(input)
                    //MetadataOutput型の出力用の箱を用意
                    let captureMetadataOutput = AVCaptureMetadataOutput()
                    //captureMetadataOutputに先ほど入力したinputのmetadataoutputを入れる
                    AVsession.addOutput(captureMetadataOutput)
                    //MetadataObjectsのdelegateに自己(self)をセット
                    captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
                    //Metadataの出力タイプをqrにセット
                    //                    captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
                    captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.ean13]
                    
                    //カメラ画像表示viewの準備とカメラの開始
                    //カメラ画像を表示するAVCaptureVideoPreviewLayer型のオブジェクトをsessionをAVsessionで初期化でプレビューレイヤを初期化
                    videoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: AVsession)
                    videoPreviewLayer.videoGravity = .resizeAspectFill //←これ
                    //        previewLayer.connection?.videoOrientation = .landscapeRight
                    
                    //カメラ画像を表示するvideoPreviewLayerの大きさをview(superview)の大きさに設定
                    //                    videoPreviewLayer?.frame = previewLayer.bounds
                    //カメラ画像を表示するvideoPreviewLayerをビューに追加
                    //previewLayer.addSublayer(videoPreviewLayer!)
                }
                
                
                //セッションの開始(今回はカメラの開始)
                DispatchQueue.global(qos: .background).async {
                    self.AVsession.startRunning()
                    
                }
            } catch {
                print("Error occured while creating video device input: \(error)")
            }
        }
    }
    
    
    func startSession() {
        if AVsession.isRunning { return }
        AVsession.startRunning()
    }
    
    func stopSession() {
        if !AVsession.isRunning { return }
        AVsession.stopRunning()
    }
    
    
}
//MARK: - AVCaptureMetadataOutputObjectsDelegate
extension Reader:AVCaptureMetadataOutputObjectsDelegate{
    
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        
        //カメラ画像にオブジェクトがあるか確認
        if metadataObjects.count == 0 {
            return
        }
        //オブジェクトの中身を確認
        for metadata in metadataObjects as! [AVMetadataMachineReadableCodeObject] {
            // metadataのtype: metadata.type
            print(metadata.type)
            print(metadata.stringValue!)
            
            // QRの中身: metadata.stringValue
            guard let data = metadata.stringValue else { return }
            isdetectQR = true
            //            isdetectean13 = true
            
            //            qrData = data
            ean13Data = data
            
            print("読み取りvalue:",data)
            //一旦て停止
            stopSession()
            //AVsession.stopRunning()
        }
    }
}

このやり方で作ってたんですが、これだとアラートの表示とかできなくて別記事のバーコードスキャンのソースと上記で使った正方形カメラの表示のやり方を君合わせて一つのバーコード読み取り機能を実装しました

画面の一部にバーコードスキャンを導入したいなんて思ってる方はこちらのやり方とか参考にできる部分があるかなと思います

どなたかの参考になれば幸いです

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?