Как я могу сканировать штрих-коды на iOS? - PullRequest
184 голосов
/ 08 мая 2009

Как я могу просто сканировать штрих-коды на iPhone и / или iPad?

Ответы [ 19 ]

81 голосов
/ 05 мая 2010

Check ZBar считывает QR-код и ECN / ISBN-коды и доступно как по лицензии LGPL v2.

80 голосов
/ 14 мая 2009

Мы создали приложение «Штрих-коды» для iPhone. Он может декодировать QR-коды. Исходный код доступен из проекта zxing ; в частности, вы хотите взглянуть на клиент для iPhone и частичный порт C ++ базовой библиотеки . Порт немного старый, начиная с версии 0.9 Java-кода, но все равно должен работать достаточно хорошо.

Если вам нужно сканировать другие форматы, например, 1D, вы можете продолжить порт Java-кода в этом проекте на C ++.

РЕДАКТИРОВАТЬ: Штрих-коды и код iphone в проекте были удалены в начале 2014 года.

54 голосов
/ 14 октября 2013

Как и в выпуске iOS7, вам больше не нужно использовать внешний каркас или библиотеку. Экосистема iOS с AVFoundation теперь полностью поддерживает сканирование почти каждого кода от QR через EAN до UPC.

Просто взгляните на Техническую записку и руководство по программированию AVFoundation. AVMetadataObjectTypeQRCode твой друг.

Вот хороший учебник , который показывает его шаг за шагом: Библиотека QR-кодов iPhone 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 голосов
/ 08 декабря 2010

Камера iPhone 4 - это больше, чем просто возможность делать штрих-коды. Библиотека штрих-кодов для зебры имеет вилку на github zxing-iphone . Это с открытым исходным кодом.

10 голосов
/ 06 июня 2011

liteqr - это «Lite QR Reader в Objective C, перенесенный с zxing» на github и поддерживающий Xcode 4.

10 голосов
/ 19 ноября 2012

Есть две основные библиотеки:

  • ZXing библиотека, написанная на Java, а затем перенесенная в Objective C / C ++ (только QR-код). И еще один порт для ObjC был сделан, TheLevelUp: ZXingObjC

  • ZBar программное обеспечение с открытым исходным кодом для считывания штрих-кодов на основе C.

Согласно моим экспериментам, ZBar гораздо точнее и быстрее , чем ZXing, по крайней мере, на iPhone.

7 голосов
/ 17 января 2011
6 голосов
/ 14 мая 2018

Вы можете найти другое нативное решение для iOS, используя Swift 4 и Xcode 9 ниже. Встроенный AVFoundation каркас, используемый в этом решении.

Первая часть - это подкласс UIViewController, который имеет связанные функции настройки и обработки для AVCaptureSession.

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)
    }

}

Вторая часть - это расширение нашего подкласса UIViewController для AVCaptureMetadataOutputObjectsDelegate, где мы собираем захваченные выходные данные.

extension BarCodeScannerViewController: AVCaptureMetadataOutputObjectsDelegate {

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

}

Обновление для Swift 4.2

.UIApplicationWillEnterForeground изменяется как UIApplication.willEnterForegroundNotification.

5 голосов
/ 25 сентября 2012

Если для вашего приложения важна поддержка iPad 2 или iPod Touch, я бы выбрал SDK для сканера штрих-кодов, который может декодировать штрих-коды в расплывчатых изображениях, например, наш Scandit сканер штрих-кода SDK для iOS и Android. Декодирование расплывчатых изображений штрих-кода также полезно на телефонах с камерами с автофокусировкой, поскольку пользователю не нужно ждать срабатывания автофокуса.

Scandit поставляется с бесплатным тарифным планом сообщества, а также имеет API-интерфейс продукта, который позволяет легко преобразовывать номера штрих-кодов в названия продуктов.

(Отказ от ответственности: я являюсь соучредителем Scandit)

5 голосов
/ 08 мая 2009

Не уверен, поможет ли это, но вот ссылка на открытый исходный код Библиотека QR-кодов . Как вы можете видеть, несколько человек уже использовали это для создания приложений для iphone.

В Википедии есть статья, объясняющая , что такое QR-коды . На мой взгляд, QR-коды гораздо лучше подходят для использования, чем стандартный штрих-код для iphone, так как он был разработан для реализации такого типа.

...