5

I am creating an app using Swift 4 and Xcode 9 that scans PDF417 barcodes using AVFoundation. The scanner works with some codes but doesn't recognize the PDF417 barcode that you would find on the front of a CA Lottery scratchers ticket for example.

Is there anything I am missing to make it work? Below is my code:

let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera], mediaType: AVMediaType.video, position: .back)

    guard let captureDevice = deviceDiscoverySession.devices.first else {
        print("Failed to get the camera device")
        return
    }

    do {
        captureSession = AVCaptureSession()

        let input = try AVCaptureDeviceInput(device: captureDevice)
        captureSession!.addInput(input)

        let captureMetadataOutput = AVCaptureMetadataOutput()

        captureSession!.addOutput(captureMetadataOutput)
        captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.pdf417]

        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
        videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        videoPreviewLayer?.frame = view.layer.bounds
        view.layer.addSublayer(videoPreviewLayer!)
        captureSession?.startRunning()
     } catch {
        print(error)
        return
    }

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

    //Get the metadata object
    let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
    if scanType.contains(metadataObj.type) {
        let barCodeObj = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)

        if(metadataObj.stringValue != nil) {
            callDelegate(metadataObj.stringValue)
            captureSession?.stopRunning()
            AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
            navigationController?.popViewController(animated: true)
        }
    }
}

Thanks!

Rana Kolta
  • 71
  • 7

1 Answers1

0

Replace your initialization code for the scanner with the following code either in your viewDidLoad or some method that you'd like it to be in

// Global vars used in init below
var captureSession: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!


func setupCaptureInputDevice() {
    let cameraMediaType = AVMediaType.video

    captureSession = AVCaptureSession()

    // get the video capture device, which should be of type video
    guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else {

        // if there is an error then something is wrong, so dismiss
        dismiss(animated: true, completion: nil)
        return

    }

    let videoInput: AVCaptureDeviceInput

    // create a capture input for the above device input that was created
    do {
        videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
    } catch {
        return
    }

    // this is important to check for if we are able to add the input
    // because adding before this could cause a crash or it could not happen
    if (captureSession.canAddInput(videoInput)) {
        captureSession.addInput(videoInput)
    } else {
        // dismiss or display error
        return
    }

    // get ready to capture output somewhere
    let metadataOutput = AVCaptureMetadataOutput()

    // again check to make sure that we can do this operation before doing it
    if (captureSession.canAddOutput(metadataOutput)) {
        captureSession.addOutput(metadataOutput)

        // setting the metadataOutput's delegate to be self and then requesting it run on the main thread
        metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        // specify your code type
        metadataOutput.metadataObjectTypes = [.pdf417]
    } else {
        // dismiss or display error
        return
    }

    // the preview layer now becomes the capture session
    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

    // just add it to the screen
    previewLayer.frame = view.layer.bounds
    previewLayer.videoGravity = .resizeAspectFill
    view.layer.addSublayer(previewLayer)

    // and begin input
    captureSession.startRunning()
}
KSigWyatt
  • 1,368
  • 1
  • 16
  • 33
  • I am sorry I didn't include the delegate in my question, but I do have the delegate in my code. I will add it to the question, maybe you could point out anything I might have missed – Rana Kolta Jul 20 '18 at 04:08
  • 1
    If you add a breakpoint to the middle of that delegate method, does the breakpoint get hit if you try to scan a code? I have a feeling that the setup that you have is not completely correct. Because with my scanner I do not use `DiscoverySession`. I'll update my answer to show what I use to setup the view. I have a feeling that this is why you're having issues. I'm not actually sure what DiscoverySession is – KSigWyatt Jul 20 '18 at 12:18
  • I got most of the code from this tutorial https://www.appcoda.com/barcode-reader-swift/. The scanner works for most PDF417 but it just doesn’t read the one in a scratcher lottery ticket, I am thinking it might be because it’s not in a standard iso format. However third party apps like MicroBlink picks it up. So I am not sure if there is something I’m missing to make AVF better. – Rana Kolta Jul 20 '18 at 12:32
  • I have made a scanner using the above code in order to make a PDF417 scanner. It is using AVFoundation, however It comes down to the quality of the barcode and how small it is. Smaller barcodes are harder for the scanner to reco, meaning that if the barcode is too small it can't read it. Or if the PDF417 is squished together it won't scan. But yes that may very well be the solution. This code works. Try it on your drivers license, there's a PDF417 on the back – KSigWyatt Jul 20 '18 at 14:01
  • 1
    Thanks for all your effort and help on this I really appreciate it. Glad to get confirmation that the code works, I asked around at work today and the PDF417 code I am trying to scan is non standard and super tiny as you mentioned, most probably that’s why it is not working. – Rana Kolta Jul 20 '18 at 19:26