Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Swift Barcode Reading

Tags:

ios

swift

barcode

I have barcode scanning working in my app. After the barcode is detected I stop the capture session to allow processing of the barcode. However, after the barcode is processed I want the scanning controller to stay up and the next barcode scanned. I had assumed that starting the capture session (startRunning()) would do it but the image stays frozen. How can I start the capture session again?

like image 496
Floyd Resler Avatar asked Jul 01 '15 20:07

Floyd Resler


People also ask

Can iOS scan barcodes?

You can use Camera or the Code Scanner to scan Quick Response (QR) codes for links to websites, apps, coupons, tickets, and more. The camera automatically detects and highlights a QR code.


2 Answers

To Stop The Session use this code

self.session.stopRunning()

To begin it agian, use this code

self.session.startRunning()

Here is all the code to implement a barcode scanner...

import UIKit
import AVFoundation

class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    let session         : AVCaptureSession = AVCaptureSession()
    var previewLayer    : AVCaptureVideoPreviewLayer!
    var highlightView   : UIView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Allow the view to resize freely
        self.highlightView.autoresizingMask =   
            UIViewAutoresizing.FlexibleTopMargin |
            UIViewAutoresizing.FlexibleBottomMargin |
            UIViewAutoresizing.FlexibleLeftMargin |
            UIViewAutoresizing.FlexibleRightMargin

        // Select the color you want for the completed scan reticle
        self.highlightView.layer.borderColor = UIColor.greenColor().CGColor
        self.highlightView.layer.borderWidth = 3

        // Add it to our controller's view as a subview.
        self.view.addSubview(self.highlightView)

        // For the sake of discussion this is the camera
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

        // Create a nilable NSError to hand off to the next method.
        // Make sure to use the "var" keyword and not "let"
        var error : NSError? = nil

        let input : AVCaptureDeviceInput? =
            AVCaptureDeviceInput.deviceInputWithDevice(device, error: &error) 
                as? AVCaptureDeviceInput

        // If our input is not nil then add it to the session, otherwise we're kind of done!
        if input != nil {
            session.addInput(input)
        } else {
            // This is fine for a demo, do something real with this in your app. :)
            println(error)
        }

        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        session.addOutput(output)
        output.metadataObjectTypes = output.availableMetadataObjectTypes

        previewLayer =
            AVCaptureVideoPreviewLayer.layerWithSession(session) 
                as! AVCaptureVideoPreviewLayer
        previewLayer.frame = self.view.bounds
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.view.layer.addSublayer(previewLayer)

        // Start the scanner. You'll have to end it yourself later.
        session.startRunning()
    }

    // This is called when we find a known barcode type with the camera.
    func captureOutput(
        captureOutput: AVCaptureOutput!, 
        didOutputMetadataObjects metadataObjects: [AnyObject]!,
        fromConnection connection: AVCaptureConnection!) {

        var highlightViewRect = CGRectZero
        var barCodeObject : AVMetadataObject!
        var detectionString : String!

        let barCodeTypes = [AVMetadataObjectTypeUPCECode,
            AVMetadataObjectTypeCode39Code,
            AVMetadataObjectTypeCode39Mod43Code,
            AVMetadataObjectTypeEAN13Code,
            AVMetadataObjectTypeEAN8Code,
            AVMetadataObjectTypeCode93Code,
            AVMetadataObjectTypeCode128Code,
            AVMetadataObjectTypePDF417Code,
            AVMetadataObjectTypeQRCode,
            AVMetadataObjectTypeAztecCode]

        // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan.
        for metadata in metadataObjects {

            for barcodeType in barCodeTypes {

                if metadata.type == barcodeType {
                    barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject)
                    highlightViewRect = barCodeObject.bounds
                    detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
                    self.session.stopRunning()
                    self.alert(detectionString)
                    break
                }
            }
        }

        println(detectionString)
        self.highlightView.frame = highlightViewRect
        self.view.bringSubviewToFront(self.highlightView)
    }        

    func alert(Code: String){
        let actionSheet:UIAlertController = 
            UIAlertController(
                title: "Barcode", 
                message: "\(Code)", 
                preferredStyle: UIAlertControllerStyle.Alert)

        // for alert add .Alert instead of .Action Sheet
        // start copy
        let firstAlertAction:UIAlertAction = 
            UIAlertAction(
                title: "OK",
                style: UIAlertActionStyle.Default, 
                handler: { (alertAction: UIAlertAction!) in
                // action when pressed
                self.session.startRunning()      
        })

        actionSheet.addAction(firstAlertAction)
        // end copy
        self.presentViewController(actionSheet, animated: true, completion: nil)
    }  
}
like image 180
nachshon f Avatar answered Sep 30 '22 18:09

nachshon f


edited the above code for swift 2.0:

import UIKit
import AVFoundation

class BarCodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    let session         : AVCaptureSession = AVCaptureSession()
    var previewLayer    : AVCaptureVideoPreviewLayer!
    @IBOutlet weak var highlightView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Select the color you want for the completed scan reticle
        self.highlightView.layer.borderColor = UIColor.greenColor().CGColor
        self.highlightView.layer.borderWidth = 3

        // Add it to our controller's view as a subview.
        self.view.addSubview(self.highlightView)

        // For the sake of discussion this is the camera
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

        // Create a nilable NSError to hand off to the next method.
        // Make sure to use the "var" keyword and not "let"
        var error : NSError? = nil
        var input: AVCaptureDeviceInput = AVCaptureDeviceInput()
        do {
            input = try  AVCaptureDeviceInput(device: device) as AVCaptureDeviceInput
        } catch let myJSONError {
            print(myJSONError)
        }

        // If our input is not nil then add it to the session, otherwise we're kind of done!
        if input !=  AVCaptureDeviceInput() {
            session.addInput(input)
        }
        else {
            // This is fine for a demo, do something real with this in your app. :)
            print(error)
        }

        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        session.addOutput(output)
        output.metadataObjectTypes = output.availableMetadataObjectTypes

        previewLayer = AVCaptureVideoPreviewLayer(session: session)
        previewLayer.frame = self.view.bounds
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.view.layer.addSublayer(previewLayer)

        // Start the scanner. You'll have to end it yourself later.
        session.startRunning()
    }

    // This is called when we find a known barcode type with the camera.
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        var highlightViewRect = CGRectZero
        var barCodeObject : AVMetadataObject!
        var detectionString : String!
        let barCodeTypes = [AVMetadataObjectTypeUPCECode,
            AVMetadataObjectTypeCode39Code,
            AVMetadataObjectTypeCode39Mod43Code,
            AVMetadataObjectTypeEAN13Code,
            AVMetadataObjectTypeEAN8Code,
            AVMetadataObjectTypeCode93Code,
            AVMetadataObjectTypeCode128Code,
            AVMetadataObjectTypePDF417Code,
            AVMetadataObjectTypeQRCode,
            AVMetadataObjectTypeAztecCode
        ]

        // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan.
        for metadata in metadataObjects {

            for barcodeType in barCodeTypes {

                if metadata.type == barcodeType {
                    barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject)

                    highlightViewRect = barCodeObject.bounds
                    detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
                    self.session.stopRunning()
                    self.alert(detectionString)
                    break
                }
            }
        }

        print(detectionString)
        self.highlightView.frame = highlightViewRect
        self.view.bringSubviewToFront(self.highlightView)
    }

    func alert(Code: String){
        let actionSheet:UIAlertController = UIAlertController(title: "Barcode", message: "\(Code)", preferredStyle: UIAlertControllerStyle.Alert)

        // for alert add .Alert instead of .Action Sheet
        // start copy

        let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: {
                (alertAction:UIAlertAction!) in
                // action when pressed
                self.session.startRunning()  
        })

        actionSheet.addAction(firstAlertAction)

        // end copy
        self.presentViewController(actionSheet, animated: true, completion: nil)
    }
}
like image 26
mkhoshpour Avatar answered Sep 30 '22 16:09

mkhoshpour