Files
Schnappix/node_modules/expo-camera/ios/Current/MetaDataDelegate.swift
T

109 lines
3.6 KiB
Swift

import ZXingObjC
protocol BarcodeScanningResponseHandler {
func onScanningResult(_ result: [String: Any])
}
class MetaDataDelegate: NSObject, AVCaptureMetadataOutputObjectsDelegate, AVCaptureVideoDataOutputSampleBufferDelegate {
private var settings: [String: [AVMetadataObject.ObjectType]]
private var previewLayer: AVCaptureVideoPreviewLayer?
private var zxingBarcodeReaders: [AVMetadataObject.ObjectType: ZXReader]
private var zxingEnabled = true
private var zxingFPSProcessed = 6.0
private let responseHandler: BarcodeScanningResponseHandler
init(
settings: [String: [AVMetadataObject.ObjectType]],
previewLayer: AVCaptureVideoPreviewLayer?,
zxingBarcodeReaders: [AVMetadataObject.ObjectType: ZXReader],
zxingEnabled: Bool,
metadataResultHandler: BarcodeScanningResponseHandler
) {
self.settings = settings
self.previewLayer = previewLayer
self.zxingEnabled = zxingEnabled
self.responseHandler = metadataResultHandler
self.zxingBarcodeReaders = zxingBarcodeReaders
}
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
guard let settings = settings[BARCODE_TYPES_KEY] else {
return
}
for metadata in metadataObjects {
var codeMetadata = metadata as? AVMetadataMachineReadableCodeObject
if let previewLayer {
codeMetadata = previewLayer.transformedMetadataObject(for: metadata) as? AVMetadataMachineReadableCodeObject
}
for barcodeType in settings {
if zxingBarcodeReaders[barcodeType] != nil {
continue
}
if let codeMetadata {
if codeMetadata.stringValue != nil && codeMetadata.type == barcodeType {
self.responseHandler.onScanningResult(BarcodeScannerUtils.avMetadataCodeObjectToDictionary(codeMetadata))
}
}
}
}
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard zxingEnabled else {
return
}
let kMinMargin = 1.0 / zxingFPSProcessed
let presentTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
var curFrameTimeStamp = 0.0
var lastFrameTimeStamp = 0.0
curFrameTimeStamp = Double(presentTimeStamp.value) / Double(presentTimeStamp.timescale)
if curFrameTimeStamp - lastFrameTimeStamp > Double(kMinMargin) {
lastFrameTimeStamp = curFrameTimeStamp
if let videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer),
let videoFrameImage = ZXCGImageLuminanceSource.createImage(from: videoFrame) {
self.scanBarcodes(from: videoFrameImage) { barcodeScannerResult in
self.responseHandler.onScanningResult(BarcodeScannerUtils.zxResultToDictionary(barcodeScannerResult))
}
}
}
}
func scanBarcodes(from image: CGImage, completion: @escaping (ZXResult) -> Void) {
let source = ZXCGImageLuminanceSource(cgImage: image)
let binarizer = ZXHybridBinarizer(source: source)
let bitmap = ZXBinaryBitmap(binarizer: binarizer)
var result: ZXResult?
for reader in zxingBarcodeReaders.values {
result = try? reader.decode(bitmap, hints: nil)
if result != nil {
break
}
}
if result == nil && bitmap?.rotateSupported == true {
if let rotatedBitmap = bitmap?.rotateCounterClockwise() {
for reader in zxingBarcodeReaders.values {
result = try? reader.decode(rotatedBitmap, hints: nil)
if result != nil {
break
}
}
}
}
if let result {
completion(result)
}
}
}