Strange happened when Scanning EAN13 Barcode by using xcode AVFoundation

1.8k views Asked by At

I wrote a small ios app to scan ean13 barcode, there is a strange problem regarding the sensitivity, it can read 100% of those ean13 barcodes from the products for which the barcodes are well printed on the product by the manufacturer, for example, CD box, medicine box, chocolate, butter, tea box..., but if the barcode is printed manually instead of the manufacture's barcode printing. then there is a problem to read the barcode, but these barcodes are a valid ean13 barcode, and it can be read easily by the barcode reader device hardware, and even by some barcode scan app which I download from the apple store, for example, QRbot.

for example, the following image shows a manually printed ean13 barcode, it is a valid ean13 barcode, and can be easily read by barcode reader hardware, and can also be read by the QRbot app downloaded from app store. but it can not be read from the app which I wrote by using the AVFoundation. ean13barcode

Here are the complete codes:

import UIKit 

import AVFoundation

class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

@IBOutlet weak var scanFrame: UIImageView!
var video = AVCaptureVideoPreviewLayer()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    let session = AVCaptureSession()
    let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
    do
    {
        let input = try AVCaptureDeviceInput(device: captureDevice)
        session.addInput(input)
    }
    catch
    {
        print ("Error opening device")
    }

    let output = AVCaptureMetadataOutput()
    session.addOutput(output)
    output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
    output.metadataObjectTypes = [AVMetadataObjectTypeEAN13Code]
    video = AVCaptureVideoPreviewLayer(session: session)
    video.frame = view.layer.bounds
    view.layer.addSublayer(video)
    self.view.bringSubview(toFront: scanFrame)
    session.startRunning()
    output.rectOfInterest = video.metadataOutputRectOfInterest(for: scanFrame.frame)

}


func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {       
    if metadataObjects != nil && metadataObjects.count != 0
    {
        if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject
        {
            if object.type == AVMetadataObjectTypeEAN13Code
            {
                let alert = UIAlertController(title: "QR Code", message: object.stringValue, preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "Scan again?", style: .default, handler: nil))
                alert.addAction(UIAlertAction(title: "Copy to clipboard", style: .default, handler: { (nil) in
                    UIPasteboard.general.string = object.stringValue
                }))

                print(object.stringValue)
                present(alert, animated: true, completion: nil)
            }
        }
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

Thanks in advance!

enter image description here

1

There are 1 answers

8
Ionescu Vlad On

Hi I've just made modify some of your code , if you copy paste this it should work. The class is based on this tutorial Don't forget to add the camera privacy in info.plist Also I've removed scanFrame so I won't have to take care of UI as well, you can added back if you want.

import UIKit
import Foundation
import AVFoundation

class ViewController: UIViewController {

    var session: AVCaptureSession!
    var previewLayer: AVCaptureVideoPreviewLayer!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create a session object.

        session = AVCaptureSession()

        // Set the captureDevice.

        let videoCaptureDevice = AVCaptureDevice.default(for: AVMediaType.video)

        // Create input object.

        let videoInput: AVCaptureDeviceInput?

        do {
            videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice!)
        } catch {
            return
        }
        // Add input to the session.

        if (session.canAddInput(videoInput!)) {
            session.addInput(videoInput!)
        } else {
            scanningNotPossible()
        }

        // Create output object.

        let metadataOutput = AVCaptureMetadataOutput()

        // Add output to the session.

        if (session.canAddOutput(metadataOutput)) {
            session.addOutput(metadataOutput)

            // Send captured data to the delegate object via a serial queue.

            metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)

            // Set barcode type for which to scan: EAN-13.

            metadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.ean13]

        } else {
            scanningNotPossible()
        }

        // Add previewLayer and have it show the video data.

        previewLayer = AVCaptureVideoPreviewLayer(session: session);
        previewLayer.frame = view.layer.bounds;
        previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill;
        view.layer.addSublayer(previewLayer);

        // Begin the capture session.

        session.startRunning()
    }

    func scanningNotPossible() {
        // Let the user know that scanning isn't possible with the current device.
        let alert = UIAlertController(title: "Can't Scan.", message: "Let's try a device equipped with a camera.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        present(alert, animated: true, completion: nil)
        session = nil
    }


    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        if (session?.isRunning == false) {
            session.startRunning()
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        if (session?.isRunning == true) {
            session.stopRunning()
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
extension ViewController: AVCaptureMetadataOutputObjectsDelegate {
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        if metadataObjects.count != 0
        {
            if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject
            {
                if object.type == AVMetadataObject.ObjectType.ean13
                {
                    let alert = UIAlertController(title: "Barcode Code", message: object.stringValue, preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "Scan again?", style: .default, handler: nil))
                    alert.addAction(UIAlertAction(title: "Copy to clipboard", style: .default, handler: { (nil) in
                        UIPasteboard.general.string = object.stringValue
                    }))

                    print(object.stringValue ?? "error")
                    present(alert, animated: true, completion: nil)
                }
            }
        }
    }
}

enter image description here