iOS二维码的生成与扫描
Posted 小呀小儿狼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS二维码的生成与扫描相关的知识,希望对你有一定的参考价值。
由于近期工作中遇到了个需求:需要将一些固定的字段 在多个移动端进行相互传输,所以就想到了 二维码 这个神奇的东东! 现在的大街上、连个摊煎饼的大妈 都有自己的二维码来让大家进行扫码支付。可见现在的二维码使用率多高, 不光如此,在很多的社交类的APP 基本都有扫一扫加好友这个功能吧,因此决定学一学这个神奇的东西。
查找了一些资料博客啊发现,ios7之前 对于开发人员来说 熟悉的第三方QRCode库有:
但是iOS7之后呢,系统框架已经集成二维码的生成与读取, 这使开发变得方便很多, 并且会比第三方更加效率。今天就来讲讲用系统原生的方式 来实现二维码的生成和扫描吧
( 一 )高清二维码
系统二维码主要通过 CIFilter 的对象来完成, 当然首先我们需要先导入这个类所在的框架,并实现下面的代码
#import <CoreImage/CoreImage.h> // 1.创建过滤器 -- 苹果没有将这个字符定义为常量 CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; // 2.过滤器恢复默认设置 [filter setDefaults]; // 3.给过滤器添加数据(正则表达式/帐号和密码) -- 通过KVC设置过滤器,只能设置NSData类型 NSString *dataString = @"http://www.baidu.com"; NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding]; [filter setValue:data forKeyPath:@"inputMessage"]; // 4.获取输出的二维码 CIImage *outputImage = [filter outputImage]; // 5.显示二维码 UIImage *image = [UIImage imageWithCIImage:outputImage];
通过上面这种最简单的方式 生成的二维码很模糊,而且二维码的大小也不方便控制,
对于我们来说,需求的是一张 能控制大小,并且高清显示的二维码,因此我们需要用一种方式 将CIImage 转为我们心目中那个UIImage
/** 根据CIImage生成指定大小的UIImage */ + (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat)size { CGRect extent = CGRectIntegral(image.extent); CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent)); // 1.创建bitmap; size_t width = CGRectGetWidth(extent) * scale; size_t height = CGRectGetHeight(extent) * scale; CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone); CIContext *context = [CIContext contextWithOptions:nil]; CGImageRef bitmapImage = [context createCGImage:image fromRect:extent]; CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone); CGContextScaleCTM(bitmapRef, scale, scale); CGContextDrawImage(bitmapRef, extent, bitmapImage); // 2.保存bitmap到图片 CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef); CGContextRelease(bitmapRef); CGImageRelease(bitmapImage); return [UIImage imageWithCGImage:scaledImage]; }
( 二 )彩色二维码
在使用过程中发现了个问题, 就是当我们使用一个长度过长的字段 去生成高清二维码的时候,这个二维码 就会变得非常密集、浓稠, 用手机来扫描的时候,由于手机摄像头像素问题很难读取到这个二维码,因此我需要一个 彩色二维码来增加它的辨识度。
// 1、创建滤镜对象 CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; // 恢复滤镜的默认属性 [filter setDefaults]; // 2、设置数据 NSString *string_data = @"http://www.baidu.com"; NSData *qrImageData = [string_data dataUsingEncoding:NSUTF8StringEncoding]; // 设置过滤器的输入值, KVC赋值 [filter setValue:qrImageData forKey:@"inputMessage"]; // 3、获得滤镜输出的图像 CIImage *outputImage = [filter outputImage]; // 图片小于(27,27),我们需要放大 outputImage = [outputImage imageByApplyingTransform:CGAffineTransformMakeScale(9, 9)]; // 4、创建彩色过滤器(彩色的用的不多) CIFilter * color_filter = [CIFilter filterWithName:@"CIFalseColor"]; // 设置默认值 [color_filter setDefaults]; // 5、KVC 给私有属性赋值 [color_filter setValue:outputImage forKey:@"inputImage"]; // 6、需要使用 CIColor 为背景颜色 和 主颜色 上色 // inputColor0:背景颜色 ,inputColor1 主颜色 // 注意不要使用 [CIColor redColor][CIColor blueColor],这些类似于UIColor的方法只有在iOS 10系统才有 [color_filter setValue:[CIColor colorWithRed:1 green:1 blue:1] forKey:@"inputColor0"]; [color_filter setValue:[CIColor colorWithRed:0 green:0 blue:1] forKey:@"inputColor1"]; // 7、设置输出 CIImage *colorImage = [color_filter outputImage]; //8、输出UIImage UIImage *image = [UIImage imageWithCIIimage:colorImage];
扫描二维码
扫描主要使用的是AVFoundation 使用起来也非常的简单 ,通过设置<AVCaptureMetadataOutputObjectsDelegate>代理可以监听扫描到的二维码中的信息
#import "ViewController.h" #import <AVFoundation/AVFoundation.h> @interface ViewController () <AVCaptureMetadataOutputObjectsDelegate> /// 会话对象 @property (nonatomic, strong) AVCaptureSession *session; /// 图层类 @property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 1、获取摄像设备 AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; // 2、创建输入流 AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; // 3、创建输出流 AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init]; // 4、设置代理 在主线程里刷新 [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; // 设置扫描范围(每一个取值0~1,以屏幕右上角为坐标原点) // 注:微信二维码的扫描范围是整个屏幕,这里并没有做处理(可不用设置) output.rectOfInterest = CGRectMake(0.05, 0.2, 0.7, 0.6); // 5、初始化链接对象(会话对象) self.session = [[AVCaptureSession alloc] init]; // 高质量采集率 [_session setSessionPreset:AVCaptureSessionPresetHigh]; // 5.1 添加会话输入 [_session addInput:input]; // 5.2 添加会话输出 [_session addOutput:output]; // 6、设置输出数据类型,需要将元数据输出添加到会话后,才能指定元数据类型,否则会报错 // 设置扫码支持的编码格式(如下设置条形码和二维码兼容) output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]; // 7、实例化预览图层, 传递_session是为了告诉图层将来显示什么内容 self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session]; _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; _previewLayer.frame = self.view.layer.bounds; // 8、将图层插入当前视图 [self.view.layer insertSublayer:_previewLayer atIndex:0]; // 9、启动会话 [_session startRunning]; } #pragma mark - 获取扫描结果 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { if (metadataObjects.count > 0) { AVMetadataMachineReadableCodeObject *object = [metadataObjects lastObject]; NSLog(@"%@", object.stringValue); } } @end
AVCaptureMetadataOutput 有个属性 rectOfInterest 他是用来控制你屏幕扫描的范围的,默认是按照整个屏幕来扫描,
rectOfInterest
的值的范围都是0-1 是按比例取值而不是实际尺寸 不过其实也很简单 只要换算一下就好了 ,这里唯一要注意的一点是 rectOfInterest 都是按照横屏来计算的 所以当竖屏的情况下 x轴和y轴要交换一下
读取二维码
读取主要用到CoreImage 不过要强调的是读取二维码的功能只有在iOS8之后才支持,读取的代码也非常的简单
//首先拿到 我们需要读取的那个图片 UIImage * srcImage = qrcodeImage; CIContext *context = [CIContext contextWithOptions:nil]; // CIDetector(CIDetector可用于人脸识别)进行图片解析,声明一个CIDetector,并设定识别类型 CIDetectorTypeQRCode CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}]; CIImage *image = [CIImage imageWithCGImage:srcImage.CGImage]; // 取得识别结果是个数组 NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]]; for (int index = 0; index < [features count]; index ++) { CIQRCodeFeature *feature = [features objectAtIndex:index]; //这个String就是我们从二维码中获取到的信息 NSString *scannedResult = feature.messageString; }
以上是关于iOS二维码的生成与扫描的主要内容,如果未能解决你的问题,请参考以下文章
iOS 简单易用的二维码扫描及生成二维码三方控件LFQRCode,可灵活自定义UI
Cordova各个插件使用介绍系列—$cordovaBarcodeScanner扫描二维码与生成二维码