I have an iOS app that scans a barcode.
Now I would like to define a specific scan area. For this, I use the rectOfInterestand property metadataOutputRectOfInterest.
The problems i am facing
When I use only this code below, nothing will be scanned, if I delete barcodeAreaView, the scan works fine on the whole screen
class BarcodeReaderViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
var cameraView: AVCaptureVideoPreviewLayer?
let captureSession = AVCaptureSession()
let sessionQueue = DispatchQueue(label: AVCaptureSession.self.description(), attributes: [], target: nil)
var barcodeAreaView: UIView?
let supportedCodeTypes = [
AVMetadataObjectTypeEAN8Code,
AVMetadataObjectTypeEAN13Code,
AVMetadataObjectTypeUPCECode,
AVMetadataObjectTypeCode39Code,
AVMetadataObjectTypeCode93Code,
AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeInterleaved2of5Code
]
let metadataOutput = AVCaptureMetadataOutput()
var barcodeArea:CGRect!
override func viewDidLoad() {
super.viewDidLoad()
let width = 250
let height = 100
print(self.view.frame.size.width)
let xPos = (CGFloat(self.view.frame.size.width) / CGFloat(2)) - (CGFloat(width) / CGFloat(2))
let yPos = (CGFloat(self.view.frame.size.height) / CGFloat(2)) - (CGFloat(height) / CGFloat(2))
barcodeArea = CGRect(x: Int(xPos), y: Int(yPos), width: width, height: height)
barcodeAreaView = UIView()
barcodeAreaView?.layer.borderColor = UIColor.red.cgColor
barcodeAreaView?.layer.borderWidth = 1
barcodeAreaView?.frame = barcodeArea
view.addSubview(barcodeAreaView!)
captureSession.beginConfiguration()
let videoDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
if videoDevice != nil {
let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice)
if videoDeviceInput != nil {
if captureSession.canAddInput(videoDeviceInput) {
captureSession.addInput(videoDeviceInput)
}
}
if captureSession.canAddOutput(metadataOutput) {
captureSession.addOutput(metadataOutput)
metadataOutput.metadataObjectTypes = supportedCodeTypes
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
cameraView = AVCaptureVideoPreviewLayer(session: captureSession)
cameraView?.videoGravity = AVLayerVideoGravityResizeAspectFill
cameraView?.frame = view.layer.bounds
metadataOutput.rectOfInterest = cameraView!.metadataOutputRectOfInterest(for: barcodeArea)
view.layer.addSublayer(cameraView!)
}
}
captureSession.commitConfiguration()
view.bringSubview(toFront: barcodeAreaView!)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
sessionQueue.async {
self.captureSession.startRunning()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sessionQueue.async {
self.captureSession.stopRunning()
}
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
if let metadataObject = metadataObjects.first {
let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject
let message = readableObject.stringValue
print(message)
}
}
}
I have already considered this issue.
How to use metadataOutputRectOfInterestForRect method and rectOfInterest property to scan a specific area? (QR code)
The problem I am encountering here is that scanning is a bit laggy and my navigation controller is not working (because the listener is waiting for a scan)
UPDATE:
solved the problem as suggested in this answer
qaru.site/questions/313079/...
self.captureSession.startRunning()
metadataOutput.rectOfInterest = cameraView!.metadataOutputRectOfInterest(for: barcodeArea)