【转】 iOS使用AVFoundation实现二维码扫描

原文:http://strivingboy.github.io/blog/2014/11/08/scan-qrcode/

关于二维码扫描有不少优秀第三方库如:

最近项目需要,看了下使用ios7自带的 AVFoundation Framework 来实现二维码扫描,Demo 见:scan_qrcode_demo

关于AVFoundation

AVFoundation 是一个很大基础库,用来创建基于时间的视听媒体,可以使用它来检查,创建、编辑或媒体文件。也可以输入流从设备和操作视频实时捕捉和回放。详细框架介绍见官网:About AV Foundation,本文只是介绍如果使用AVFoundation获取二维码。

首先获取流媒体信息我们需要AVCaptureSession对象来管理输入流和输出流,AVCaptureVideoPreviewLayer对象来显示信息,基本流程如下图所示:

注:

  • AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
  • AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
  • AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
  • AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
  • AVCaptureVideoPreviewLayerCALayer的一个子类,显示捕获到的相机输出流。

下面看下实现过程如下:

Step1:需要导入:AVFoundation Framework 包含头文件:

#import <AVFoundation/AVFoundation.h>

Step2:设置捕获会话

设置 AVCaptureSession 和 AVCaptureVideoPreviewLayer 成员

1
2
3
4
5
6
7
8
9
10
    #import <AVFoundation/AVFoundation.h>

    static const char *kScanQRCodeQueueName = "ScanQRCodeQueue";

    @interface ViewController () <AVCaptureMetadataOutputObjectsDelegate>
    .....
    @property (nonatomic) AVCaptureSession *captureSession;
    @property (nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer;
    @property (nonatomic) BOOL lastResult;
    @end

Step3:创建会话,读取输入流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    - (BOOL)startReading
    {
        // 获取 AVCaptureDevice 实例
        NSError * error;
        AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        // 初始化输入流
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
        if (!input) {
            NSLog(@"%@", [error localizedDescription]);
            return NO;
        }
        // 创建会话
        _captureSession = [[AVCaptureSession alloc] init];
        // 添加输入流
        [_captureSession addInput:input];
        // 初始化输出流
        AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
        // 添加输出流
        [_captureSession addOutput:captureMetadataOutput];

        // 创建dispatch queue.
        dispatch_queue_t dispatchQueue;
        dispatchQueue = dispatch_queue_create(kScanQRCodeQueueName, NULL);
        [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
        // 设置元数据类型 AVMetadataObjectTypeQRCode
        [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];

        // 创建输出对象
        _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
        [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        [_videoPreviewLayer setFrame:_sanFrameView.layer.bounds];
        [_sanFrameView.layer addSublayer:_videoPreviewLayer];
        // 开始会话
        [_captureSession startRunning];

        return YES;
    }

Step4:停止读取

1
2
3
4
5
6
7
    - (void)stopReading
    {
        // 停止会话
        [_captureSession stopRunning];
        _captureSession = nil;
    }

Step5:获取捕获数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
  fromConnection:(AVCaptureConnection *)connection
{
    if (metadataObjects != nil && [metadataObjects count] > 0) {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        NSString *result;
        if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            result = metadataObj.stringValue;
        } else {
            NSLog(@"不是二维码");
        }
        [self performSelectorOnMainThread:@selector(reportScanResult:) withObject:result waitUntilDone:NO];
    }
}

Step6:处理结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  - (void)reportScanResult:(NSString *)result
  {
      [self stopReading];
      if (!_lastResult) {
          return;
      }
      _lastResut = NO;
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"二维码扫描"
                                                      message:result
                                                     delegate:nil
                                            cancelButtonTitle:@"取消"
                                            otherButtonTitles: nil];
      [alert show];
      // 以下处理了结果,继续下次扫描
      _lastResult = YES;
  }

以上基本就是二维码的获取流程,和扫一扫二维码伴随的就是开启系统照明,这个比较简单,也是利用 AVCaptureDevice,请看如下实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
  - (void)systemLightSwitch:(BOOL)open
  {
      AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
      if ([device hasTorch]) {
          [device lockForConfiguration:nil];
          if (open) {
              [device setTorchMode:AVCaptureTorchModeOn];
          } else {
              [device setTorchMode:AVCaptureTorchModeOff];
          }
          [device unlockForConfiguration];
      }
  }

以上就是本文介绍的大部分内容,详细代码请看demo scan_qrcode_deomo

实现过程中遇到一下两个问题:

1、扫描一个二维码,输出流回重复调用,代理方法头文件介绍:

1
2
3
4
5
6
7
8
9
10
11
12
13
   /*!
  @method captureOutput:didOutputMetadataObjects:fromConnection:
  .....
  @discussion
     Delegates receive this message whenever the output captures and emits new objects, as specified by
     its metadataObjectTypes property. Delegates can use the provided objects in conjunction with other APIs
     for further processing. This method will be called on the dispatch queue specified by the output‘s
     metadataObjectsCallbackQueue property. **This method may be called frequently** so it must be efficient to
     prevent capture performance problems, including dropped metadata objects.

     Clients that need to reference metadata objects outside of the scope of this method must retain them and
     then release them when they are finished with them.
 */

代理方法会频繁调用,我暂且用一个标记(@property (nonatomic) BOOL lastResult)表示是否是第一次扫描成功,来处理。

2、AVFoundation 该库不能扫描相册中的二维码图片,不知为啥苹果没有支持,有知道实现的麻烦告诉我哈。

参考链接

时间: 2024-10-11 06:28:04

【转】 iOS使用AVFoundation实现二维码扫描的相关文章

iOS使用AVFoundation实现二维码扫描

实现过程如下: Step1:需要导入:AVFoundation Framework 包含头文件: #import <AVFoundation/AVFoundation.h> Step2:设置捕获会话 设置 AVCaptureSession 和 AVCaptureVideoPreviewLayer 成员 1 2 3 4 5 6 7 8 9 10 #import <AVFoundation/AVFoundation.h> static const char *kScanQRCodeQu

iOS使用AVFoundation实现二维码扫描(ios7以上)——转载

关于二维码扫描有不少优秀第三方库: ZBar SDK 里面有详细的文档,相应介绍也非常多,如:http://rdcworld-iphone.blogspot.in/2013/03/how-to-use-barcode-scanner-br-and-qr-in.html ZXing google推出的开源项目,相应介绍如:http://blog.devtang.com/blog/2012/12/23/use-zxing-library/ 关于AVFoundation AVFoundation 是一

iOS 开发之 ZBarSDK 二维码扫描自定义二维码扫描页面(二)

iOS 开发之 ZBarSDK 二维码扫描自定义二维码扫描页面(二) 上一篇解决了ZBarSDK不支持64bit的问题,下面我们就可以使用ZBarSDK了. 导入ZBarSDk.h文件 附上代码: // //  MeViewController.m //  Auditory Blog // //  Created by 寒竹子 on 15/4/28. //  Copyright (c) 2015年 寒竹子. All rights reserved. // #define ScanWidth  2

Swift:使用系统AVFoundation实现二维码扫描和生成

系统提供的AVCaptureSession仅仅适用于iOS7.0以上的系统.之前的请用Zbar来替代 下载地址:http://download.csdn.net/detail/huobanbengkui/8881097 配置project: 引入: import Foundation import AVFoundation 接受AVCaptureMetadataOutputObjectsDelegate(如: class QrcodeVC: UIViewController,AVCaptureM

使用AVFoundation完成二维码扫描

其中有几点需要注意的 1.应该使用异步线程来配置那几个属性,这样可以防止阻塞主线程加载UI. 2.output的rectOfInterst是感应区域,就是说,在这个区域内才有扫描效果.但是由于摄像头的关系,这个rect的x和y是反着的,width和height也是反着的,就是说,这里的x坐标对应着正常情况下的y坐标,这里的宽度对应着正常情况下的高度. 3.sessionPreset属性是用来设置扫描精度的. 4.metaObjectTypes属性可以设置扫描的类型,有二维码和一维码(条形码).

iOS 开发之 ZBarSDK 二维码扫描 静态库不支持64bit完美解决(一)

由于ZBarSDK不支持arm64 bit,下面是自己进行编译打包生成支持64bit的.a文件的方法. 首先下载ZBarSDK,解压后打开iPhone的文件夹,删除Example文件夹.然后打开zbar.xcodeproject,设置工程编译环境为Release环境. 修改Standard Achived 为armv7 arm64,然后build.注意:先选择真机build,此时不需要插入真机.然后,在选择模拟器build. 得到两个.a文件. 最后一步: 将真机下得到的.a文件和模拟器下得到的

iOS开发-二维码扫描和应用跳转

iOS开发-二维码扫描和应用跳转 序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar.使用时集成麻烦,出错也不方便调试.在iOS7之后,苹果自身提供了二维码的扫描功能,从效率上来说,原生的二维码远高于这些第三方框架.本文讲解如何使用原生框架实现二维码扫描功能,并且进行扫描后的项目跳转.ps:本期的源代码会在文章结尾给出链接 扫描相关类 二维码扫描需要获取摄像头并读取

Ios二维码扫描(系统自带的二维码扫描)

Ios二维码扫描 这里给大家介绍的时如何使用系统自带的二维码扫描方法和一些简单的动画! 操作步骤: 1).首先你需要搭建UI界面如图:下图我用了俩个imageview和一个label 2).你需要在你当前的控制器中导入 #import <AVFoundation/AVFoundation.h> <AVCaptureMetadataOutputObjectsDelegate>代理 3).在@interface中定义 @property (nonatomic,strong)AVCapt

IOS二维码扫描IOS7系统实现

扫描相关类 二维码扫描需要获取摄像头并读取照片信息,因此我们需要导入系统的AVFoundation框架,创建视频会话.我们需要用到一下几个类: AVCaptureSession 会话对象.此类作为硬件设备输入输出信息的桥梁,承担实时获取设备数据的责任 AVCaptureDeviceInput 设备输入类.这个类用来表示输入数据的硬件设备,配置抽象设备的port AVCaptureMetadataOutput 输出类.这个支持二维码.条形码等图像数据的识别 AVCaptureVideoPrevie