序言
之前做二维码扫描有使用过ZBar, ZXing,并没有觉得集成或者使用有多方便。iOS7之后,苹果就提供了扫码相关的接口,今天尝试了下,扫码的识别效率比较高,提供的API用起来也比较方便。本文主要说明:1. 使用原生API实现扫码功能。2. 如何设置扫描范围。3. 透明区域图形绘制。
相关接口:
一个最简单的二维码扫描功能,需要用到如下这些类:
- AVCaptureDevice:物理设备,提供实时输入的媒体数据,如视频和音频
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
- AVCaptureDeviceInput:提供接口从AVCaptureDevice捕获数据
- AVCaptureMetadataOutput:输出类,输出读取的数据
- AVCaptureSession:关联输入输出,信息实时输入输出的枢纽
- AVCaptureVideoPreviewLayer:显示摄像头捕获的数据
扫码功能初始化:
@property (strong,nonatomic) AVCaptureDevice *device;
@property (strong,nonatomic) AVCaptureDeviceInput *input;
@property (strong,nonatomic) AVCaptureMetadataOutput *output;
@property (strong,nonatomic) AVCaptureSession *session;
@property (strong,nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
_input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
_output = [[AVCaptureMetadataOutput alloc]init];
[_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
_session = [[AVCaptureSession alloc]init];
[_session setSessionPreset:AVCaptureSessionPresetHigh];
if ([_session canAddInput:self.input]) {
[_session addInput:self.input];
}
if ([_session canAddOutput:self.output])
{
[_session addOutput:self.output];
}
_output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
_previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
_previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
_previewLayer.frame = self.view.layer.bounds;
[self.view.layer insertSublayer:_previewLayer atIndex:0];
[_session startRunning];
识别到二维码信息后,代理方法会执行,在此解析数据:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
if ([metadataObjects count] >0)
{
[_session stopRunning];
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
NSString *stringValue = metadataObject.stringValue;
NSLog(@"解析到的数据 : %@",stringValue);
NSURL *url = [NSURL URLWithString:stringValue];
if([[UIApplication sharedApplication]canOpenURL:url])
{
[[UIApplication sharedApplication]openURL:url];
}
}
}
如上两段代码即可实现二维码扫描功能。
但是我们会发现我们整个屏幕都是二维码扫描的区域。如果有多个二维码在一块,这时可能会影响你扫码的准确性。这个时候我们就需要设置扫描的识别区域了。
扫描范围设置:
iOS也为我们提供了一个接口,可以设置识别区域。
@property(nonatomic) CGRect rectOfInterest;//默认值为CGRectMake(0, 0, 1, 1)
我们刚开始对此属性进行设置时,可能发现怎么设置都不对。后面发现一个奇怪的现象:原点似乎是在右上角,而且对应的x和y的值好像也是反的。如下图:
ABCD四点的值分别标记在了图中。重点在A点,理解了A点,其余的几个点也就都理解了。与上图扫描区域对应的rect设置为:
_output.rectOfInterest = CGRectMake(0.35, 0.3, 0.6, 0.7);
如果还是不好理解这个坐标,那么请想象一下:假设你的手机是透明的,从二维码所在的方位,看你的手机。从手机的背面看这个图片,是不是和我们所理解的坐标系统(原点在左上)一样了。
最后再附上一段, 绘制透明区域的代码:
- (void)drawRect:(CGRect)rect {
[[UIColor colorWithWhite:0 alpha:0.5] setFill];
//半透明区域
UIRectFill(rect);
//透明的区域
CGRect holeRection = CGRectMake(85,180,200,200);
CGRect holeiInterSection = CGRectIntersection(holeRection, rect);
[[UIColor clearColor] setFill];
UIRectFill(holeiInterSection);
}```