К сожалению, камера 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.
@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твой друг.
Если вы хотите обнаружить штрих-код на изображении на iOS8, это руководство может оказаться полезным.
NSDeveloper 09
Я обнаружил, что мне нужно вызвать startRunningсеанс, чтобы заставить приведенный выше код работать, в случае, если это кому-то поможет :)
Крис
13
Камера iPhone 4 более чем способна создавать штрих-коды. Библиотека штрих-кодов «зебра» имеет вилку на github zxing-iphone . Это открытый исходный код.
ZXing библиотеку, написанную на Java, а затем портированную на Objective C / C ++ (только QR-код). И еще один перенос на ObjC был сделан TheLevelUp: ZXingObjC
ZBar - программное обеспечение с открытым исходным кодом для считывания штрих-кодов на основе C.
Согласно моим экспериментам, ZBar намного точнее и быстрее, чем ZXing, по крайней мере, на iPhone.
Мне кажется, что ZXingObjC - это тот, который к настоящему времени должен быть продвинут на вершину с наибольшим количеством голосов. Я не использовал его еще , но описание говорит , что на паритете с ZXing 2.0.
Shaolo
Лицензия ZBar требует, чтобы вы предлагали объектные файлы пользователям, чтобы они могли запускать их и изменять свою библиотеку.
Вы можете найти другое собственное решение для iOS с использованием Swift 4 и Xcode 9 ниже. Собственная AVFoundationструктура, используемая в этом решении.
Первая часть - это подкласс, для UIViewControllerкоторого есть связанные функции настройки и обработчика AVCaptureSession.
import UIKit
import AVFoundation
classBarCodeScannerViewController: UIViewController{
let captureSession = AVCaptureSession()
var videoPreviewLayer: AVCaptureVideoPreviewLayer!var initialized = falselet 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]
overridefuncviewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupCapture()
// set observer for UIApplicationWillEnterForeground, so we know when to start the capture session againNotificationCenter.default.addObserver(self,
selector: #selector(willEnterForeground),
name: .UIApplicationWillEnterForeground,
object: nil)
}
overridefuncviewWillDisappear(_ 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@objcfuncwillEnterForeground() {
setupCapture()
}
funcsetupCapture() {
var success = falsevar accessDenied = falsevar accessRequested = falselet authorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
if authorizationStatus == .notDetermined {
// permission dialog not yet presented, request authorization
accessRequested = trueAVCaptureDevice.requestAccess(for: .video,
completionHandler: { (granted:Bool) -> Voidinself.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)
iflet captureDevice = deviceDiscoverySession.devices.first {
do {
let videoInput = tryAVCaptureDeviceInput(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 userif !accessRequested {
// Generic message if we cannot figure out why we cannot establish a camera sessionvar 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) -> Voidinself.navigationController?.popViewController(animated: true)
})
alertPrompt.addAction(confirmAction)
self.present(alertPrompt, animated: true, completion: nil)
}
}
}
funchandleCapturedOutput(metadataObjects: [AVMetadataObject]) {
if metadataObjects.count == 0 {
return
}
guardlet metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObjectelse {
return
}
if barCodeTypes.contains(metadataObject.type) {
iflet metaDataString = metadataObject.stringValue {
captureSession.stopRunning()
displayResult(code: metaDataString)
return
}
}
}
funcdisplayResult(code: String) {
let alertPrompt = UIAlertController(title: "Bar code detected", message: code, preferredStyle: .alert)
iflet url = URL(string: code) {
let confirmAction = UIAlertAction(title: "Launch URL", style: .default, handler: { (action) -> VoidinUIApplication.shared.open(url, options: [:], completionHandler: { (result) inif 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) -> Voidin
})
alertPrompt.addAction(confirmAction)
self.present(alertPrompt, animated: true, completion: {
self.setupCapture()
})
}
})
})
alertPrompt.addAction(confirmAction)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Voidinself.setupCapture()
})
alertPrompt.addAction(cancelAction)
present(alertPrompt, animated: true, completion: nil)
}
}
Вторая часть - это расширение нашего UIViewControllerподкласса, в AVCaptureMetadataOutputObjectsDelegateкотором мы перехватываем захваченные выходные данные.
Не уверен, что это поможет, но вот ссылка на библиотеку QR-кода с открытым исходным кодом . Как видите, несколько человек уже использовали это для создания приложений для iphone.
В Википедии есть статья, объясняющая, что такое QR-коды . На мой взгляд, QR-коды гораздо больше подходят для этой цели, чем стандартный штрих-код, когда речь идет о iphone, поскольку он был разработан для этого типа реализации.
Если для вашего приложения важна поддержка iPad 2 или iPod Touch, я бы выбрал SDK сканера штрих-кода, который может декодировать штрих-коды в размытых изображениях, такой как наш SDK сканера штрих-кода Scandit для iOS и Android. Расшифровка размытых изображений штрих-кода также полезна на телефонах с автофокусными камерами, потому что пользователю не нужно ждать, пока сработает автофокус.
Scandit поставляется с бесплатным тарифным планом сообщества, а также имеет API-интерфейс продукта, который упрощает преобразование номеров штрих-кодов в названия продуктов.
(Отказ от ответственности: я соучредитель Scandit)
Прямая ссылка (не думаю, что 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 'SimpleBarcodeScanner'do
pod 'BarcodeScanner'
end
Не забудьте добавить разрешение камеры в файл .plist.
Если вы разрабатываете для iOS> 10.2 с Swift 4, вы можете попробовать мое решение. Я перепутал это и это руководство и придумал ViewController, который сканирует QR-код и print()выдает его. У меня также есть переключатель в моем пользовательском интерфейсе, чтобы переключать свет камеры, тоже может быть полезно. Пока я тестировал его только на iPhone SE, дайте мне знать, если он не работает на новых iPhone.
Ну вот:
import UIKit
import AVFoundation
classQRCodeScanner: UIViewController, AVCaptureMetadataOutputObjectsDelegate{
let captureSession: AVCaptureSession = AVCaptureSession()
var videoPreviewLayer: AVCaptureVideoPreviewLayer?let qrCodeFrameView: UIView = UIView()
var captureDevice: AVCaptureDevice?overridefuncviewDidLoad() {
// Get the back-facing camera for capturing videoslet 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 = tryAVCaptureDeviceInput(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)
iflet videoPreviewLayer = videoPreviewLayer {
videoPreviewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
videoPreviewLayer.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer)
// Start video capture.
captureSession.startRunning()
iflet 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@IBActionfuncswitchFlashChanged(_ sender: UISwitch) {
do {
if sender.isOn {
captureDevice?.torchMode = .on
} else {
captureDevice?.torchMode = .off
}
}
}
// MARK: AVCaptureMetadataOutputObjectsDelegatefuncmetadataOutput(_ 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! AVMetadataMachineReadableCodeObjectif 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 boundslet barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
qrCodeFrameView.frame = barCodeObject!.bounds
print("QR Code: \(metadataObj.stringValue)")
}
}
}
Иногда может быть полезно также сгенерировать QR-коды . Для этого есть превосходная библиотека C, которая работает как шарм. Он называется libqrencode . В этом случае написать собственное представление для отображения QR-кода не так сложно, и его можно сделать с базовым пониманием QuartzCore.
знаете ли вы какое-либо руководство о том, как включить это в проект iOS xCode?
james
не могли бы вы рассказать, как вы сгенерировали представление с помощью quartcore? было бы
здорово сэкономить время
Это верно. Однако убедитесь, что вы соответствуете лицензии на программное обеспечение, с которой публикуется библиотека.
GorillaPatch
Этот вопрос касается признания, а не поколения.
MonsieurDart
0
вы можете проверить ZBarSDK, чтобы прочитать QR-код и коды ECN / ISBN, это просто интегрировать, попробуйте следующий код.
- (void)scanBarcodeWithZBarScanner
{
// ADD: present a barcode reader that scans from the camera feedZBarReaderViewController *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 barcodebreak;
// 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];
}
Ответы:
Мы сделали приложение «Штрих-коды» для iPhone. Он может декодировать QR-коды. Исходный код доступен в проекте zxing ; в частности, вы хотите взглянуть на клиент iPhone и частичный порт C ++ основной библиотеки . Порт немного устарел, примерно от версии 0.9 кода Java, но все равно должен работать достаточно хорошо.
Если вам нужно сканировать другие форматы, например форматы 1D, вы можете продолжить перенос кода Java в этом проекте на C ++.
РЕДАКТИРОВАТЬ: штрих-коды и
iphone
код в проекте были удалены примерно в начале 2014 года.источник
Обратите внимание, что ZBar считывает QR-код и коды ECN / ISBN и доступен по лицензии LGPL v2.
источник
Как и в случае с выпуском,
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]; }
источник
startRunning
сеанс, чтобы заставить приведенный выше код работать, в случае, если это кому-то поможет :)Камера iPhone 4 более чем способна создавать штрих-коды. Библиотека штрих-кодов «зебра» имеет вилку на github zxing-iphone . Это открытый исходный код.
источник
liteqr - это "Lite QR Reader в Objective C, перенесенный из zxing" на github и поддерживающий Xcode 4.
источник
Есть две основные библиотеки:
ZXing библиотеку, написанную на Java, а затем портированную на Objective C / C ++ (только QR-код). И еще один перенос на ObjC был сделан TheLevelUp: ZXingObjC
ZBar - программное обеспечение с открытым исходным кодом для считывания штрих-кодов на основе C.
Согласно моим экспериментам, ZBar намного точнее и быстрее, чем ZXing, по крайней мере, на iPhone.
источник
HOWTO: Добавление считывателя штрих-кода в приложение для iPhone , которое указывает на ZBar iPhone SDK , выглядит полезным ( из другого потока ).
источник
Вы можете найти другое собственное решение для 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
.источник
metadataObjects
внутри функции handleCapturedOutput .Не уверен, что это поможет, но вот ссылка на библиотеку QR-кода с открытым исходным кодом . Как видите, несколько человек уже использовали это для создания приложений для iphone.
В Википедии есть статья, объясняющая, что такое QR-коды . На мой взгляд, QR-коды гораздо больше подходят для этой цели, чем стандартный штрих-код, когда речь идет о iphone, поскольку он был разработан для этого типа реализации.
источник
Если для вашего приложения важна поддержка iPad 2 или iPod Touch, я бы выбрал SDK сканера штрих-кода, который может декодировать штрих-коды в размытых изображениях, такой как наш SDK сканера штрих-кода Scandit для iOS и Android. Расшифровка размытых изображений штрих-кода также полезна на телефонах с автофокусными камерами, потому что пользователю не нужно ждать, пока сработает автофокус.
Scandit поставляется с бесплатным тарифным планом сообщества, а также имеет API-интерфейс продукта, который упрощает преобразование номеров штрих-кодов в названия продуктов.
(Отказ от ответственности: я соучредитель Scandit)
источник
Вы можете взглянуть на исходный код iPhone DataMatrix Reader Штефана Хафенегера ( проект Google Code ; архивная запись в блоге ), если он еще доступен.
источник
Проблема с камерой iPhone заключается в том, что в первых моделях (которых используется множество) есть камера с фиксированным фокусом, которая не может делать снимки в фокусе на расстояниях менее 2 футов. Изображения расплывчаты и искажены, а если они сняты с большого расстояния, штрих-код не содержит достаточных деталей / информации.
Несколько компаний разработали приложения для iPhone, которые могут приспособиться к этому с помощью передовых технологий устранения размытости. Эти приложения вы можете найти в магазине приложений Apple: pic2shop, RedLaser и ShopSavvy. Все компании объявили, что у них также доступны SDK - некоторые бесплатно или на очень льготных условиях, проверьте это.
источник
со 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) } }
Тем не менее, и любые вопросы или проблемы, пожалуйста, проверьте здесь образец приложения с полным исходным кодом
источник
Если вы ищете собственный сканер штрих-кода iOS 7, посмотрите мой проект на GitHub:
источник
Я считаю, что это можно сделать с помощью 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 } } } }
источник
Вот простой код:
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 }
источник
Если вы разрабатываете для 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)") } } }
источник
Иногда может быть полезно также сгенерировать QR-коды . Для этого есть превосходная библиотека C, которая работает как шарм. Он называется libqrencode . В этом случае написать собственное представление для отображения QR-кода не так сложно, и его можно сделать с базовым пониманием QuartzCore.
источник
вы можете проверить 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]; }
источник