初次接触二维码扫描的时候还是iOS4.3的系统,那时候还没有原生的API,记得当时是使用zbar来弄的,那个麻烦啊……现在好了,Core Image就可以实现二维码的生成和从图片识别二维码。
一、二维码的生成
使用CIQRCodeGenerator滤镜即可从字符串生成二维码:
+ (UIImage *)generateQRCode:(NSString *)inputMessage size:(CGSize)size {
NSData *data = [inputMessage dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:NO];
//inputCorrectionLevel 二维码的容错率 L: 7% M: 15% Q: 25% H: 30%
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"
withInputParameters:@{@"inputMessage": data, @"inputCorrectionLevel" : @"Q"}];
CIImage *image = [filter outputImage];
CIContext *context = [CIContext contextWithOptions:nil];
//改变尺寸前的位图
CGImageRef bitmap = [context createCGImage:image fromRect:image.extent];
CGFloat sx = size.width / image.extent.size.width;
CGFloat sy = size.height / image.extent.size.height;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceGray();
//位图上下文
CGContextRef bitmapRef = CGBitmapContextCreate(nil, size.width, size.height, 8, 0, colorSpaceRef, 0);
CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
CGContextScaleCTM(bitmapRef, sx, sy);
//重画图片
CGContextDrawImage(bitmapRef, image.extent, bitmap);
CGImageRef scaleImage = CGBitmapContextCreateImage(bitmapRef);
return [[UIImage alloc] initWithCGImage:scaleImage];
}
CIQRCodeGenerator生成的二维码图片大小是不固定的,所以需要重画缩放图片到指定大小。
二、从图片检测二维码
使用CIDetector来实现:
+ (NSString *)detecteQRCode:(UIImage *)image {
CIContext *context = [CIContext contextWithOptions:nil];
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
if (features && features.count > 0) {
return ((CIQRCodeFeature *)features[0]).messageString;
}
return nil;
}
三、扫描二维码
可使用AVFoundation来扫描二维码:
在ViewController中增加以下定义:
@property (nonatomic, strong) UIView *viewPreview;
@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
关键代码:
- (BOOL)startScanning {
NSError *error;
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
NSLog(@"%@", [error localizedDescription]);
return NO;
}
_captureSession = [[AVCaptureSession alloc] init];
[_captureSession addInput:input];
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
[_captureSession addOutput:captureMetadataOutput];
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("captureQueue", NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPreviewLayer setFrame:_viewPreview.layer.bounds];
[_viewPreview.layer addSublayer:_videoPreviewLayer];
[_captureSession startRunning];
return YES;
}
声明和实现AVCaptureMetadataOutputObjectsDelegate协议
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
if (metadataObjects != nil && [metadataObjects count] > 0) {
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
NSLog(@"Code: %@", [metadataObj stringValue]);
}
}
}
以上代码会在设备扫描到二维码后将字符串输出到控制台。