简介: 这里介绍在IOS7 中使用AVFoundation扫描二维码

在 iOS7 以前,在iOS中实现二维码和条形码扫描,我们所知的有,两大开源组件ZBar与ZXing. 这两大组件我们都有用过,这里总结下各自的缺点:

ZBar在扫描的灵敏度上,和内存的使用上相对于ZXing上都是较优的,但是对于 “圆角二维码” 的扫描确很困难。

ZXing 是 Google Code上的一个开源的条形码扫描库,是用java设计的,连Google Glass 都在使用的。但有人为了追求更高效率以及可移植性,出现了c++ port. Github上的Objectivc-C port,其实就是用OC代码封装了一下而已,而且已经停止维护。这样效率非常低,在instrument下面可以看到CPU和内存疯涨,在内存小的机器上很容易崩溃。

iOS 7以后AVFoundation开始支持扫描了.AVFoundation无论在扫描灵敏度和性能上来说都是最优的,所以毫无疑问我们应该切换到AVFoundation,需要兼容iOS 6或之前的版本可以用zbar或zxing代替。

下面介绍本文的重点,无论你是用以上哪一种或其他的解决方案,都需要知道下面两点。

1. 图片很小的二维码

以前测试提了一个bug,说有二维码扫不了,拿到二维码一看,是个很小的二维码,边长不到1cm,于是就修改了 sessionPreset 为 1080p 的,当时用的是ZXing, 当把图片质量改清楚时,也造成了性能的下降,基本打开扫描界面就会报memoryWarning,但是也确实解决了小二维码扫描的问题。

AVCaptureSession 可以设置 sessionPreset 属性,这个决定了视频输入每一帧图像质量的大小。

  • AVCaptureSessionPreset320x240
  • AVCaptureSessionPreset352x288
  • AVCaptureSessionPreset640x480
  • AVCaptureSessionPreset960x540
  • AVCaptureSessionPreset1280x720
  • AVCaptureSessionPreset1920x1080

以上列举了部分的属性值,分别代表输入图片质量大小,一般来说AVCaptureSessionPreset640x480就够使用,但是如果要保证较小的二维码图片能快速扫描,最好设置高些,如AVCaptureSessionPreset1920x1080(就是我们常说的1080p).

2. scanCrop

另一个提升扫描速度和性能的就是设置解析的范围,在zbar和zxing中就是scanCrop, AVFoundation中设置 AVCaptureMetadataOutput 的 rectOfInterest 属性来配置解析范围。

最开始我按照文档说的按照比例值来设置这个属性,如下:

CGSize size = self.view.bounds.size;
CGRect cropRect = CGRectMake(40, 100, 240, 240);
captureOutput.rectOfInterest = CGRectMake(cropRect.origin.x/size.width,cropRect.origin.y/size.height,cropRect.size.width/size.width,cropRect.size.height/size.height);

但是发现, Ops, 好像不对啊,扫不到了,明显不正确呢,于是猜想: AVCapture输出的图片大小都是横着的,而iPhone的屏幕是竖着的,那么我把它旋转90°呢:

CGSize size = self.view.bounds.size;
CGRect cropRect = CGRectMake(40, 100, 240, 240);
captureOutput.rectOfInterest = CGRectMake(cropRect.origin.y/size.height,cropRect.origin.x/size.width,cropRect.size.height/size.height,cropRect.size.width/size.width);

OK,貌似对了,在iPhone5上一切工作良好,但是在4s上,或者换了sessionPreset的大小之后,这个框貌似就不那么准确了, 可能发现超出框上下一些也是可以扫描出来的。 再次猜想: 图片的长宽比和手机屏幕不是一样的,这个rectOfInterest是相对于图片大小的比例。比如iPhone4s屏幕大小是 640x960, 而图片输出大小是 1920x1080.

iPhone4s屏幕,大小640x960, 上面代表AVCaptureVideoPreviewLayer中预览到的图片位置,在图片输入为1920x1080大小时,实际大小上下会被截取一点的,因为我们AVCaptureVideoPreviewLayer设置的videoGravity是AVLayerVideoGravityResizeAspectFill, 类似于UIView的UIViewContentModeScaleAspectFill效果。

于是我对大小做了一下修正:

CGSize size = self.view.bounds.size;

CGRect cropRect = CGRectMake(40, 100, 240, 240);

CGFloat p1 = size.height/size.width;

CGFloat p2 = 1920./1080.;  //使用了1080p的图像输出

if (p1 < p2) {

CGFloat fixHeight = bounds.size.width * 1920. / 1080.;

CGFloat fixPadding = (fixHeight - size.height)/2;

captureOutput.rectOfInterest = CGRectMake((cropRect.origin.y + fixPadding)/fixHeight,

cropRect.origin.x/size.width,

cropRect.size.height/fixHeight,

cropRect.size.width/size.width);

else {

CGFloat fixWidth = bounds.size.height * 1080. / 1920.;

CGFloat fixPadding = (fixWidth - size.width)/2;

captureOutput.rectOfInterest = CGRectMake(cropRect.origin.y/size.height,

(cropRect.origin.x + fixPadding)/fixWidth,

cropRect.size.height/size.height,

cropRect.size.width/fixWidth);

}

经过上面的验证,证实了猜想rectOfInterest是基于图像的大小裁剪的。

下面跟上本人时间用AVFoundation扫描的测试代码,没有做UI调整只能单次扫描:

#import

@interface ViewController : UIViewController

@property (strong,nonatomic)AVCaptureDevice *device;

@property (strong,nonatomic)AVCaptureDeviceInput *input;

@property (strong,nonatomic)AVCaptureMetadataOutput *output;

@property (strong,nonatomic)AVCaptureSession *session;

@property (strong,nonatomic)AVCaptureVideoPreviewLayer *preview;

@end

- (IBAction)setupCamera

{

// Device

self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

// Input

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

// Output

self.output = [[AVCaptureMetadataOutput alloc]init];

[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

// Session

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

[self.session setSessionPreset:AVCaptureSessionPresetHigh];

if ([self.session canAddInput:self.input])

{

[self.session addInput:self.input];

}

if ([self.session canAddOutput:self.output])

{

[self.session addOutput:self.output];

}

// 条码类型

self.output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];

// Preview

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

[self.view.layer addSublayer:self.preview];

// Start

[self.session startRunning];

}

//

//条码类型有如下几种:

//AVMetadataObjectTypeUPCECode

//AVMetadataObjectTypeCode39Code

//AVMetadataObjectTypeCode39Mod43Code

//AVMetadataObjectTypeEAN13Code

//AVMetadataObjectTypeEAN8Code

//AVMetadataObjectTypeCode93Code

//AVMetadataObjectTypeCode128Code

//AVMetadataObjectTypePDF417Code

//AVMetadataObjectTypeQRCode

//AVMetadataObjectTypeAztecCode

//

//扫瞄到二维码之后,会调用delegate

#pragma mark AVCaptureMetadataOutputObjectsDelegate

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection

{

NSString *stringValue;

if ([metadataObjects count] >0) {

AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex:0];

stringValue = metadataObject.stringValue;

NSLog(@"==========%@",stringValue);

}

[_session stopRunning];

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil

message:stringValue

delegate:nil

cancelButtonTitle:@"OK"

otherButtonTitles:nil,nil];

[alert show];

}

IOS7实现扫描二维码相关推荐

  1. 【转】借助第三方支持https协议的存储实现自己网站上扫描二维码安装IOS APP

    使用plist安装,一般是企业级开发者账号不需要登录到APP STORE的IOS设备应用发布时所用到的技巧. 准备: *一台运行着OSX的苹果电脑,最新版的XCODE,用于导出ipa和plist 一个 ...

  2. iOS中 扫描二维码/生成二维码详解

    最近大家总是问我有没有关于二维码的demo,为了满足大家的需求,特此研究了一番,希望能帮到大家! 指示根视图: ? 1 self.window.rootViewController = [[UINav ...

  3. 关于Unity调用摄像头扫描二维码与生成二维码的实现方法

    1.常用的生成二维码网址 https://cli.im/ 2.上官网下载二维码插件 http://zxingnet.codeplex.com/ 3.将下载的插件中zxing.unity.dll文件放入 ...

  4. Android扫描二维码 实现 登录网页

    工程代码:ScanQRcode.zip ------------------------------------------------------------------ 1. 扫描二维码登录的实现 ...

  5. 转【微信小程序 四】二维码生成/扫描二维码

    原文:https://blog.csdn.net/xbw12138/article/details/75213274 前端  二维码生成  二维码要求:每分钟刷新一次,模拟了个鸡肋,添加了个按分钟显示 ...

  6. 解决android扫描二维码时,用户禁止权限报错问题

    当我用ZBarDecoder.jar写了一个扫描二维码的程序,确实实现了扫描功能.组长说如果用户禁止调用摄像头,那程序也不能崩溃.结果我一运行就崩溃了.在网上自己找了找,可以这样解决. try { m ...

  7. 扫描二维码读取文档_使用深度学习读取和分类扫描的文档

    扫描二维码读取文档 To many people's dismay, there is still a giant wealth of paper documents floating out the ...

  8. 基于ZXing Android实现生成二维码图片和相机扫描二维码图片即时解码的功能

    NextQRCode ZXing开源库的精简版 **基于ZXing Android实现生成二维码图片和相机扫描二维码图片即时解码的功能 原文博客 附源码下载地址** 与原ZXingMini项目对比 N ...

  9. Teams App 扫描二维码

    上篇文章我们讲了如何在app的manifest里设置设备的权限,这篇文章我们来实际操作开发一个可以扫描二维码的teams app. 首先,我们先到app studio里,创建一个teams app,然 ...

最新文章

  1. 最全的大数据解决方案(多图)
  2. 如果类是个泛型类的话dllImport 代码不能编译
  3. 删除win10自带的旧版edge浏览器(亲测有效)
  4. 云计算灾备:灾备通识
  5. [C语言] va_start和va_end详解
  6. mac mysql ngram_MySQL ngram
  7. itchat没了咱们还可以用Python的wxpy模块来玩转微信
  8. xgboost: 速度快效果好的boosting模型
  9. 新商业时代最大的机会在于创业市场
  10. vb net excel 剪贴板 粘贴_Excel零基础教程选项卡功能详解
  11. 2020,新年快乐!
  12. Atitit vue.js 把ajax数据 绑定到form表单
  13. .如何彻底删除oracle,如何做到Oracle完全卸载
  14. 超定方程 matlab,Matlab求解超定方程组实例(精品文档)
  15. ORA-24761: transaction rolled back
  16. 支付宝APP参数SDK转换URL网页链接
  17. React-native 开启DEBUG模式后应用闪退
  18. 教程篇(7.0) 04. FortiGate安全 NAT ❀ Fortinet 网络安全专家 NSE 4
  19. 信息系统项目管理师学习笔记5——信息化与信息系统5
  20. vue实现页面锁屏完美解决

热门文章

  1. bioinformaitcs的latex版本参考文献填坑
  2. Windows 2003 Server 用户隔离
  3. 关于java中的数组
  4. Lotus 下部门间用户的移动操作
  5. 如何制作U盘启动菜单
  6. ASP应用之模板采用
  7. where嵌套select_Select子查询:Select Zoo
  8. python 进度条_六种酷炫Python运行进度条
  9. 领地柜怎么砸_5㎡餐厅也配有餐边柜!布局、尺寸都给你们准备好,照着装准没错...
  10. php查询oracle大量数据,Oracle 百万行数据查询优化