二維碼掃描在App中很常見的功能,之前都是用三方工具Zing、ZBar。后來Apple的AVFoundation也支持二維碼掃描、生成,而且效率比三方庫還要高。我把它封裝成一個工具,這樣使用起來十分方便,同時還封裝了掃描視圖,在工程中增加掃描更加快捷。
主要使用AVCaptureSession鏈接攝像頭進行采集信息
Coding~
//初始化鏈接對象
self.session = [[AVCaptureSession alloc]init];
//高質量采集率
[self.session setSessionPreset:AVCaptureSessionPresetHigh];
//獲取攝像設備
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//創建輸入流
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
//添加輸入流
if ([self.session canAddInput:input]) {
[self.session addInput:input];
}
//創建輸出流
self.output = [[AVCaptureMetadataOutput alloc] init];
//設置代理在主線程里刷新(Tip:如果封裝的類不是單利或者全局變量,代理AVCaptureMetadataOutputObjectsDelegated不會被調用)
[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//添加輸出流
if ([self.session canAddOutput:self.output]) {
[self.session addOutput:self.output];
}
//設置掃碼支持的編碼格式,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];
}
}
//設置有效的掃描區域,Tip:rectOfInterest是比值,默認為CGRectMake(0, 0, 1, 1)
/* 手動計算
計算為CGRectMake(y1/h, x1/w, h1/h, w1/w);
y1,x1,h1,w1為掃描區域的frame,h,w是layer視圖的寬高
手動計算要在session運行前設置
*/
/* 自動轉換
- (CGRect)metadataOutputRectOfInterestForRect:(CGRect)rectInLayerCoordinatesl;
這個方法可以把掃描區域的frame轉成rectOfInterest的坐標系
這個方法必須在session運行后設置
*/
//如果傳入的scanArea的寬不大于1,說明是手動計算
if (scanRect.size.width <= 1) {
self.output.rectOfInterest = scanRect;
}
//創建相機渲染層
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,調用系統方法轉換
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();
}
}
}];
注意點:
有效的掃描區域:rectOfInterest。這是個比值,而且坐標系和我們平常開發使用的不一樣,計算時需要轉化,不過系統給我們提供了方法
- (CGRect)metadataOutputRectOfInterestForRect:(CGRect)rectInLayerCoordinatesl;
可以轉化我們熟悉的坐標系下的frame為rectOfInterest需要的坐標,但使用這個方法必須在session啟動之后設置。
代理:
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
AVMetadataMachineReadableCodeObject *object = [metadataObjects objectAtIndex:0];
NSString *obj = [object stringValue];
}
二維碼條形碼生成
主要使用過濾器CIFilter
//二維碼過濾器
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
/條形碼過濾器
CIFilter *filter = [CIFilter filterWithName:@"CICode128BarcodeGenerator"];
解析二維碼圖片
NSString *url = nil;
//初始化一個監測器
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
//監測到的結果數組
NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:aImage.CGImage]];
if (features.count >=1) {
//結果對象
CIQRCodeFeature *feature = [features objectAtIndex:0];
NSString *result = feature.messageString;
url = result;
}
解析條形碼圖片
很遺憾╮(╯_╰)原生還不支持解析條形碼圖片,如果有需要的話只能使用三方庫了。