Swift - 二维码QRCode的读取(从图片读取 ,或通过摄像头扫描)
(本文代码已升级至Swift4)
一、直接读取图片中的二维码
使用 CIDetector 可以很方便的检测并读取二维码。下面是一个从 UIImage 中读取二维码的样例,我们要把图片上所有的二维码信息都打印出来。
代码如下:
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let qrcodeImg = UIImage(named: "codeBg.png") let ciImage:CIImage=CIImage(image:qrcodeImg!)! let context = CIContext(options: nil) let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh]) let features = detector?.features(in: ciImage) print("扫描到二维码个数:\(features?.count ?? 0)") //遍历所有的二维码,并框出 for feature in features as! [CIQRCodeFeature] { print(feature.messageString ?? "") } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
控制台输出如下:
扫描到二维码个数:2
http://www.hangge.com
http://www.hangge.com
可以看到两个二维码都成功的读取到了。
http://www.hangge.com
http://www.hangge.com
(注:这个我原来用模拟器一直检测不到二维码,使用真机调试就没问题。感谢网友“落叶”的提醒,模拟器选iphone5s及以上设备也是可以检测到的。)
(2)通过 AVCaptureMetadataOutput 的 rectOfInterest 属性,可以设置探测探测区域。同时给这个探测区域添加个方框,只有在框中的二维码才会被扫描到。
二、从相册中选择图片读取二维码
1,Info.plist 配置
由于苹果安全策略更新,在使用 Xcode8 开发时,需要在 Info.plist 配置请求照片的相关描述字段(Privacy - Photo Library Usage Description)2,样例代码
import UIKit class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { override func viewDidLoad() { super.viewDidLoad() } //选取相册 @IBAction func fromAlbum(_ sender: AnyObject) { //判断设置是否支持图片库 if UIImagePickerController.isSourceTypeAvailable(.photoLibrary){ //初始化图片控制器 let picker = UIImagePickerController() //设置代理 picker.delegate = self //指定图片控制器类型 picker.sourceType = .photoLibrary //弹出控制器,显示界面 self.present(picker, animated: true, completion: { () -> Void in }) }else{ print("读取相册错误") } } //选择图片成功后代理 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { //获取选择的原图 let image = info[UIImagePickerControllerOriginalImage] as! UIImage //二维码读取 let ciImage:CIImage=CIImage(image:image)! let context = CIContext(options: nil) let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh]) if let features = detector?.features(in: ciImage) { print("扫描到二维码个数:\(features.count)") //遍历所有的二维码,并框出 for feature in features as! [CIQRCodeFeature] { print(feature.messageString ?? "") } } //图片控制器退出 picker.dismiss(animated: true, completion: { () -> Void in }) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
三、使用摄像头扫描读取二维码
(1)扫描主要使用的是 AVFoundation,用起来方便简单(2)通过 AVCaptureMetadataOutput 的 rectOfInterest 属性,可以设置探测探测区域。同时给这个探测区域添加个方框,只有在框中的二维码才会被扫描到。
1,效果图
2,Info.plist 配置
由于苹果安全策略更新,在使用 Xcode8 开发时,需要在 Info.plist 配置请求摄像头的相关描述字段(Privacy - Camera Usage Description)
3,样例代码
import UIKit import AVFoundation class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate, UIAlertViewDelegate{ var scanRectView:UIView! var device:AVCaptureDevice! var input:AVCaptureDeviceInput! var output:AVCaptureMetadataOutput! var session:AVCaptureSession! var preview:AVCaptureVideoPreviewLayer! override func viewDidLoad() { super.viewDidLoad() } //通过摄像头扫描 @IBAction func fromCamera(_ sender: AnyObject) { do{ self.device = AVCaptureDevice.default(for: AVMediaType.video) self.input = try AVCaptureDeviceInput(device: device) self.output = AVCaptureMetadataOutput() output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) self.session = AVCaptureSession() if UIScreen.main.bounds.size.height<500 { self.session.sessionPreset = AVCaptureSession.Preset.vga640x480 }else{ self.session.sessionPreset = AVCaptureSession.Preset.high } self.session.addInput(self.input) self.session.addOutput(self.output) self.output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr] //计算中间可探测区域 let windowSize = UIScreen.main.bounds.size let scanSize = CGSize(width:windowSize.width*3/4, height:windowSize.width*3/4) var scanRect = CGRect(x:(windowSize.width-scanSize.width)/2, y:(windowSize.height-scanSize.height)/2, width:scanSize.width, height:scanSize.height) //计算rectOfInterest 注意x,y交换位置 scanRect = CGRect(x:scanRect.origin.y/windowSize.height, y:scanRect.origin.x/windowSize.width, width:scanRect.size.height/windowSize.height, height:scanRect.size.width/windowSize.width); //设置可探测区域 self.output.rectOfInterest = scanRect self.preview = AVCaptureVideoPreviewLayer(session:self.session) self.preview.videoGravity = AVLayerVideoGravity.resizeAspectFill self.preview.frame = UIScreen.main.bounds self.view.layer.insertSublayer(self.preview, at:0) //添加中间的探测区域绿框 self.scanRectView = UIView(); self.view.addSubview(self.scanRectView) self.scanRectView.frame = CGRect(x:0, y:0, width:scanSize.width, height:scanSize.height); self.scanRectView.center = CGPoint( x:UIScreen.main.bounds.midX, y:UIScreen.main.bounds.midY) self.scanRectView.layer.borderColor = UIColor.green.cgColor self.scanRectView.layer.borderWidth = 1; //开始捕获 self.session.startRunning() }catch _ { //打印错误消息 let alertController = UIAlertController(title: "提醒", message: "请在iPhone的\"设置-隐私-相机\"选项中,允许本程序访问您的相机", preferredStyle: .alert) let cancelAction = UIAlertAction(title: "确定", style: .cancel, handler: nil) alertController.addAction(cancelAction) self.present(alertController, animated: true, completion: nil) } } //摄像头捕获 func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) { var stringValue:String? if metadataObjects.count > 0 { let metadataObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject stringValue = metadataObject.stringValue if stringValue != nil{ self.session.stopRunning() } } self.session.stopRunning() //输出结果 let alertController = UIAlertController(title: "二维码", message: stringValue,preferredStyle: .alert) let okAction = UIAlertAction(title: "确定", style: .default, handler: { action in //继续扫描 self.session.startRunning() }) alertController.addAction(okAction) self.present(alertController, animated: true, completion: nil) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
赞
[discovery] errors encountered while discovering extensions: Error Domain=PlugInKit Code=13 "query cancelled" UserInfo={NSLocalizedDescription=query cancelled}
出现上面错误是为什么啊?
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.
出现上面错误描述怎么办
航哥 求问有没有什么好用的名片 ocr 扫描的接口
你好,我想请教一下,如果一张图片上有N个二维码,我想通过扫描识别二维码信息,并且每个二维码信息通过回车/换行操作,这个程序能用吗?如果要修改的话怎么修改?谢啦
你好,我想请问一下获取了二维码的内容,例如我生成一个三行文字的二维码,如何解析每一行的内容出来。
2,3案例无法正常演示了
我想问一下iPhone5,5c及以下产品不能使用CIDetector识别二维码是什么原因呢?是硬件不支持吗?
第一个实例用模拟器选iphone5s 及以上设备可以检测到,iphone5 4 4s都不行,真机就可以