SwiftUI - 在 macOS 应用程序中扫描二维码

SwiftUI - scanning QR codes in the macOS app

我正在开发一个 Mac 应用程序,它将从相机读取 QR 码,然后从中读取文本。

不幸的是,CodeScanner 包仅适用于 iOS,并且没有调用的方法:

func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)

当然,要使用它,必须包含 AVCaptureMetadataOutputObjectsDelegate - 不幸的是,此协议在 macOS 上不可用。

有什么方法可以使用 SwiftUI 创建 macOS 二维码扫描器吗?

我目前有一个 Mac内置的图书相机预览,但我想念缺少捕捉 QR 码的东西:

final class PlayerContainerView: NSViewRepresentable {
    typealias NSViewType = PlayerView
    
    let captureSession: AVCaptureSession
    
    init(captureSession: AVCaptureSession) {
        self.captureSession = captureSession
    }
    
    func makeNSView(context: Context) -> PlayerView {
        return PlayerView(captureSession: captureSession)
    }
    
    func updateNSView(_ nsView: PlayerView, context: Context) {}
}

class PlayerView: NSView {
    var previewLayer: AVCaptureVideoPreviewLayer?
    
    init(captureSession: AVCaptureSession) {
        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        super.init(frame: .zero)
        
        setupLayer()
    }
    
    func setupLayer() {
        previewLayer?.frame = self.frame
        previewLayer?.contentsGravity = .resizeAspectFill
        previewLayer?.videoGravity = .resizeAspectFill
        previewLayer?.connection?.automaticallyAdjustsVideoMirroring = false
        
        if let mirroringSupported = previewLayer?.connection?.isVideoMirroringSupported {
            if mirroringSupported {
                previewLayer?.connection?.automaticallyAdjustsVideoMirroring = false
                previewLayer?.connection?.isVideoMirrored = true
            }
        }

        
        layer = previewLayer
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

我找不到任何委托协议可以像 AVCaptureMetadataOutputObjectsDelegate 一样工作并允许我捕获元数据对象。

我也很惊讶 macOS AVFoundation 不支持 AVCaptureMetadataOutput,但是 CoreImage 支持 QR 码,这对我有用:

let qrDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: nil)!

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
    
    let ciImage = CIImage(cvImageBuffer: imageBuffer)
    let features = qrDetector.features(in: ciImage)

    for feature in features {
        let qrCodeFeature = feature as! CIQRCodeFeature
        print("messageString \(qrCodeFeature.messageString!)")
    }
}

可能有更有效的方法。