2

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

Kevin Xu
  • 57
  • 6

1 Answers1

0

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

Ionescu Vlad
  • 151
  • 6
  • Hello, Thanks for your reply, but Unfortunately, your version doesn't read any barcode. have you tried to scan the barcode from the image I posted here? – Kevin Xu Mar 22 '18 at 13:22
  • Yes I've added my answer and added a photo as well – Ionescu Vlad Mar 22 '18 at 13:25
  • Hello, I modified some of your code, I changed the extension from " func metadataOutput(" into "func captureOutput(" Now it works and I can scan and read the barcode which I post here on the moniotor, but the strange thing is, if I print the same image from printer, and try to scan and read it, it doesn't work, I use HP laser printer to print it, it is a very clear printing, Could you help to try to print on a paper and scan it again? I have upload the printed barcode. – Kevin Xu Mar 22 '18 at 14:18
  • I don't have access to a printer right now , try generate the code and print it. Here is a link (one of many) to generate ean13 barcode : https://racoindustries.com/barcodegenerator/1d/ean-13/ – Ionescu Vlad Mar 22 '18 at 16:03
  • If I generate it and print a new one from my laser printer, it will be perfectly scanned, the main problem is that I want to scan the barcode from the image I posted here in printed form, and it failed, that is main point, the printed barcode from that image is very clear , but the scan doesn't work. I feel confused here. – Kevin Xu Mar 22 '18 at 16:41
  • It means that the quality of the photo is not high enough in order to print it and scan it, it has nothing to do with the code. what is the exact reson for doing this and not print a generated barcode ? Also next time try using flash when making a photo of a barcode it will hilight better the diference between black bars and white ones. – Ionescu Vlad Mar 22 '18 at 16:45
  • The reason is, In my friend's shop, he has got many products which the suppliers have already put the barcode on them, those barcode are valid ean13 barcode like the image I post here, and can be easily read by barcode scanner hardware, but for some reason, some of them can not be read by my iOS app which I post here. and I could not find the reason. I even download an iOS app from the Apple shop called QRbot to try, and this app can read them very easily! so I have no idea. I wonder that maybe only good quality barcode can be read by using AVFoundation, otherwise not.. – Kevin Xu Mar 22 '18 at 20:58
  • try scanning the real barcode not a photo of the barcode, I bet it will work. – Ionescu Vlad Mar 22 '18 at 22:09