原文:http://blog.csdn.net/qq_24307675/article/details/49817701
公司iOS项目需要用到二维码扫描,本来已经有人写好了,但是扫描速度不太快,于是让我接手研究一下。之前也没接触过二维码扫描,写这篇博客献给新手。
先来二维码生成吧,二维码生成需要libqrencode库,将libqrencode库下载下来拖入工程
(文章末会提供下载链接),
在QRCodeGenerator.h中#import<UIKit/UIKit.h>,否则会报错。
使用举例:UIImage *image =[QRCodeGenerator qrImageForString:<#(NSString *)#> imageSize:<#(CGFloat)#>];
直接调用 QRCodeGenerator qrImageForString:<#(NSString *)#> imageSize:<#(CGFloat)#>就可以生成二维码图片,其中string可以是任何字符串,imageSize是生成图片的大小
二维码扫描:现在主流二维码扫描有zbar和zxing两大开源组件
ZBar在扫描的灵敏度上,和内存的使用上相对于ZXing上都是较优的,但是对于 “圆角二维码” 的扫描确很困难
ZXing 是 Google Code上的一个开源的条形码扫描库,是用java设计的,连Google Glass 都在使用的。但有人为了追求更高效率以及可移植性,出现了c++ port. Github上的Objectivc-C port,其实就是用OC代码封装了一下而已,而且已经停止维护。这样效率非常低,在instrument下面可以看到CPU和内存疯涨,在内存小的机器上很容易崩溃。
iOS6后,苹果提供了原生的二维码扫描AVFoundation,AVFoundation无论在扫描灵敏度和性能上来说都是最优的。缺点是不能扫描相册中的二维码,条码扫描不如zbar,不支持iOS6以前的版本。所以有的项目可能需要两种扫描相结合
先来说说zbar吧,公司之前用的就是zbar,由于公司放入二维码的数据有点多,二维码又大又密,扫描的确需要花一定的时间。
先下载zbar导入工程,在build phases的link binary 目录下导入如下库
如果从相册选择二维码扫描参考如下代码:
- (IBAction)pickImageButton:(id)sender {
UIImagePickerController *picker = [[UIImagePickerControlleralloc]init];
picker.sourceType =UIImagePickerControllerSourceTypeSavedPhotosAlbum;
picker.delegate =self;
[selfpresentViewController:pickeranimated:YEScompletion:nil];
}
实现UIImagePickerControllerDelegatea代理- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
UIImage *image = [infoobjectForKey:UIImagePickerControllerOriginalImage];
CGImageRef cgImage = image.CGImage;
ZBarReaderController *readVC = [[ZBarReaderControlleralloc]init];
readVC.delegate =self;
ZBarSymbol *symbol =nil;
for (symbolin [readVCscanImage:cgImage]) {
NSLog(@"%@",symbol.data);
}
[picker dismissViewControllerAnimated:YEScompletion:nil];
}
通过相机扫描的话先设置扫描的范围
_readerView= [[ZBarReaderViewalloc]init]; //必须如此初始化
_readerView.frame =CGRectMake(0,64,VIEW_WIDTH,VIEW_HEIGHT -64);
[_readerViewstart];
默认的是全屏的效果,并没有我们平常微信扫描的那个框,还有那条滑动的线条,所以需要我们自己画,具体代码参考demo(文章末有下载地址)
最后实现ZBarReaderViewDelegate代理-(void)readerView:(ZBarReaderView *)readerView didReadSymbols:(ZBarSymbolSet *)symbols fromImage:(UIImage *)image
{
constzbar_symbol_t *symbol =zbar_symbol_set_first_symbol(symbols.zbarSymbolSet);
NSString *resultStr = [NSStringstringWithUTF8String:zbar_symbol_get_data(symbol)];
NSLog(@"%@",resultStr);
return;
}
再来原生的AVFoundation,个人推荐这种方式,扫描速度相比zbar是火箭的速度(夸张,笑)
先在build phases的link binary 中导入AVFoundation.framework库,然后参考代码
@property (nonatomic)AVCaptureSession *captureSession;
@property (nonatomic)AVCaptureVideoPreviewLayer *videoPreviewLayer;
- (BOOL)startReading
{
// 获取 AVCaptureDevice 实例
NSError * error;
AVCaptureDevice *captureDevice = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];
// 初始化输入流
AVCaptureDeviceInput *input = [AVCaptureDeviceInputdeviceInputWithDevice:captureDeviceerror:&error];
if (!input) {
NSLog(@"%@", [errorlocalizedDescription]);
returnNO;
}
// 创建会话
_captureSession = [[AVCaptureSessionalloc]init];
//提高图片质量为1080P,提高识别效果
_captureSession.sessionPreset =AVCaptureSessionPreset1920x1080;
// 添加输入流
[_captureSessionaddInput:input];
// 初始化输出流
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutputalloc]init];
//设置扫描范围
captureMetadataOutput.rectOfInterest =CGRectMake((_scanCropView.frame.origin.y-10)/VIEW_HEIGHT, (_scanCropView.frame.origin.x-10)/VIEW_WIDTH, (_scanCropView.frame.size.width+10)/VIEW_HEIGHT, (_scanCropView.frame.size.height+10)/VIEW_WIDTH);
// 添加输出流
[_captureSessionaddOutput:captureMetadataOutput];
// 创建dispatch queue.
dispatch_queue_t dispatchQueue;
dispatchQueue =dispatch_queue_create(kScanQRCodeQueueName,NULL);
[captureMetadataOutputsetMetadataObjectsDelegate:selfqueue:dispatchQueue];
// 设置元数据类型 AVMetadataObjectTypeQRCode
[captureMetadataOutput setMetadataObjectTypes:[NSArrayarrayWithObject:AVMetadataObjectTypeQRCode]];
// 创建输出对象
_videoPreviewLayer = [[AVCaptureVideoPreviewLayeralloc]initWithSession:_captureSession];
[_videoPreviewLayersetVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPreviewLayersetFrame:_scanView.layer.bounds];
[_scanView.layerinsertSublayer:_videoPreviewLayeratIndex:0];
// 开始会话
[_captureSessionstartRunning];
return YES;
}
- (void)stopReading
{
// 停止会话
[_captureSessionstopRunning];
_captureSession =nil;
}
其中图片质量,扫描范围是自己设置的,图片质量我设置的是1080P,增强小二维码图片的扫描效果。扫描范围默认是全屏,意思是如果你设置了一个范围框,扫描的时候二维码还没到框里的时候扫描就已经结束了,这里我设置的是比框大20的范围。注意一点是苹果坐标是按左上角作为原点的,所以要注意坐标轴的变化。画框依旧请参考demo。
实现AVCaptureMetadataOutputObjectsDelegate代理
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
fromConnection:(AVCaptureConnection *)connection
{
if (metadataObjects !=nil && [metadataObjects count] > 0) {
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjectsobjectAtIndex:0];
NSString *result;
if ([[metadataObjtype] isEqualToString:AVMetadataObjectTypeQRCode]) {
result = metadataObj.stringValue;
NSLog(@"%@",result);
}else {
NSLog(@"不是二维码");
}
[selfstopReading];
}
return;
}
zxing我没有去研究,值得一提的是,zbarCPU消耗也非常的厉害,扫描的时候CPU能到90%,而原生扫描时候最多2%。
demo下载地址:https://github.com/Chris958/-
扫描效果:因为在模拟器上运行的,所以无法获取图像,黑色的部分都应是显示摄入的图像
原生的我封装成了一个类,只需要将demo中的ScanImageViewController.h和ScanImageViewController.m拖入你需要的工程,实现ScanImageView代理就能实现原生扫描效果,包括了闪光灯的控制。
联系客服