二维码扫描和创建(上)
来自: http://www.lvesli.com/?p=421
扫描二维码(包括读取和解码)
扫描二维码 OC 的开源库有 ZBar和ZXing 。 iOS7 以后iOS拥有原生的扫码功能。
我在iPhone项目 扫码神奇 中使用的就是下面第三种方法,大家可以到APPStore搜索 扫码神奇 ,下载体验一下(记得给个好评呦)。 扫码神奇 下载链接: https://itunes.apple.com/cn/app/id1074173840
好了下面是具体实现介绍:
ZXing
现在 OC 版本已经停止维护,Java版本还在维护, github 链接: https://github.com/zxing/zxing ,现在也很少有人使用,在 唐巧 的一篇12年 http://blog.devtang.com/blog/2012/12/23/use-zxing-library/ 文章中有关于 ZXing的 配置过程,不过好像他好久没有更新了。 ZXing 相对于 ZBar 的好处是读取和扫码速度快,但是整合到 Xcode 项目中比较痛苦。
ZBar
ZBar 的 github 地址: https://github.com/bmorton/ZBarSDK ,在github上下载的 .a 文件不支持 64位 ,好像也有好今年没有更新了,不过我在网上找到了支持64位的 .a 文件,下载链接: https://markobl.com/2015/03/27/zbar-sdk-64-bit-for-iphone-6-and-ios-8-download/ ,下面说一下 ZBar 的集成步骤:
-
从 github 上下载源文件,解压后如下图,把Headers文件夹拖入到项目中。
-
从 64位.a文件 下载支持64位的.a文件,添加到项目中
-
在新工程中导入以下框架: AVFoundation.framework、CoreMedia.framework、CoreVideo.framework、QuartzCore.framework、libiconv.dylib
-
在需要使用的页面 .h 文件中引用头文件 #import "ZBarSDK.h"
.m 文件中在点击开始扫描的按钮中实现:
ZBarReaderViewController *reader = [ZBarReaderViewController new]; reader.readerDelegate = self; reader.supportedOrientationsMask = ZBarOrientationMaskAll; ZBarImageScanner *scanner = reader.scanner; [scanner setSymbology: ZBAR_I25 config: ZBAR_CFG_ENABLE to: 0]; [self presentViewController:reader animated:YES completion:^{ }];
还要实现 代理 :
- (void) imagePickerController: (UIImagePickerController*) reader didFinishPickingMediaWithInfo: (NSDictionary*) info{ id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults]; ZBarSymbol *symbol = nil; for(symbol in results) break; [self dismissViewControllerAnimated:YES completion:^{ }]; NSString *code = [NSString stringWithString:symbol.data]; }
ZBar 有一个弊端,因为他是静态文件,所以自定义相机比较困难,只能进行简单的修改,我尝试实现微信扫码效果没有实现。
iOS原生扫码
iOS7以后APPle有了自己原生的扫码接口,我当然要义无反顾地选择使用原生的了,下面是我在项目中的部分代码: 在.m文件中:
#import <AVFoundation/AVFoundation.h> @interface SysScannerController ()<AVCaptureMetadataOutputObjectsDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate> @property (nonatomic, strong) AVCaptureSession *session;//输入输出的中间桥梁 @property (strong,nonatomic)AVCaptureDevice *device; @property (strong,nonatomic)AVCaptureDeviceInput *input; @property (strong,nonatomic)AVCaptureMetadataOutput *output; @property (strong,nonatomic)AVCaptureVideoPreviewLayer *preview; @end
懒加载:
#pragma mark - Setter & Getter -(UIView *)line{ if (_line == nil) { _line = [[UIView alloc] initWithFrame:CGRectMake((ScreenFrameWith-180)/2, ScreenFrameHeight/3.f, 180, 4)]; _line.backgroundColor=[UIColor whiteColor]; [self.view addSubview:_line]; } return _line; } -(AVCaptureDevice *)device{ if (_device == nil) { _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; } return _device; } -(AVCaptureDeviceInput *)input{ if (_input == nil) { _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; } return _input; } -(AVCaptureMetadataOutput *)output{ if (_output == nil) { _output = [[AVCaptureMetadataOutput alloc]init]; [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; //限制扫描区域(上左下右) [ _output setRectOfInterest : CGRectMake (1/6.f,1/6.f,4/6.f,4/6.f)]; } return _output; } - (AVCaptureSession *)session{ if (_session == nil) { // Session _session = [[AVCaptureSession alloc]init]; [_session setSessionPreset:AVCaptureSessionPresetHigh]; if ([_session canAddInput:self.input]) { [_session addInput:self.input]; } if ([_session canAddOutput:self.output]) { [_session addOutput:self.output]; } } return _session; } -(AVCaptureVideoPreviewLayer *)preview{ if (_preview == nil) { _preview =[AVCaptureVideoPreviewLayer layerWithSession:self.session]; } return _preview; }
在 -viewDidLoad 中调用下面函数:
- (void)setupCamera { //1. if(self.device == nil){ [self showAlertTipWithTitle:@"未检测到相机" andMessage:@"请检查相机设备是否正常"]; return ; } // 2.添加预览图层 [self.view.layer insertSublayer:self.preview atIndex:0]; self.preview.frame = self.view.bounds; // 3.设置输出能够解析的数据类型 // 注意点: 设置数据类型一定要在输出对象添加到会话之后才能设置 self.output.metadataObjectTypes = self.output.availableMetadataObjectTypes; // 4.设置监听监听输出解析到的数据 [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; // 5.开始扫描 [self.session startRunning]; }
实现 AVCaptureMetadataOutputObjectsDelegate 代理:
#pragma mark AVCaptureMetadataOutputObjectsDelegate - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { if ([metadataObjects count] >0) { AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0]; if ([metadataObject isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) { NSString *stringValue = [metadataObject stringValue]; if (stringValue != nil) { [self.session stopRunning]; //扫描结果 self.scannedResult=stringValue; } } } }
iOS原生的扫码界面你可以随意的自定义了,和自定义相机一样,这里就不做介绍了。
扫描相册中的二维码
扫描相册中的二维码,首先打开相册然后先在UIImagePickerControllerDelegate代理方法中:
#pragma mark - imagePickerController delegate - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { //1.获取选择的图片 UIImage *image = info[UIImagePickerControllerOriginalImage]; //2.初始化一个监测器 CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }]; [picker dismissViewControllerAnimated:YES completion:^{ //监测到的结果数组 NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]]; if (features.count >=1) { /**结果对象 */ CIQRCodeFeature *feature = [features objectAtIndex:0]; NSString *scannedResult = feature.messageString; self.scannedResult=scannedResult; [self performSegueWithIdentifier:@"ToResult" sender:self]; } else{ [self showAlertTipWithTitle:@"提示" andMessage:@"该图片没有包含一个二维码!"]; } }]; }
好了,关于扫描二维码今天就说到这,下一篇我会分享创建二维码功能。 扫描二维码和创建二维码项目展示:APPStore搜索 扫码神奇 。上一篇文章 http://www.lvesli.com/?p=412 中有扫码神奇的具体介绍:
关注微信公众号: lecoding 实时关注文章更新。你也可以扫描下方二维码关注我们:
</div>