二維碼掃描在App中很常見(jiàn)的功能愧杯,之前都是用三方工具Zing涎才、ZBar鞋既。后來(lái)Apple的AVFoundation也支持二維碼掃描力九、生成,而且效率比三方庫(kù)還要高邑闺。我把它封裝成一個(gè)工具跌前,這樣使用起來(lái)十分方便,同時(shí)還封裝了掃描視圖陡舅,在工程中增加掃描更加快捷抵乓。
主要使用AVCaptureSession鏈接攝像頭進(jìn)行采集信息
Coding~
//初始化鏈接對(duì)象
self.session = [[AVCaptureSession alloc]init];
//高質(zhì)量采集率
[self.session setSessionPreset:AVCaptureSessionPresetHigh];
//獲取攝像設(shè)備
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//創(chuàng)建輸入流
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
//添加輸入流
if ([self.session canAddInput:input]) {
[self.session addInput:input];
}
//創(chuàng)建輸出流
self.output = [[AVCaptureMetadataOutput alloc] init];
//設(shè)置代理在主線程里刷新(Tip:如果封裝的類不是單利或者全局變量,代理AVCaptureMetadataOutputObjectsDelegated不會(huì)被調(diào)用)
[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//添加輸出流
if ([self.session canAddOutput:self.output]) {
[self.session addOutput:self.output];
}
//設(shè)置掃碼支持的編碼格式靶衍,Tip:必須在添加輸出流之后
if ([self.output availableMetadataObjectTypes].count) {
if (scanType == ZHBarScanTypeQRCode) {
self.output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
} else if (scanType == ZHBarScanTypeBarCode) {
self.output.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code,
AVMetadataObjectTypeEAN8Code,
AVMetadataObjectTypeCode128Code];
} else {
self.output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
AVMetadataObjectTypeEAN13Code,
AVMetadataObjectTypeEAN8Code,
AVMetadataObjectTypeCode128Code];
}
}
//設(shè)置有效的掃描區(qū)域灾炭,Tip:rectOfInterest是比值,默認(rèn)為CGRectMake(0, 0, 1, 1)
/* 手動(dòng)計(jì)算
計(jì)算為CGRectMake(y1/h, x1/w, h1/h, w1/w);
y1,x1,h1,w1為掃描區(qū)域的frame颅眶,h,w是layer視圖的寬高
手動(dòng)計(jì)算要在session運(yùn)行前設(shè)置
*/
/* 自動(dòng)轉(zhuǎn)換
- (CGRect)metadataOutputRectOfInterestForRect:(CGRect)rectInLayerCoordinatesl;
這個(gè)方法可以把掃描區(qū)域的frame轉(zhuǎn)成rectOfInterest的坐標(biāo)系
這個(gè)方法必須在session運(yùn)行后設(shè)置
*/
//如果傳入的scanArea的寬不大于1蜈出,說(shuō)明是手動(dòng)計(jì)算
if (scanRect.size.width <= 1) {
self.output.rectOfInterest = scanRect;
}
//創(chuàng)建相機(jī)渲染層
self.layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
self.layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.layer.frame = layerView.layer.bounds;
[layerView.layer insertSublayer:self.layer atIndex:0];
[ZHBarTool requestCameraAuthorizedResult:^(BOOL granted) {
if (granted) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.session startRunning];
self.isAvailable = YES;
self.scanInterval = self.scanInterval ? self.scanInterval : 2;
//如果傳入的scanArea的寬大于1,調(diào)用系統(tǒng)方法轉(zhuǎn)換
if (scanRect.size.width > 1) {
self.scanRect = scanRect;
CGRect rectOfInterest = [self.layer metadataOutputRectOfInterestForRect:scanRect];
self.output.rectOfInterest = rectOfInterest;
}
});
} else {
if ([self.delegate respondsToSelector:@selector(ZHBarAuthorizedCameraFailed)]) {
[self.delegate ZHBarAuthorizedCameraFailed];
}
if (self.authorizedCameraFailed) {
self.authorizedCameraFailed();
}
}
}];
注意點(diǎn):
有效的掃描區(qū)域:rectOfInterest涛酗。這是個(gè)比值铡原,而且坐標(biāo)系和我們平常開(kāi)發(fā)使用的不一樣偷厦,計(jì)算時(shí)需要轉(zhuǎn)化,不過(guò)系統(tǒng)給我們提供了方法
- (CGRect)metadataOutputRectOfInterestForRect:(CGRect)rectInLayerCoordinatesl;
可以轉(zhuǎn)化我們熟悉的坐標(biāo)系下的frame為rectOfInterest需要的坐標(biāo)燕刻,但使用這個(gè)方法必須在session啟動(dòng)之后設(shè)置只泼。
代理:
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
AVMetadataMachineReadableCodeObject *object = [metadataObjects objectAtIndex:0];
NSString *obj = [object stringValue];
}
二維碼條形碼生成
主要使用過(guò)濾器CIFilter
//二維碼過(guò)濾器
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
/條形碼過(guò)濾器
CIFilter *filter = [CIFilter filterWithName:@"CICode128BarcodeGenerator"];
解析二維碼圖片
NSString *url = nil;
//初始化一個(gè)監(jiān)測(cè)器
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
//監(jiān)測(cè)到的結(jié)果數(shù)組
NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:aImage.CGImage]];
if (features.count >=1) {
//結(jié)果對(duì)象
CIQRCodeFeature *feature = [features objectAtIndex:0];
NSString *result = feature.messageString;
url = result;
}
解析條形碼圖片
很遺憾╮(╯_╰)原生還不支持解析條形碼圖片,如果有需要的話只能使用三方庫(kù)了卵洗。