序言
之前做二維碼掃描有使用過ZBar, ZXing,并沒有覺得集成或者使用有多方便。iOS7之后,蘋果就提供了掃碼相關的接口,今天嘗試了下,掃碼的識別效率比較高,提供的API用起來也比較方便。本文主要說明:1. 使用原生API實現(xiàn)掃碼功能。2. 如何設置掃描范圍。3. 透明區(qū)域圖形繪制。
相關接口:
一個最簡單的二維碼掃描功能,需要用到如下這些類:
- AVCaptureDevice:物理設備,提供實時輸入的媒體數(shù)據(jù),如視頻和音頻
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
- AVCaptureDeviceInput:提供接口從AVCaptureDevice捕獲數(shù)據(jù)
- AVCaptureMetadataOutput:輸出類,輸出讀取的數(shù)據(jù)
- AVCaptureSession:關聯(lián)輸入輸出,信息實時輸入輸出的樞紐
- AVCaptureVideoPreviewLayer:顯示攝像頭捕獲的數(shù)據(jù)
掃碼功能初始化:
@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];
識別到二維碼信息后,代理方法會執(zhí)行,在此解析數(shù)據(jù):
- (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(@"解析到的數(shù)據(jù) : %@",stringValue);
NSURL *url = [NSURL URLWithString:stringValue];
if([[UIApplication sharedApplication]canOpenURL:url])
{
[[UIApplication sharedApplication]openURL:url];
}
}
}
如上兩段代碼即可實現(xiàn)二維碼掃描功能。
但是我們會發(fā)現(xiàn)我們整個屏幕都是二維碼掃描的區(qū)域。如果有多個二維碼在一塊,這時可能會影響你掃碼的準確性。這個時候我們就需要設置掃描的識別區(qū)域了。
掃描范圍設置:
iOS也為我們提供了一個接口,可以設置識別區(qū)域。
@property(nonatomic) CGRect rectOfInterest;//默認值為CGRectMake(0, 0, 1, 1)
我們剛開始對此屬性進行設置時,可能發(fā)現(xiàn)怎么設置都不對。后面發(fā)現(xiàn)一個奇怪的現(xiàn)象:原點似乎是在右上角,而且對應的x和y的值好像也是反的。如下圖:

圖1
ABCD四點的值分別標記在了圖中。重點在A點,理解了A點,其余的幾個點也就都理解了。與上圖掃描區(qū)域?qū)膔ect設置為:
_output.rectOfInterest = CGRectMake(0.35, 0.3, 0.6, 0.7);
如果還是不好理解這個坐標,那么請想象一下:假設你的手機是透明的,從二維碼所在的方位,看你的手機。從手機的背面看這個圖片,是不是和我們所理解的坐標系統(tǒng)(原點在左上)一樣了。
最后再附上一段, 繪制透明區(qū)域的代碼:
- (void)drawRect:(CGRect)rect {
[[UIColor colorWithWhite:0 alpha:0.5] setFill];
//半透明區(qū)域
UIRectFill(rect);
//透明的區(qū)域
CGRect holeRection = CGRectMake(85,180,200,200);
CGRect holeiInterSection = CGRectIntersection(holeRection, rect);
[[UIColor clearColor] setFill];
UIRectFill(holeiInterSection);
}```