ios7 苹果原生二维码扫描(和微信类似)

在ios7苹果推出了二维码扫描,以前想要做二维码扫描,只能通过第三方ZBar与ZXing。

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

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

AVFoundation无论在扫描灵敏度和性能上来说都是最优的。

首先要导入#import <AVFoundation/AVFoundation.h>框架

 

 其次还需要授权应用可以访问相机

    // 判断相机是否授权使用相机AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];if(status == AVAuthorizationStatusAuthorized) {} else if(status == AVAuthorizationStatusDenied){// NSLog(@"denied不允许");return ;} else if(status == AVAuthorizationStatusNotDetermined){[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {if(granted){
//                NSLog(@"允许");} else {
//                NSLog(@"不允许");return;}}];}//    typedef enum
//        AVAuthorizationStatusNotDetermined = 0, // 用户尚未做出选择这个应用程序的问候
//        AVAuthorizationStatusRestricted,        // 此应用程序没有被授权访问的照片数据。可能是家长控制权限
//        AVAuthorizationStatusDenied,            // 用户已经明确否认了这一照片数据的应用程序访问
//        AVAuthorizationStatusAuthorized         // 用户已经授权应用访问照片数据} CLAuthorizationStatus;

 

 

完成二维码扫描大致有十个步骤:

    // 1.获取输入设备AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];// 2.创建输入对象NSError *error;AVCaptureDeviceInput *inPut = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];if (inPut == nil) {UIAlertView *aler = [[UIAlertView alloc] initWithTitle:@"提示" message:@"设备不可用" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];[self.view addSubview:aler];[aler show];return;}// 3.创建输出对象AVCaptureMetadataOutput *outPut = [[AVCaptureMetadataOutput alloc] init];// 4.设置代理监听输出对象的输出流  (说明:使用主线程队列,相应比较同步,使用其他队列,相应不同步,容易让用户产生不好的体验)
    [outPut setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];// 5.创建会话AVCaptureSession *session = [[AVCaptureSession alloc] init];self.session = session;// 6.将输入和输出对象添加到会话if ([session canAddInput:inPut]) {[session addInput:inPut];}if ([session canAddOutput:outPut]) {[session addOutput:outPut];}// 7.告诉输出对象, 需要输出什么样的数据  // 提示:一定要先设置会话的输出为output之后,再指定输出的元数据类型!
    [outPut setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];// 8.创建预览图层AVCaptureVideoPreviewLayer *preViewLayer = [AVCaptureVideoPreviewLayer layerWithSession:session];preViewLayer.frame = self.view.bounds;[self.view.layer insertSublayer:preViewLayer atIndex:0];// 9.设置扫面范围outPut.rectOfInterest = CGRectMake(0.2, 0.18, 0.6, 0.5);// 10.设置扫描框UIView *boxView = [[UIView alloc] initWithFrame:CGRectMake(0.2 * SrceenW, 0.18 * SrceenH, 0.6 * SrceenW, 0.5 * SrceenH)];self.boxView = boxView;boxView.layer.borderColor = [UIColor yellowColor].CGColor;boxView.layer.borderWidth = 3;[self.view addSubview:boxView];// 设置扫描线CALayer *scanLayer = [[CALayer alloc] init];self.scanLayer = scanLayer;scanLayer.frame = CGRectMake(0, 0, boxView.bounds.size.width, 2);scanLayer.backgroundColor = [UIColor redColor].CGColor;[boxView.layer addSublayer:scanLayer];// 开始扫描[session startRunning];

其中第9个步骤是可以优化内存的

@property(nonatomic) CGRect rectOfInterest;

这个属性大致意思就是告诉系统它需要注意的区域,大部分APP的扫码UI中都会有一个框,提醒你将条形码放入那个区域,这个属性的作用就在这里,它可以设置一个范围,只处理在这个范围内捕获到的图像的信息。如此一来,我们代码的效率又会得到很大的提高,在使用这个属性的时候。需要几点注意:

1、这个CGRect参数和普通的Rect范围不太一样,它的四个值的范围都是0-1,表示比例。

2、经过测试发现,这个参数里面的x对应的恰恰是距离左上角的垂直距离,y对应的是距离左上角的水平距离。

3、宽度和高度设置的情况也是类似。

 

/// 经过测试  使用rectOfInterest 更改扫描范围 并没有很好的可控制范围,如果想达到想微信那样,只有在固定的扫描框中才可以扫描成功

    可以使用以下设置,在

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection; 方法中,判断二维码的三个坐标点是否在扫描框中。

 

for (id objects in metadataObjects) {// 判断检测到的对象类型if (![objects isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {return;}// 转换对象坐标
AVMetadataMachineReadableCodeObject *obj = (AVMetadataMachineReadableCodeObject *)[preViewLayer transformedMetadataObjectForMetadataObject:objects];// 判断扫描范围if (!CGRectContainsRect(self.boxView.frame, obj.bounds)) {continue;}}

 

 

 

 

-----------------------------以下是源码:

#import "ScanQrcodeVController.h"

@protocol ScanQrcodeVControllerDelegate <NSObject>
// 二维码返回结果
-(void)scanQrcodeWithNString:(NSString *) ruselt;
@end
@interface ScanQrcodeVController : UIViewController
@property (nonatomic, weak) id<ScanQrcodeVControllerDelegate>delegate;
@end

#import "ScanQrcodeVController.m"

@interface ScanQrcodeVController ()<AVCaptureMetadataOutputObjectsDelegate>
// 会话
@property (nonatomic, strong) AVCaptureSession *session;
// 定时器
@property (nonatomic, strong) CADisplayLink *link;
// 扫描线
@property (nonatomic, strong) CALayer *scanLayer;
// 扫描框
@property (nonatomic, weak) UIView *boxView;
/// 保存二维码结果
@property (nonatomic, copy) NSString *string;
@end@implementation ScanQrcodeVController
- (void)viewDidLoad {[super viewDidLoad];self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"NavBack"] style:UIBarButtonItemStylePlain target:self action:@selector(goBack)];self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"确定" style:UIBarButtonItemStylePlain target:self action:@selector(doneClick)];[self scanCode];  
}-(void)scanCode {CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(updataFrame)];self.link = link;link.frameInterval = 3;[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

  

    // 判断相机是否授权使用相机

 

    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

 

    if(status == AVAuthorizationStatusAuthorized) {

 

    } else if(status == AVAuthorizationStatusDenied){

 

       // NSLog(@"denied不允许");

 

        return ;

 

    } else if(status == AVAuthorizationStatusNotDetermined){

 

        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {

 

            if(granted){

 

//                NSLog(@"允许");

 

            } else {

 

//                NSLog(@"不允许");

 

                return;

 

            }

 

        }];

 

    // 1.获取输入设备

    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];// 2.创建输入对象NSError *error;AVCaptureDeviceInput *inPut = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];if (inPut == nil) {UIAlertView *aler = [[UIAlertView alloc] initWithTitle:@"提示" message:@"设备不可用" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];[self.view addSubview:aler];[aler show];return;}// 3.创建输出对象AVCaptureMetadataOutput *outPut = [[AVCaptureMetadataOutput alloc] init];// 4.设置代理监听输出对象的输出流  说明:使用主线程队列,相应比较同步,使用其他队列,相应不同步,容易让用户产生不好的体验
    [outPut setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];// 5.创建会话AVCaptureSession *session = [[AVCaptureSession alloc] init];self.session = session;// 6.将输入和输出对象添加到会话if ([session canAddInput:inPut]) {[session addInput:inPut];}if ([session canAddOutput:outPut]) {[session addOutput:outPut];}// 7.告诉输出对象, 需要输出什么样的数据  // 提示:一定要先设置会话的输出为output之后,再指定输出的元数据类型!
    [outPut setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];// 8.创建预览图层AVCaptureVideoPreviewLayer *preViewLayer = [AVCaptureVideoPreviewLayer layerWithSession:session];preViewLayer.frame = self.view.bounds;[self.view.layer insertSublayer:preViewLayer atIndex:0];// 9.设置扫面范围outPut.rectOfInterest = CGRectMake(0.2, 0.18, 0.6, 0.5);// 10.设置扫描框UIView *boxView = [[UIView alloc] initWithFrame:CGRectMake(0.2 * SrceenW, 0.18 * SrceenH, 0.6 * SrceenW, 0.5 * SrceenH)];self.boxView = boxView;boxView.layer.borderColor = [UIColor yellowColor].CGColor;boxView.layer.borderWidth = 3;[self.view addSubview:boxView];// 设置扫描线CALayer *scanLayer = [[CALayer alloc] init];self.scanLayer = scanLayer;scanLayer.frame = CGRectMake(0, 0, boxView.bounds.size.width, 2);scanLayer.backgroundColor = [UIColor redColor].CGColor;[boxView.layer addSublayer:scanLayer];// 开始扫描
    [session startRunning];
}-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    for (id objects in metadataObjects) {

        // 判断检测到的对象类型

        if (![objects isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {

            return;

        }

        // 转换对象坐标

        AVMetadataMachineReadableCodeObject *obj = (AVMetadataMachineReadableCodeObject *)[preViewLayer transformedMetadataObjectForMetadataObject:objects];

        // 判断扫描范围

        if (!CGRectContainsRect(self.boxView.frame, obj.bounds)) {

            continue;

     }

 

        // 设置代理

      if ([self.delegate respondsToSelector:@selector(scanQrcodeWithNString:)]) {

            [self.delegate scanQrcodeWithNString:obj.stringValue];

     } 

     // 停止扫描

     [self.session stopRunning];

        // 移除CADisplayLink对象

        [self.link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

        self.link = nil;

    }


}-(void)updataFrame {CGRect frame = self.scanLayer.frame;if (self.scanLayer.frame.origin.y > self.boxView.frame.size.height) {frame.origin.y = -20;self.scanLayer.frame = frame;}else{frame.origin.y += 3;self.scanLayer.frame = frame;}}-(void)viewDidDisappear:(BOOL)animated{[super viewDidDisappear:animated];// 记得释放CADisplayLink对象if (self.link != nil) {[self.link invalidate];self.link = nil;} }// 返回上一个界面 -(void)goBack {[self.navigationController popViewControllerAnimated:YES]; }// 二维码扫描完成 -(void)doneClick {// 设置代理if ([self.delegate respondsToSelector:@selector(scanQrcodeWithNString:)]) {[self.delegate scanQrcodeWithNString:self.string];}[self.navigationController popToRootViewControllerAnimated:YES]; } @end

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/Mr-Ygs/p/4904710.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/397382.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有符号位和无符号位。——int8疑问有感

学习go语言的数据类型&#xff0c;看见int、int8、int16很是疑惑&#xff0c;int8是什么意思&#xff1f;查询资料进行综合解释大概如下&#xff1a; Int8是有符号位8位整形&#xff08;-128到127&#xff09;&#xff0c;随即产生疑惑&#xff0c;为什么负数可表示到-128&…

html帮助文档乱码,使用doxygen生成的帮助文档,中文出现乱码的问题

今天使用doxygen工具生成帮助文档发现中文注释都是乱码。然后根据网上的要求把Exper>>Input>>INPUT_ENCODING&#xff1a;(输入文件的编码) UTF-8 改成 GBK 或者 GB2312Exper>>HTML>>CHM_INDEX_ENCODING&#xff1a;(输出文件的编码) UTF-8 改成 GBK 或…

Java并发编程--理解ThreadLocal

另一篇博文&#xff1a;Hibernet中的ThreadLocal使用 http://www.cnblogs.com/gnivor/p/4440776.html 本文参考&#xff1a;http://blog.csdn.net/lufeng20/article/details/24314381http://www.cnblogs.com/chenying99/articles/3405161.html ThreadLocal类接口很简单&#xf…

delphi Post数据到网页

varhttp: TIdHttp;sendtoserver: TStringStream;str: string; beginhttp : TIdHttp.Create(); // 创建http.HandleRedirects : True; // 允许转头http.ReadTimeout : 3000; …

python之路——迭代器与生成器

要了解for循环是怎么回事儿&#xff0c;咱们还是要从代码的角度出发。 首先&#xff0c;我们对一个列表进行for循环。 for i in [1,2,3,4]: print(i) 上面这段代码肯定是没有问题的&#xff0c;但是我们换一种情况&#xff0c;来循环一个数字1234试试 for i in 1234print(i) 结…

HTML页面显示透视效果,html – CSS – 对背景图像的“敲除”/透视效果

我认为这里的想法是图像必须足够大,以覆盖网页或至少父母div ..然后,您可以将图像应用于容器和’inner’div的背景.覆盖可以通过伪元素而不是单独的div来实现.修订结构 –.bck {position: relative;height: 800px;width: 100%;background:url(http://webneel.com/wallpaper/sit…

DFS分布式文件系统--管理篇

DFS分布式文件系统--管理篇参考文档&#xff1a;浅谈DFS分布式文件系统DFS 命名空间 和 DFS 复制概述续DFS分布式文件系统--基础篇DFS分布式文件系统--部署篇添加命名空间服务器&#xff08;添加第二台命名空间服务器 NameSrv02)成功后如下图&#xff1a;“从显示区域隐藏命名空…

Linux 0-1 修改主机名及IP地址

1.修改主机名 hostname 查看主机名 vi /etc/sysconfig/network 修改hostname主机名 vi /etc/hosts 修改127.0.1 主机名 service network restart #/etc/hosts 在域名解析时优先于DNS服务器2.IP地址 ifconfig 查看目前网络卡信息 cd /etc/sysconfig/network-scripts ls查看…

html渐变颜色代码表,渐变颜色代码表

渐变颜色代码表2020-12-24素材&#xff1a;网络 编辑&#xff1a;唔尔灬#000000#2F0000#600030#460046#28004D#272727#4D0000#820041#5E005E#3A006F#3C3C3C#600000#9F0050#750075#4B0091#4F4F4F#750000#BF0060#930093#5B00AE#5B5B5B#930000#D9006C#AE00AE#6F00D2#6C6C6C#AE0000…

js贪心算法---背包问题

/** param {Object} capacity 背包容量 6* param {Object} weights 物品重量 [2,3,4]* param {Object} values 物品价值 [3,4,5]*///贪心算法&#xff0c;只能算&#xff0c;可以分割的物品&#xff0c;如果不能分割物品&#xff0c;只能得到近似解&#xff0c;不分割物品&…

Spring利用JDBCTemplate实现批量插入和返回id

1、先介绍一下java.sql.Connection接口提供的三个在执行插入语句后可取的自动生成的主键的方法&#xff1a; //第一个是 PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException; 其中autoGenerateKeys 有两个可选值&#xff1a;Stat…

jsp压缩html,使用HtmlCompressor压缩JSP编译的Html代码

HtmlCompressor 能够删除多余的HTML代码。它提供多种方法&#xff1a;删除无用的空行、删除注释以及删除无用的表格等等&#xff0c;简单而有效。在Java代码中可以这样使用&#xff1a;String html getHtml(); //需要处理的Html代码HtmlCompressor compressor new HtmlCompre…

LVS负载均衡(3)——LVS工作模式与工作原理

LVS介绍及工作原理1. LVS 介绍LVS,Linux Virtual Server 的简写&#xff0c;意即 Linux 虚拟服务器&#xff0c;是一个虚拟的服务器集群系统&#xff0c;可以在 UNIX/Linux 平台下实现负载均衡集群功能。文章&#xff1a;LVS项目介绍LVS集群体系结构LVS集群的IP负载均衡技术LVS…

保留凸性的方式:一个凸函数在一个随机变量上的期望仍然是凸函数

设函数 gg 是实数范围内的一个凸函数&#xff0c;DD 是一个随机变量&#xff0c; 那么函数 GEDg(y−D)GEDg(y−D) 仍然是一个凸函数。 证明&#xff1a;记 θθθθ, yy 与 yy 是任意两个数 ≥θG(y)θG(y)θEDg(y−D)θEDg(y−D)ED[θg(y−D)θ(gy−D)]ED[g(θyθy−D)]G(θyθ…

MyBatis入门(二)---一对一,一对多

一、创建数据库表 1.1、创建数据表同时插入数据 /* SQLyog Enterprise v12.09 (64 bit) MySQL - 5.6.27-log : Database - mybatis ********************************************************************* *//*!40101 SET NAMES utf8 */;/*!40101 SET SQL_MODE*/;/*!40014 SE…

零基础学Java的10个方法

2019独角兽企业重金招聘Python工程师标准>>> 版权声明&#xff1a;本文为北京尚学堂原创文章&#xff0c;未经允许不得转载。​ 零基础学Java只要方法得当&#xff0c;依然有机会学习好Java编程。 但作为初学者可以通过制定一些合理清晰的学习计划。 在帮你屡清楚思…

html 转换为cshtml,使用Html而不是csHtml

我想使用纯HTML页面而不是使用MVC .net的cshtml . 但是当我通过右键单击索引添加视图时&#xff0c;我只能看到两个选项 .public class HomeController : Controller{//// GET: /Home/public ActionResult Index(){return View();}}Cshtml(剃刀)Aspx论坛但仍无济于事 . 我仍然没…

scp windows 和 linux 远程复制 (双向)

一下命令在cmd中 从w -> l : scp D:\a.txt root192.168.2.113:/home/a 从l -> w: scp root192.168.2.113:/home/aaa d:/b.txt 按说在Linux中也可以&#xff0c;但是不知道怎么的只有在winodws上行&#xff0c;在linux上就会报 ssh: connect to host 192.168.2.157 port 2…

北京尚学堂|程序员的智慧

2019独角兽企业重金招聘Python工程师标准>>> 版权声明&#xff1a;本文为北京尚学堂原创文章&#xff0c;未经允许不得转载。 编程是一种创造性的工作&#xff0c;是一门艺术。精通任何一门艺术&#xff0c;都需要很多的练习和领悟&#xff0c;所以这里提出的“智慧…

翼城中学2021高考成绩查询入口,2021年临汾中考分数线查询(4)

临汾2021年中考分数线查询 2021临汾中考录取分数线 19年临汾中考各校录取分数线 临汾各高中录取分数线 临汾2021中考录取线查询 中考信息网提供2021临汾中考分数线查询信息。临汾中考录取分数线预计7月初公布&#xff0c;届时考生可登陆临汾招生考试网官网查看分数线情况。2…