使用AVFoundation 生成的二维码扫描器,扫描速度快,加上扫描限定区域缩小扫描范围,另外代码直接在扫描区域外生成黑色透明蒙版,简单扫描动画。相册相片识别二维码信息(只支持ios8及以上版本)。功能写的比较简单,细节需要的自己去优化吧~详情见附件! 
 另外:二维码生成可以参考站内其他源码:http://blog.yourtion.com/custom-cifilter-qrcode-generator.html

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>@interface QRCodeScanController : UIViewController<AVCaptureMetadataOutputObjectsDelegate>@end
//NOTE: 二维码扫描实现。  生成二维码以及扫描二维码实现方式是基于AVFoundation库,由于Apple 在 IOS8.0后才
//      提供了从相册识别二维码的新特性(代码中已被注释掉),为了兼容IOS8.0以前机型,故识别相片二维码信息采用的是开源库ZXINGObjc.
//      ZBar  Zxing均已停止更新且不支持64位架构。#import "QRCodeScanController.h"
#import "NSObject+GCD.h"@interface QRCodeScanController ()@property (weak, nonatomic) IBOutlet UIImageView *scanBackgrondImageView;@property (weak, nonatomic) IBOutlet UIView *scanContainerView;@property (weak, nonatomic) IBOutlet UIView *scanView;@property (weak, nonatomic) IBOutlet UILabel *statusLabel;@property(strong,nonatomic) AVCaptureSession *session; // 二维码生成的绘画@property(strong,nonatomic)  AVCaptureVideoPreviewLayer *previewLayer;@property(assign,nonatomic) BOOL finished;@property (nonatomic,strong)UIImageView * readLineView;//扫描器灰色蒙板。
@property (nonatomic,strong)CALayer * maskLayer;@property(nonatomic,strong)CIDetector * detector;@property(nonatomic,assign)CMVideoDimensions dimensions;@property (nonatomic,strong) NSString * albumId;
@property (weak, nonatomic) IBOutlet UILabel *remindLabel;@end@implementation QRCodeScanController- (void)dealloc{// 删除预览图层if (self.previewLayer) {[self.previewLayer removeFromSuperlayer];}if (self.maskLayer) {self.maskLayer.delegate = nil;}NSLog(@"%@ will dealloc !",NSStringFromClass([self class]));
}- (void)viewDidLoad {[super viewDidLoad];self.navigationController.navigationBar.translucent = NO;
}- (void)viewWillDisappear:(BOOL)animated
{[super viewWillDisappear:animated];[self stopScanning:self.session];
}-(void)viewWillAppear:(BOOL)animated{[super viewWillAppear:animated];if (!self.session) {[self readQRcode];}
}- (void)onCancelBarButtonTouched:(id)sender{[self dismissViewControllerAnimated:YES completion:nil];
}//ios8.0及以上版本可使用。
- (CIDetector *)detector{if (_detector == nil) {NSDictionary * options = @{CIDetectorAccuracy : CIDetectorAccuracyHigh};_detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:options];}return _detector;
}- (void)doneButtonTouched:(id)sender{if (self.finished) {// 1. 如果扫描完成,停止会话[self stopScanning:self.session];// 2. 删除预览图层[self.previewLayer removeFromSuperlayer];}[self dismissViewControllerAnimated:YES completion:^{}];
}- (void)setStatusText:(NSString *)text{CGRect stringRect = [text boundingRectWithSize:CGSizeMake(self.statusLabel.frame.size.width, 80.0)options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)attributes:@{ NSFontAttributeName : self.statusLabel.font }context:nil];CGRect rect = self.statusLabel.frame;rect.size.height = MAX(stringRect.size.height, rect.size.height);self.statusLabel.frame = rect;self.statusLabel.text = text;
}//停止扫描
- (void)stopScanning:(AVCaptureSession *)session{[session stopRunning];safe_dispatch_main_async(^{[self.scanBackgrondImageView.layer removeAllAnimations];});
}//开始扫描
- (void)startScanning:(AVCaptureSession *)session{[session startRunning];safe_dispatch_main_async(^{if (_readLineView) {[self.scanBackgrondImageView.layer removeAllAnimations];}else{[self loopDrawLine];}});
}#pragma mark 扫描动画
-(void)loopDrawLine{CGRect screenBounds = [[UIScreen mainScreen] bounds];CGFloat scaleX = screenBounds.size.width/320.0;CGFloat loopLineWidth = 244.0 * scaleX;CGRect rect = CGRectMake(0, 5, loopLineWidth, 2);if (_readLineView) {[_readLineView removeFromSuperview];}__weak QRCodeScanController *weakSelf = self;weakSelf.readLineView = [[UIImageView alloc] initWithFrame:rect];[_readLineView setImage:[UIImage imageNamed:@"scan_line.png"]];[UIView animateWithDuration:1.5delay: 0.0options: UIViewAnimationOptionCurveEaseInanimations:^{//修改fream的代码写在这里weakSelf.readLineView.frame =CGRectMake(weakSelf.scanBackgrondImageView.frame.origin.x, weakSelf.scanBackgrondImageView.frame.origin.y+weakSelf.scanBackgrondImageView.frame.size.height - 5, loopLineWidth, 2);[weakSelf.readLineView setAnimationRepeatCount:0];}completion:^(BOOL finished){[weakSelf loopDrawLine];}];[weakSelf.scanBackgrondImageView addSubview:weakSelf.readLineView];
}#pragma mark - 读取二维码- (void)readQRcode{// 1. 摄像头设备AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];// 2. 设置输入// 因为模拟器是没有摄像头的,因此在此最好做一个判断NSError *error = nil;AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];if (error) {NSLog(@"没有摄像头-%@", error.localizedDescription);return;}// 3. 设置输出(Metadata元数据)AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];// 3.1 设置输出的代理// 说明:使用主线程队列,相应比较同步,使用其他队列,相应不同步,容易让用户产生不好的体验[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];// 4. 拍摄会话//在生成拍摄回话时原来直接设置的是最高清画质,但对于ipod 5这类低配设备是不支持的,故在此我采取了下面这种方式来设置画质。AVCaptureSession *session = [[AVCaptureSession alloc] init];if ([device supportsAVCaptureSessionPreset:AVCaptureSessionPreset1920x1080]) {session.sessionPreset = AVCaptureSessionPreset1920x1080;//设置图像输出质量self.dimensions = (CMVideoDimensions){1080,1920};}else if ([device supportsAVCaptureSessionPreset:AVCaptureSessionPreset1280x720]){session.sessionPreset = AVCaptureSessionPreset1280x720;self.dimensions = (CMVideoDimensions){720,1280};}else if ([device supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]){session.sessionPreset = AVCaptureSessionPreset640x480;self.dimensions = (CMVideoDimensions){480,640};}else if ([device supportsAVCaptureSessionPreset:AVCaptureSessionPreset352x288]){session.sessionPreset = AVCaptureSessionPreset352x288;self.dimensions = (CMVideoDimensions){288,352};}// 添加session的输入和输出[session addInput:input];[session addOutput:output];// 4.1 设置输出的格式// 提示:一定要先设置会话的输出为output之后,再指定输出的元数据类型![output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];CGRect scanBounds = [self.view bounds];// 5. 设置预览图层(用来让用户能够看到扫描情况)AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:session];// 5.1 设置preview图层的属性[preview setVideoGravity:AVLayerVideoGravityResizeAspectFill];// 5.2 设置preview图层的大小[preview setFrame:scanBounds];preview.backgroundColor = [UIColor lightGrayColor].CGColor;// 5.3 将图层添加到视图的图层[self.view.layer insertSublayer:preview atIndex:0];self.previewLayer = preview;self.maskLayer = [[CALayer alloc]init];self.maskLayer.frame = self.view.layer.bounds;self.maskLayer.delegate = self;[self.view.layer insertSublayer:self.maskLayer above:self.previewLayer];[self.maskLayer setNeedsDisplay];//5.4设置扫描区域/*获取图像输出大小*/CMVideoDimensions dimensions = self.dimensions;CGFloat width = dimensions.width;CGFloat height = dimensions.height;CGSize size = scanBounds.size;CGRect screenBounds = [[UIScreen mainScreen] bounds];CGFloat scaleX = screenBounds.size.width/320.0;CGFloat scaleY = screenBounds.size.height/568.0;CGRect scanFrame = [self.view convertRect:self.scanView.frame fromView:self.scanView.superview];CGRect cropRect = CGRectMake(scanFrame.origin.x * scaleX, scanFrame.origin.y * scaleY, scanFrame.size.width*scaleX, scanFrame.size.height * scaleY);CGFloat p1 = size.height/size.width;CGFloat p2 = height/width; //与之前设置的图像输出质量应该对应。if (p1 < p2) {CGFloat fixHeight = self.view.bounds.size.width * height / width; //缩放并剪裁后的高度。CGFloat fixPadding = (fixHeight - size.height)/2;output.rectOfInterest = CGRectMake((cropRect.origin.y + fixPadding)/fixHeight,cropRect.origin.x/size.width,cropRect.size.height/fixHeight,cropRect.size.width/size.width);} else {CGFloat fixWidth = self.view.bounds.size.height * width / height;CGFloat fixPadding = (fixWidth - size.width)/2;output.rectOfInterest = CGRectMake(cropRect.origin.y/size.height,(cropRect.origin.x + fixPadding)/fixWidth,cropRect.size.height/size.height,cropRect.size.width/fixWidth);}//说明: rectOfInterest 参数和普通的Rect范围不太一样,它的四个值的范围都是0-1,表示比例//      参数里的x对应的恰恰是距离左上角的垂直距离,y对应的是距离左上角的水平距离,宽度和高度设置的情况也是类似//      举个例子如果我们想让扫描的处理区域是屏幕的下半部分,我们这样设置  output.rectOfInterest=CGRectMake(0.5,0,0.5, 1)// 6. 启动会话[self startScanning:session];self.session = session;}#pragma mark - 输出代理方法// 此方法是在识别到QRCode,并且完成转换// 如果QRCode的内容越大,转换需要的时间就越长- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{// 扫描结果if (metadataObjects.count > 0) {AVMetadataMachineReadableCodeObject *obj = metadataObjects[0];NSString *result = obj.stringValue;self.remindLabel.text = [NSString stringWithFormat:@"扫描结果:%@",result];//result 即为扫描得到的结果。//可以开始对扫描得到的结果进行相应处理了。}
}//Note: 蒙板生成。需设置代理,并在退出页面时取消代理。
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{if (layer == self.maskLayer) {UIGraphicsBeginImageContextWithOptions(self.maskLayer.frame.size, NO, 1.0);CGContextSetFillColorWithColor(ctx, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.6].CGColor);CGContextFillRect(ctx, self.maskLayer.frame);CGRect scanFrame = [self.view convertRect:self.scanView.frame fromView:self.scanView.superview];CGContextClearRect(ctx, scanFrame);}
}@end

iOS 使用AVFoundation 扫描二维码并限定扫描区域(带代码生成蒙版)相关推荐

  1. 微信扫描二维码和浏览器扫描二维码 ios和Android 分别进入不用的提示页面

    实现微信扫描二维码和浏览器扫描二维码 ios和Android 分别进入不用的提示页面 而进入商城下载该项目 详情地址:gitee.com/DuJiaHui123- 1.创建完之后 替换文件里面的ios ...

  2. ios使用AVFoundation读取二维码的方法

    二维码(Quick Response Code,简称QR Code)是由水平和垂直两个方向上的线条设计而成的一种二维条形码(barcode).可以编码网址.电话号码.文本等内容,能够存储大量的数据信息 ...

  3. Google Zxing 只扫描二维码或者只扫描条形码

    Google Zxing怎样实现扫描二维码.条形码,具体参考我 这里主要说一下,怎样选择不同的模式. Zxing 默认支持扫描二维码.条形码两种功能,但是因为项目要求,禁止扫描二维码.那么怎样禁止扫描 ...

  4. 让你的APP轻松加上扫描二维码功能

    在这个二维码横行的年代,如果一个APP连扫描二维码的功能都没有是会被耻笑的.今天小老虎教小白们如何为自己的APP添加扫描二维码功能和生成二维码,并做到外部扫描跳转网页,内部扫描跳转具体Activity ...

  5. 只需3个步骤,轻松解决程序员在Java中生成、扫描二维码难题

    条形码包含有关产品或公司的信息,以机器可读的形式直观地表示.条码广泛用于跟踪货物和库存管理.我们可以在 WPF 应用程序中轻松生成各种类型的条码.二维码广泛用于分享重要信息.对于不同的要求,您可能希望 ...

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

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

  7. iOS 扫描二维码/条形码

    级别:★★☆☆☆ 标签:「iOS 原生扫描」「AVCaptureSession」「AVCaptureDevice」「rectOfInterest」 作者: Xs·H 审校: QiShare团队 最近做 ...

  8. IOS实现扫描二维码,利用系统API实现,看了这篇IOS扫描功能再也不用求人了。

    如今在国内无论走到哪里,只要是涉及支付的方面都可以使用支付宝或微信扫个二维码进行付款.现在二维码随处可见,二维码支付,二维码点餐,二维码坐公交,二维码做地铁,广告宣传页上, 电视台节目上等等.另外连乞 ...

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

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

最新文章

  1. 创建ContentProvider的详细步骤
  2. 找工作刷题--------Java相关
  3. 20145317 《网络对抗技术》免杀原理与实践
  4. C# 导出word文档及批量导出word文档(3)
  5. 手动发布证书吊销列表
  6. Ubuntu 16.04 安装phpmyadmin以及注意事项
  7. vue-cli3的安装使用
  8. 操作 神通数据库_神通数据库OGDCProvider使用手册.PDF
  9. Python 调用谷歌翻译(2021年9月测试可用)
  10. 9个实用的,可以写进简历的数据分析项目!
  11. SkeyeVSS综合安防Onvif、RTSP、GB28181视频云服务H5无插件直播点播卡顿的解决方案
  12. C#/.NET 系统优化专题(搜索引擎Lucene的使用)
  13. java jtextarea边框_JTextArea在java swing中的边框
  14. 南京 雅趣 php,书房雅趣-南京大学校报电子版《南京大学报》
  15. 全球及中国汽车轻触开关行业发展展望及投资潜力预测报告2022-2028年
  16. 基于JSP实现的课程资源管理系统网站
  17. AlphaGo Model-Based RL
  18. 1024程序员节,给猿媛们的超值当当网购书薅羊毛
  19. OpenCV 设置摄像机焦距
  20. KeeFarce工具抓取Keepass密码攻击复现及其行为监测

热门文章

  1. ThinkCMF设置后台编辑器上传图片到所在服务器
  2. 如何通过CAD图中的坐标来确定是哪个坐标系
  3. UG\NX二次开发 绝对坐标,工作坐标,部件之间坐标转换 UF_CSYS_map_point
  4. 什么样的人适合做外贸行业
  5. 芯片的ATE测试简介
  6. 弘辽科技:引爆店铺流量的淘宝关键词技巧
  7. 金蝶K3开发-插件实现跨帐套传递单据
  8. IT外企面试回答技巧
  9. 简易实现上拉刷新UpRefresh
  10. 2022年最新最详细的安装Node.js以及cnpm(详细图解过程、绝对成功)