如何在iOS上扫描条形码?

问题描述 投票:184回答:19

如何在iPhone和/或iPad上简单扫描条形码?

ios swift iphone cocoa-touch barcode
19个回答
80
投票

我们为iPhone制作了“条形码”应用程序。它可以解码QR码。源代码可从zxing project获得;具体来说,你想看看iPhone clientpartial C++ port of the core library。该端口有点陈旧,大约是Java代码的0.9版本,但仍然应该运行得相当好。

如果需要扫描其他格式(如1D格式),可以将此项目中的Java代码端口继续到C ++。

编辑:项目中的条形码和iphone代码在2014年初退役。


5
投票

如果对iPad 2或iPod Touch的支持对您的应用程序很重要,我会选择条形码扫描仪SDK来解码模糊图像中的条形码,例如我们用于iOS和Android的.UIApplicationWillEnterForeground。解码模糊条形码图像对于具有自动对焦相机的手机也很有用,因为用户无需等待自动对焦启动。

Scandit提供免费的社区价格计划,还有一个产品API,可以很容易地将条形码数字转换为产品名称。

(免责声明:我是Scandit的联合创始人)


4
投票

你可以看看UIApplication.willEnterForegroundNotificationQR Code library; what QR Codes are),如果它仍然可用。


3
投票

iPhone相机的问题在于,第一个型号(其中有大量使用的)具有定焦相机,无法在2英尺以下的距离内对焦。图像模糊和失真,如果从更远的距离拍摄,则条形码中没有足够的细节/信息。

一些公司开发了可以通过使用先进的去模糊技术来适应这种情况的iPhone应用程序。您可以在Apple应用商店找到的应用程序:pic2shop,RedLaser和ShopSavvy。所有的公司都宣布他们也有SDK可用 - 一些免费或非常优惠的条款,检查一个。


1
投票

对于原生iOS 7条形码扫描器,请查看我在GitHub上的项目:

Scandit barcode scanner SDK



1
投票

如果您使用Swift 4开发iOS> 10.2,那么您可以尝试我的解决方案。我混合了Google Code projectarchived blog post教程并想出了一个ViewController,它扫描QR码和https://github.com/werner77/WECodeScanner它。我的UI中也有一个Switch来切换相机灯,也可能有用。目前我只在iPhone SE上测试过,请告诉我它是否适用于较新的iPhone。

干得好:

func scanbarcode()
{
    view.backgroundColor = UIColor.blackColor()
    captureSession = AVCaptureSession()

    let videoCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    let videoInput: AVCaptureDeviceInput

    do {
        videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
    } catch {
        return
    }

    if (captureSession.canAddInput(videoInput)) {
        captureSession.addInput(videoInput)
    } else {
        failed();
        return;
    }

    let metadataOutput = AVCaptureMetadataOutput()

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

        metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code]
    } else {
        failed()
        return
    }

    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession);
    previewLayer.frame = view.layer.bounds;
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    view.layer.addSublayer(previewLayer);
    view.addSubview(closeBtn)
    view.addSubview(backimg)

    captureSession.startRunning();

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

func failed() {
    let ac = UIAlertController(title: "Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.", preferredStyle: .Alert)
    ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
    presentViewController(ac, animated: true, completion: nil)
    captureSession = nil
}

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

    if (captureSession?.running == false) {
        captureSession.startRunning();
    }
}

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

    if (captureSession?.running == true) {
        captureSession.stopRunning();
    }
}

func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
    captureSession.stopRunning()

    if let metadataObject = metadataObjects.first {
        let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject;

        AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
        foundCode(readableObject.stringValue);
    }

   // dismissViewControllerAnimated(true, completion: nil)
}

func foundCode(code: String) {
    var createAccountErrorAlert: UIAlertView = UIAlertView()
    createAccountErrorAlert.delegate = self
    createAccountErrorAlert.title = "Alert"
    createAccountErrorAlert.message = code
    createAccountErrorAlert.addButtonWithTitle("ok")
    createAccountErrorAlert.addButtonWithTitle("Retry")
    createAccountErrorAlert.show()
    NSUserDefaults.standardUserDefaults().setObject(code, forKey: "barcode")
    NSUserDefaults.standardUserDefaults().synchronize()
    ItemBarcode = code
    print(code)
}

override func prefersStatusBarHidden() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return .Portrait
}

0
投票

有时,生成QR码也很有用。这里有一个极好的C库,就像一个魅力。它被称为this。编写用于显示QR码的自定义视图并不困难,可以通过对QuartzCore的基本了解来完成。


0
投票

您可以检查ZBarSDK读取QR码和ECN / ISBN码,它易于集成,请尝试以下代码。

this

在didFinishPickingMediaWithInfo中,我们得到条形码值。

print()

0
投票

我相信这可以使用AVFramework来完成,这是执行此操作的示例代码

import UIKit
import AVFoundation

class QRCodeScanner: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    let captureSession: AVCaptureSession = AVCaptureSession()
    var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    let qrCodeFrameView: UIView = UIView()
    var captureDevice: AVCaptureDevice?

    override func viewDidLoad() {
        // Get the back-facing camera for capturing videos
        let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInDualCamera], mediaType: AVMediaType.video, position: .back)

        captureDevice = deviceDiscoverySession.devices.first
        if captureDevice == nil {
            print("Failed to get the camera device")
            return
        }

        do {
            // Get an instance of the AVCaptureDeviceInput class using the previous device object.
            let input = try AVCaptureDeviceInput(device: captureDevice!)

            // Set the input device on the capture session.
            captureSession.addInput(input)

            // Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
            let captureMetadataOutput = AVCaptureMetadataOutput()
            captureSession.addOutput(captureMetadataOutput)

            // Set delegate and use the default dispatch queue to execute the call back
            captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]

            // Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.

            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

            if let videoPreviewLayer = videoPreviewLayer {
                videoPreviewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
                videoPreviewLayer.frame = view.layer.bounds
                view.layer.addSublayer(videoPreviewLayer)

                // Start video capture.
                captureSession.startRunning()

                if let hasFlash = captureDevice?.hasFlash, let hasTorch = captureDevice?.hasTorch {
                    if hasFlash && hasTorch {
                        view.bringSubview(toFront: bottomBar)
                        try captureDevice?.lockForConfiguration()
                    }
                }
            }

            // QR Code Overlay
            qrCodeFrameView.layer.borderColor = UIColor.green.cgColor
            qrCodeFrameView.layer.borderWidth = 2
            view.addSubview(qrCodeFrameView)
            view.bringSubview(toFront: qrCodeFrameView)

        } catch {
            // If any error occurs, simply print it out and don't continue any more.
            print("Error: \(error)")
            return
        }
    }

    // MARK: Buttons and Switch

    @IBAction func switchFlashChanged(_ sender: UISwitch) {
        do {
            if sender.isOn {
                captureDevice?.torchMode = .on
            } else {
                captureDevice?.torchMode = .off
            }
        }
    }

    // MARK: AVCaptureMetadataOutputObjectsDelegate

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

        // Check if the metadataObjects array is not nil and it contains at least one object.
        if metadataObjects.count == 0 {
            qrCodeFrameView.frame = CGRect.zero
            return
        }

        // Get the metadata object.
        let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject

        if metadataObj.type == AVMetadataObject.ObjectType.qr {
            // If the found metadata is equal to the QR code metadata then update the status label's text and set the bounds
            let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
            qrCodeFrameView.frame = barCodeObject!.bounds

            print("QR Code: \(metadataObj.stringValue)")
        }
    }
}

0
投票

使用Swift 5它简单而超级快!

你只需要添加可可豆荚“BarcodeScanner”这里就是完整的代码

libqrencode

确保在.plist文件中添加Camera权限

- (void)scanBarcodeWithZBarScanner
  {
// ADD: present a barcode reader that scans from the camera feed
ZBarReaderViewController *reader = [ZBarReaderViewController new];
reader.readerDelegate = self;
reader.supportedOrientationsMask = ZBarOrientationMaskAll;

ZBarImageScanner *scanner = reader.scanner;
// TODO: (optional) additional reader configuration here

// EXAMPLE: disable rarely used I2/5 to improve performance
 [scanner setSymbology: ZBAR_I25
               config: ZBAR_CFG_ENABLE
                   to: 0];

//Get the return value from controller
[reader setReturnBlock:^(BOOL value) {

}

并以这种方式在ViewController中添加Scanner并处理结果

    - (void) imagePickerController: (UIImagePickerController*) reader
   didFinishPickingMediaWithInfo: (NSDictionary*) info
   {
    // ADD: get the decode results
    id<NSFastEnumeration> results =
    [info objectForKey: ZBarReaderControllerResults];
    ZBarSymbol *symbol = nil;
    for(symbol in results)
    // EXAMPLE: just grab the first barcode
    break;

    // EXAMPLE: do something useful with the barcode data
    barcodeValue = symbol.data;

    // EXAMPLE: do something useful with the barcode image
    barcodeImage =   [info objectForKey:UIImagePickerControllerOriginalImage];
    [_barcodeIV setImage:barcodeImage];

    //set the values for to TextFields
    [self setBarcodeValue:YES];

    // ADD: dismiss the controller (NB dismiss from the *reader*!)
    [reader dismissViewControllerAnimated:YES completion:nil];
   }

仍然和任何问题或挑战,import UIKit import AVFoundation class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate { @IBOutlet weak var lblQRCodeResult: UILabel! @IBOutlet weak var lblQRCodeLabel: UILabel! var objCaptureSession:AVCaptureSession? var objCaptureVideoPreviewLayer:AVCaptureVideoPreviewLayer? var vwQRCode:UIView? override func viewDidLoad() { super.viewDidLoad() self.configureVideoCapture() self.addVideoPreviewLayer() self.initializeQRView() } func configureVideoCapture() { let objCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) var error:NSError? let objCaptureDeviceInput: AnyObject! do { objCaptureDeviceInput = try AVCaptureDeviceInput(device: objCaptureDevice) as AVCaptureDeviceInput } catch let error1 as NSError { error = error1 objCaptureDeviceInput = nil } objCaptureSession = AVCaptureSession() objCaptureSession?.addInput(objCaptureDeviceInput as! AVCaptureInput) let objCaptureMetadataOutput = AVCaptureMetadataOutput() objCaptureSession?.addOutput(objCaptureMetadataOutput) objCaptureMetadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) objCaptureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode] } func addVideoPreviewLayer() { objCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: objCaptureSession) objCaptureVideoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill objCaptureVideoPreviewLayer?.frame = view.layer.bounds self.view.layer.addSublayer(objCaptureVideoPreviewLayer!) objCaptureSession?.startRunning() self.view.bringSubviewToFront(lblQRCodeResult) self.view.bringSubviewToFront(lblQRCodeLabel) } func initializeQRView() { vwQRCode = UIView() vwQRCode?.layer.borderColor = UIColor.redColor().CGColor vwQRCode?.layer.borderWidth = 5 self.view.addSubview(vwQRCode!) self.view.bringSubviewToFront(vwQRCode!) } func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { if metadataObjects == nil || metadataObjects.count == 0 { vwQRCode?.frame = CGRectZero lblQRCodeResult.text = "QR Code wans't found" return } let objMetadataMachineReadableCodeObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if objMetadataMachineReadableCodeObject.type == AVMetadataObjectTypeQRCode { let objBarCode = objCaptureVideoPreviewLayer?.transformedMetadataObjectForMetadataObject(objMetadataMachineReadableCodeObject as AVMetadataMachineReadableCodeObject) as! AVMetadataMachineReadableCodeObject vwQRCode?.frame = objBarCode.bounds; if objMetadataMachineReadableCodeObject.stringValue != nil { lblQRCodeResult.text = objMetadataMachineReadableCodeObject.stringValue } } } }


81
投票

查看ZBar读取QR码和ECN / ISBN代码,并在LGPL v2许可下可用。


54
投票

iOS7的发布一样,您不再需要使用外部框架或库。拥有AVFoundation的iOS生态系统现在完全支持扫描从EAN到UPC的QR中的几乎所有代码。

只需看看Tech Note和AVFoundation编程指南。 AVMetadataObjectTypeQRCode是你的朋友。

这是一个很好的教程,一步一步地显示它:iPhone QR code scan library iOS7

关于如何设置它的一个小例子:

#pragma mark -
#pragma mark AVFoundationScanSetup

- (void) setupScanner;
{
    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];

    self.session = [[AVCaptureSession alloc] init];

    self.output = [[AVCaptureMetadataOutput alloc] init];
    [self.session addOutput:self.output];
    [self.session addInput:self.input];

    [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    self.output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];

    self.preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
    self.preview.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);

    AVCaptureConnection *con = self.preview.connection;

    con.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;

    [self.view.layer insertSublayer:self.preview atIndex:0];
}

13
投票

iPhone 4相机更能够制作条形码。斑马线条形码库在github qazxsw poi上有一个分叉。它是开源的。


10
投票

zxing-iphone是github上“从zxing移植的Objective C中的Lite QR阅读器”,并且支持Xcode 4。


10
投票

有两个主要的图书馆:

  • liteqr是一个用Java编写的库,然后移植到Objective C / C ++(仅限QR代码)。 TheLevelUp:ZXing已经完成了ObjC的另一个端口
  • ZXingObjC是一个用于阅读条形码的开源软件,基于C语言。

根据我的实验,ZBar比ZXing更准确,更快,至少在iPhone上。


7
投票

qazxsw poi,指向qazxsw poi,看起来很有帮助(qazxsw poi)。


6
投票

您可以在下面找到使用Swift 4和Xcode 9的另一个原生iOS解决方案。本解决方案中使用的本机ZBar框架。

第一部分是HOWTO: Add a barcode reader to an iPhone app的子类,它具有ZBar iPhone SDK的相关设置和处理函数。

from another thread

第二部分是AVFoundationUIViewController子类的扩展,我们捕获捕获的输出。

AVCaptureSession

更新Swift 4.2

import UIKit import AVFoundation class BarCodeScannerViewController: UIViewController { let captureSession = AVCaptureSession() var videoPreviewLayer: AVCaptureVideoPreviewLayer! var initialized = false let barCodeTypes = [AVMetadataObject.ObjectType.upce, AVMetadataObject.ObjectType.code39, AVMetadataObject.ObjectType.code39Mod43, AVMetadataObject.ObjectType.code93, AVMetadataObject.ObjectType.code128, AVMetadataObject.ObjectType.ean8, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.aztec, AVMetadataObject.ObjectType.pdf417, AVMetadataObject.ObjectType.itf14, AVMetadataObject.ObjectType.dataMatrix, AVMetadataObject.ObjectType.interleaved2of5, AVMetadataObject.ObjectType.qr] override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) setupCapture() // set observer for UIApplicationWillEnterForeground, so we know when to start the capture session again NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: .UIApplicationWillEnterForeground, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // this view is no longer topmost in the app, so we don't need a callback if we return to the app. NotificationCenter.default.removeObserver(self, name: .UIApplicationWillEnterForeground, object: nil) } // This is called when we return from another app to the scanner view @objc func willEnterForeground() { setupCapture() } func setupCapture() { var success = false var accessDenied = false var accessRequested = false let authorizationStatus = AVCaptureDevice.authorizationStatus(for: .video) if authorizationStatus == .notDetermined { // permission dialog not yet presented, request authorization accessRequested = true AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted:Bool) -> Void in self.setupCapture(); }) return } if authorizationStatus == .restricted || authorizationStatus == .denied { accessDenied = true } if initialized { success = true } else { let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInTelephotoCamera, .builtInDualCamera], mediaType: .video, position: .unspecified) if let captureDevice = deviceDiscoverySession.devices.first { do { let videoInput = try AVCaptureDeviceInput(device: captureDevice) captureSession.addInput(videoInput) success = true } catch { NSLog("Cannot construct capture device input") } } else { NSLog("Cannot get capture device") } } if success { DispatchQueue.global().async { self.captureSession.startRunning() DispatchQueue.main.async { let captureMetadataOutput = AVCaptureMetadataOutput() self.captureSession.addOutput(captureMetadataOutput) let newSerialQueue = DispatchQueue(label: "barCodeScannerQueue") // in iOS 11 you can use main queue captureMetadataOutput.setMetadataObjectsDelegate(self, queue: newSerialQueue) captureMetadataOutput.metadataObjectTypes = self.barCodeTypes self.videoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession) self.videoPreviewLayer.videoGravity = .resizeAspectFill self.videoPreviewLayer.frame = self.view.layer.bounds self.view.layer.addSublayer(self.videoPreviewLayer) } } initialized = true } else { // Only show a dialog if we have not just asked the user for permission to use the camera. Asking permission // sends its own dialog to th user if !accessRequested { // Generic message if we cannot figure out why we cannot establish a camera session var message = "Cannot access camera to scan bar codes" #if (arch(i386) || arch(x86_64)) && (!os(macOS)) message = "You are running on the simulator, which does not hae a camera device. Try this on a real iOS device." #endif if accessDenied { message = "You have denied this app permission to access to the camera. Please go to settings and enable camera access permission to be able to scan bar codes" } let alertPrompt = UIAlertController(title: "Cannot access camera", message: message, preferredStyle: .alert) let confirmAction = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in self.navigationController?.popViewController(animated: true) }) alertPrompt.addAction(confirmAction) self.present(alertPrompt, animated: true, completion: nil) } } } func handleCapturedOutput(metadataObjects: [AVMetadataObject]) { if metadataObjects.count == 0 { return } guard let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject else { return } if barCodeTypes.contains(metadataObject.type) { if let metaDataString = metadataObject.stringValue { captureSession.stopRunning() displayResult(code: metaDataString) return } } } func displayResult(code: String) { let alertPrompt = UIAlertController(title: "Bar code detected", message: code, preferredStyle: .alert) if let url = URL(string: code) { let confirmAction = UIAlertAction(title: "Launch URL", style: .default, handler: { (action) -> Void in UIApplication.shared.open(url, options: [:], completionHandler: { (result) in if result { NSLog("opened url") } else { let alertPrompt = UIAlertController(title: "Cannot open url", message: nil, preferredStyle: .alert) let confirmAction = UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in }) alertPrompt.addAction(confirmAction) self.present(alertPrompt, animated: true, completion: { self.setupCapture() }) } }) }) alertPrompt.addAction(confirmAction) } let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in self.setupCapture() }) alertPrompt.addAction(cancelAction) present(alertPrompt, animated: true, completion: nil) } } changes为UIViewController


5
投票

不确定这是否有用,但这里是一个开源AVCaptureMetadataOutputObjectsDelegate的链接。正如你所看到的,有几个人已经用它来为iPhone创建应用程序。

维基百科有一篇文章解释extension BarCodeScannerViewController: AVCaptureMetadataOutputObjectsDelegate { func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { handleCapturedOutput(metadataObjects: metadataObjects) } } 。在我看来,QR码比ip​​hone所关注的标准条码更适合用途,因为它是为这种类型的实现而设计的。

© www.soinside.com 2019 - 2024. All rights reserved.