ios7之前我們實現二維碼掃描是借助第三方(ZBar,ZXing等)來實現的,在ios7之後系統自己提供二維碼掃描的方法,性能也要比第三方更好。
今天就來介紹一下原生二維碼的使用,包括掃描二維碼,從圖片掃描二維碼和生成二維碼。講解中只展示部分代碼,具體請看Github Demo,裡面的代碼不多,也很容易看懂。
掃描二維碼
二維碼掃描需要用到AVFoundation.framework,需要用先創建一個AVCaptureSession,然後設置輸入輸出流,以及掃描區域和支持的格式:
//獲取攝像設備 AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; //創建輸入流 AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; if (!input) { return nil; } //創建輸出流 AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init]; //設置代理 在主線程裡刷新 [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; //設置掃描區域的比例 CGFloat width = 300 / CGRectGetHeight(self.view.frame); CGFloat height = 300 / CGRectGetWidth(self.view.frame); output.rectOfInterest = CGRectMake((1 - width) / 2, (1- height) / 2, width, height); AVCaptureSession *session = [[AVCaptureSession alloc] init]; //高質量采集率 [session setSessionPreset:AVCaptureSessionPresetHigh]; [session addInput:input]; [session addOutput:output]; //設置掃碼支持的編碼格式(這裡設置條形碼和二維碼兼容) output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
然後用這個session生成一個AVCaptureVideoPreviewLayer加到某個view的layer上,就可以實時顯示攝像頭捕捉的內容了:
AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; layer.videoGravity = AVLayerVideoGravityResizeAspectFill; layer.frame = self.view.layer.bounds; [self.view.layer insertSublayer:layer atIndex:0];
然後調用[self.session startRunning];開始捕獲,當掃描出結果後會調用下面的代理方法,其中metadataObject.stringValue就是掃描後的結果。
#pragma mark - AVCaptureMetadataOutputObjectsDelegate -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { if (metadataObjects.count > 0) { AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects firstObject]; }
}
為了在黑夜也可以很好的掃描,可以設置一個閃光燈的開關:
#pragma mark - 開關閃光燈 - (void)rightBarButtonDidClick:(UIBarButtonItem *)item { self.flashOpen = !self.flashOpen; AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; if ([device hasTorch] && [device hasFlash]) { [device lockForConfiguration:nil]; if (self.flashOpen) { device.torchMode = AVCaptureTorchModeOn; device.flashMode = AVCaptureFlashModeOn; } else { device.torchMode = AVCaptureTorchModeOff; device.flashMode = AVCaptureFlashModeOff; } [device unlockForConfiguration]; } }
掃描二維碼
從圖片掃描
有時候我們需要從圖片中掃描二維碼,或者從相冊選擇一張圖片,代碼如下,具體可以看demo。其中feature.messageString就是掃描後的結果。
- (void)findQRCodeFromImage:(UIImage *)image { CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}]; NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]]; if (features.count >= 1) { CIQRCodeFeature *feature = [features firstObject]; } }
從圖片掃描
生成二維碼
生成二維碼的代碼很簡單,代碼如下。
/** 生成指定大小的黑白二維碼 */ - (UIImage *)createQRImageWithString:(NSString *)string size:(CGSize)size { NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding]; CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; // NSLog(@"%@",qrFilter.inputKeys); [qrFilter setValue:stringData forKey:@"inputMessage"]; [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"]; CIImage *qrImage = qrFilter.outputImage; //放大並繪制二維碼 (上面生成的二維碼很小,需要放大) CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent]; UIGraphicsBeginImageContext(size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetInterpolationQuality(context, kCGInterpolationNone); //翻轉一下圖片 不然生成的QRCode就是上下顛倒的 CGContextScaleCTM(context, 1.0, -1.0); CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage); UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGImageRelease(cgImage); return codeImage; }
黑白二維碼
上面默認生成的時黑白二維碼,不過我們也可以改顏色:
/** 為二維碼改變顏色 */ - (UIImage *)changeColorForQRImage:(UIImage *)image backColor:(UIColor *)backColor frontColor:(UIColor *)frontColor { CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor" keysAndValues: @"inputImage",[CIImage imageWithCGImage:image.CGImage], @"inputColor0",[CIColor colorWithCGColor:frontColor.CGColor], @"inputColor1",[CIColor colorWithCGColor:backColor.CGColor], nil]; return [UIImage imageWithCIImage:colorFilter.outputImage]; }
為二維碼改變顏色
有的二維碼也會在中心加一個小圖片,例如用戶頭像,代碼如下:
/** 在二維碼中心加一個小圖 */ - (UIImage *)addSmallImageForQRImage:(UIImage *)qrImage { UIGraphicsBeginImageContext(qrImage.size); [qrImage drawInRect:CGRectMake(0, 0, qrImage.size.width, qrImage.size.height)]; UIImage *image = [UIImage imageNamed:@"small"]; CGFloat imageW = 50; CGFloat imageX = (qrImage.size.width - imageW) * 0.5; CGFloat imgaeY = (qrImage.size.height - imageW) * 0.5; [image drawInRect:CGRectMake(imageX, imgaeY, imageW, imageW)]; UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return result; }
中心加小圖的二維碼
其實也可以掃描條形碼,大家可以對著條形碼試一試,代碼都是通用的。