Как сканировать штрих-коды на iOS?

190

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

Стефан
источник
7
К сожалению, камера iPhone в настоящее время не подходит для считывания штрих-кодов, поскольку ее объектив имеет фиксированный фокус на ∞. Желаем удачи!
Аластер Стюарт
1
Только что решал эту проблему, так что напишу свои наблюдения. Я опробовал несколько вариантов. RSBarcodes_Swift - легко интегрировать, но имеет очень низкую производительность. ZBarSDK - также было легко реализовать, хотя потребовалось несколько поисков в Google, чтобы узнать, как это сделать. Но имел действительно хорошую производительность (не сканировал матрицу данных и другие редкие коды) отлично работает для штрих-кодов / QRCode. Но Scandit был лучшим из них. Очень быстро, все сканирует. к сожалению стоит довольно дорого.
Katafalkas

Ответы:

84

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

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

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

Шон Оуэн
источник
Шон, какую лицензию он использует. Я хочу создать платное приложение, использующее Zbar. Возможно ли это по лицензионному соглашению?
Radu
1
Чтобы было ясно, на данный момент ZXing на iPhone поддерживает только QR-коды?
RefuX
Я считаю, что на C ++ было перенесено больше, но, к сожалению, этот порт все еще является грубым и устаревшим отголоском кода Java. Итак, да, поддерживается больше, хотя, возможно, не очень хорошо.
Шон Оуэн
У ZXing для iPhone по-прежнему утечки памяти на 1,7 вер.
Юн Ли
Из списка проблем на git of zXing я понимаю, что мы можем сканировать штрих-код только в альбомном режиме.
Сагриан
81

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

Виджай
источник
5
Частично правильно. ZBar.app находится под лицензией Apache License (версия 2.0), однако библиотека находится под лицензией LGPL v2.
Шон
3
К сожалению, лицензия требует, чтобы вы делились объектными файлами вашего приложения со всеми, кто их запрашивает ... проверьте zbar.sourceforge.net/iphone/sdkdoc/licensing.html
Бен Клейтон
1
@BenClayton, что значит делиться объектными файлами приложения?
Dejell 05
@Odelya Отправка файлов .o, созданных Xcode, кому угодно, что теоретически позволяет им создавать ваше приложение. Я определенно не доволен этим (особенно для моих клиентов), поэтому о ZBar для нас не может быть и речи. На странице лицензирования ZBar предлагается просто «надеяться, что их никто не попросит»!
Ben Clayton
@BenClayton A. Спасибо B. Я мог бы изменить компонент, если кто-нибудь попросит и потребует от уже загруженных пользователей приложения загрузить более новую версию. Это достаточно? C. Так какую библиотеку вы используете?
Dejell 05
56

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

Просто взгляните на Tech Note и руководство по программированию 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];
}
Александр
источник
1
Если вы хотите обнаружить штрих-код на изображении на iOS8, это руководство может оказаться полезным.
NSDeveloper 09
Я обнаружил, что мне нужно вызвать startRunningсеанс, чтобы заставить приведенный выше код работать, в случае, если это кому-то поможет :)
Крис
13

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

Арис Барти
источник
1
Ваш пост, похоже, подразумевает, что этот порт ZXing может сканировать не только QR-коды? Так ли это?
RefuX
4
Форк github кажется мертвым, на что указывает эта проблема: github.com/joelind/zxing-iphone/issues/3
Джош Браун
10

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

Джош Браун
источник
10

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

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

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

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

MonsieurDart
источник
Мне кажется, что ZXingObjC - это тот, который к настоящему времени должен быть продвинут на вершину с наибольшим количеством голосов. Я не использовал его еще , но описание говорит , что на паритете с ZXing 2.0.
Shaolo
Лицензия ZBar требует, чтобы вы предлагали объектные файлы пользователям, чтобы они могли запускать их и изменять свою библиотеку.
Dejell 05
Я рекомендую ZXingObjC
Dejell
7

Вы можете найти другое собственное решение для 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.

Абдуллахселек
источник
даст ли это название продукта, размер, цену, URL-адрес продукта, валюту, название магазина? или он выдаст только номер штрих-кода @abdullahselek
Р. Мохан
@ R.Mohan это связано со штрих-кодом, который вы читаете. Проверьте AVCaptureMetadataOutput и AVMetadataMachineReadableCodeObject и попробуйте прочитать metadataObjectsвнутри функции handleCapturedOutput .
abdullahselek
Хорошо, попробую. Спасибо за ответ @abdullahselek
Р. Мохан
5

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

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

Lexx
источник
5

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

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

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

Floerkem
источник
4

Вы можете взглянуть на исходный код iPhone DataMatrix Reader Штефана Хафенегера ( проект Google Code ; архивная запись в блоге ), если он еще доступен.

Гальский
источник
Как вам нравится это приложение? Для меня требуется 10 секунд или больше, чтобы декодировать простой штрих-код матрицы данных!
iamj4de
1
Ссылка изменена на stefan.hafeneger.name/blog/2009/09/08/…
Суреш Варма
1
Прямая ссылка (не думаю, что Google на какое-то время избавится от
Кто-нибудь знает, как официально называется приложение Стефана в магазине приложений? Я хотел бы загрузить его, прежде чем погрузиться в сам код.
макутан
3

Проблема с камерой iPhone заключается в том, что в первых моделях (которых используется множество) есть камера с фиксированным фокусом, которая не может делать снимки в фокусе на расстояниях менее 2 футов. Изображения расплывчаты и искажены, а если они сняты с большого расстояния, штрих-код не содержит достаточных деталей / информации.

Несколько компаний разработали приложения для iPhone, которые могут приспособиться к этому с помощью передовых технологий устранения размытости. Эти приложения вы можете найти в магазине приложений Apple: pic2shop, RedLaser и ShopSavvy. Все компании объявили, что у них также доступны SDK - некоторые бесплатно или на очень льготных условиях, проверьте это.

Нас Банов
источник
Я пробовал использовать ShopSavvy с iphone 3G. Это забавно, но очень часто дает сбой, и ему очень, очень трудно читать очень четкие плоские штрих-коды.
Джеймс Мур
1
И я только что попробовал pic2shop. Цитата моей невесты: «КАК это должно облегчить нашу жизнь?» Это симпатичное приложение, но на самом деле оно не может считывать штрих-код, насколько я могу судить.
Джеймс Мур,
В каком формате вы пробовали читать? Я пробовал использовать pic2shop для сканирования EAN, и он работает очень хорошо. Лицензионный сбор стоит дорого, даже больше, чем у RedLaser.
iamj4de
3

со Swift 5 это просто и супер быстро !!

Вам просто нужно добавить стручки какао «BarcodeScanner», вот полный код

source 'https://github.com/CocoaPods/Specs.git' 
platform :ios, '12.0' 
target 'Simple BarcodeScanner' 
do   
pod 'BarcodeScanner' 
end

Не забудьте добавить разрешение камеры в файл .plist.

<key>NSCameraUsageDescription</key>
<string>Camera usage description</string>

И добавьте сканер и обработайте результат в свой ViewController таким образом

import UIKit
import BarcodeScanner

class ViewController: UIViewController, BarcodeScannerCodeDelegate, BarcodeScannerErrorDelegate, BarcodeScannerDismissalDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let viewController = BarcodeScannerViewController()
        viewController.codeDelegate = self
        viewController.errorDelegate = self
        viewController.dismissalDelegate = self

        present(viewController, animated: true, completion: nil)
    }

    func scanner(_ controller: BarcodeScannerViewController, didCaptureCode code: String, type: String) {
        print("Product's Bar code is :", code)
        controller.dismiss(animated: true, completion: nil)
    }

    func scanner(_ controller: BarcodeScannerViewController, didReceiveError error: Error) {
        print(error)
    }

    func scannerDidDismiss(_ controller: BarcodeScannerViewController) {
        controller.dismiss(animated: true, completion: nil)
    }
}

Тем не менее, и любые вопросы или проблемы, пожалуйста, проверьте здесь образец приложения с полным исходным кодом

SwiftBoy
источник
1

Я считаю, что это можно сделать с помощью AVFramework, вот пример кода для этого

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
            }
        }
    }
}
Джефф Д
источник
1

Вот простой код:

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
}
шиха кочар
источник
1

Если вы разрабатываете для iOS> 10.2 с Swift 4, вы можете попробовать мое решение. Я перепутал это и это руководство и придумал ViewController, который сканирует QR-код и print()выдает его. У меня также есть переключатель в моем пользовательском интерфейсе, чтобы переключать свет камеры, тоже может быть полезно. Пока я тестировал его только на iPhone SE, дайте мне знать, если он не работает на новых iPhone.

Ну вот:

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

Иногда может быть полезно также сгенерировать QR-коды . Для этого есть превосходная библиотека C, которая работает как шарм. Он называется libqrencode . В этом случае написать собственное представление для отображения QR-кода не так сложно, и его можно сделать с базовым пониманием QuartzCore.

GorillaPatch
источник
знаете ли вы какое-либо руководство о том, как включить это в проект iOS xCode?
james
не могли бы вы рассказать, как вы сгенерировали представление с помощью quartcore? было бы
здорово сэкономить время
Это верно. Однако убедитесь, что вы соответствуете лицензии на программное обеспечение, с которой публикуется библиотека.
GorillaPatch
Этот вопрос касается признания, а не поколения.
MonsieurDart
0

вы можете проверить ZBarSDK, чтобы прочитать QR-код и коды ECN / ISBN, это просто интегрировать, попробуйте следующий код.

- (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) {

}

а в didFinishPickingMediaWithInfo мы получаем значение штрих-кода.

    - (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];
   }
Амит Шелгаонкар
источник