由于近期工作中遇到了个需求:需要将一些固定的字段 在多个移动端进行相互传输,所以就想到了 二维码 这个神奇的东东! 现在的大街上、连个摊煎饼的大妈 都有自己的二维码来让大家进行扫码支付。可见现在的二维码使用率多高, 不光如此,在很多的社交类的APP 基本都有扫一扫加好友这个功能吧,因此决定学一学这个神奇的东西。

  查找了一些资料博客啊发现,iOS7之前 对于开发人员来说 熟悉的第三方QRCode库有:

    • ZXing
      Google出品并开源 一直到现在都还有专人维护 是世界上使用最广的二维码库 iOS上比较稳定的移植版是ZXingObj

    • ZBar
      功能上与ZXing不相伯仲 可惜的是项目在2012年之后就不维护了 虽然代码到现在还可以使用

但是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系统原生 二维码的生成、扫描和读取(高清、彩色)的更多相关文章

  1. iOS系统原生二维码条形码扫描

    本文讲述如何用系统自带的东东实现二维码扫描的功能:点击当前页面的某个按钮,创建扫描VIEW.细心的小伙伴可以发现 title被改变了,返回按钮被隐藏了.这个代码自己写就行了,与本文关系不大...绿色的 ...

  2. iOS:原生二维码扫描

    做iOS的二维码扫描,有两个第三方库可以选择,ZBar和ZXing.今天要介绍的是iOS7.0后AVFoundation框架提供的原生二维码扫描. 首先需要添加AVFoundation.framewo ...

  3. iOS笔记061 - 二维码的生成和扫描

    二维码 生成二维码 二维码可以存放纯文本.名片或者URL 生成二维码的步骤: 导入CoreImage框架 通过滤镜CIFilter生成二维码 1.创建过滤器 2.恢复滤镜的默认属性 3.设置内容 4. ...

  4. iOS 原生二维码扫描和生成

    代码地址如下:http://www.demodashi.com/demo/12551.html 一.效果预览: 功能描述:WSLNativeScanTool是在利用原生API的条件下封装的二维码扫描工 ...

  5. iOS端使用二维码扫描(ZBarSDK)和生成(libqrencode)功能

    如今二维码随处可见,无论是实物商品还是各种礼券都少不了二维码的身影.手机中二维码使用也很广泛,如微信等.正好最近收集总结了下二维码的使用方法 下面介绍一下如何在iOS设备上使用二维码 首先在githu ...

  6. iOS 二维码的生成 QREncoder

    生成二维码: 在生成二维码的库中QREncoder最为常见,但是由于中文字符的特殊性,生成中文的时候有时会出现一定的错误,所以建议使用libqrencode,是一个纯C编写的类库. 以libqrenc ...

  7. iOS开发 - 二维码的生成与读取

    二维码的生成 从iOS7開始集成了二维码的生成和读取功能 此前被广泛使用的zbarsdk眼下不支持64位处理器 生成二维码的步骤: 导入CoreImage框架 通过滤镜CIFilter生成二维码 二维 ...

  8. iOS开发技术 - 二维码扫描、生成

    QRecLevel:QR_ECLEVEL_H // 二维码容错率,最高为30%(即QR_ECLEVEL_H),即LOGO有大                                       ...

  9. 使用IOS7原生API进行二维码条形码的扫描

    使用IOS7原生API进行二维码条形码的扫描 IOS7之前,开发者进行扫码编程时,一般会借助第三方库.常用的是ZBarSDK,IOS7之后,系统的AVMetadataObject类中,为我们提供了解析 ...

随机推荐

  1. git教程(简单的带你学好git)

    刚开始使用的时候没有找到好的资源学习,下面这个资源不错,大家可以参考学习. http://www.liaoxuefeng.com/wiki/0013739516305929606dd183612485 ...

  2. 浅谈css中单位px和em,rem的区别-转载

    px是你屏幕设备物理上能显示出的最小的一个点,这个点不是固定宽度的,不同设备上点的长宽.比例有可能会不同.假设:你现在用的显示器上1px宽=1毫米,但我用的显示器1px宽=两毫米,那么你定义一个div ...

  3. 【C和指针】笔记1

    数据 基本数据类型 整型家族:包含字符,短整型,整型和长整型 整型相互之间大小规定如下: 长整型至少和整型一样长,而整型至少应该和短整型一样长. short int至少16位,long int至少32 ...

  4. spring之bean

    Bean的基本配置 id属性 id属性确定bean的唯一标识符,容器对bean的管理,访问,以及该bean的依赖关系,都通过该属性来完成.bean的id属性在Spring容器中应该是唯一的. clas ...

  5. POJ 3261 出现至少K次的可重叠最长子串

    题意就是给一列数字,求最长的一个子串,并且满足子串在原数串中出现至少K次,子串可以重叠. 解法是将问题转为判定性问题,二分子串的长度,判定是否满足重复至少K次.判定方法是经典的根据子串长度将Heigh ...

  6. JS对象或属性的不变性

    提到不变性,不得不提一个概念: 对象常量定义:结合可写性与可配置性可以创建一个真正的常量属性(不可修改.重定义.删除) 不变性可划分为以下几个等级: 1)禁止扩展:Object.preventExte ...

  7. html、css、js实现简易计算器

    学习HTML,CSS,JS一个月后,想着能自己是否能写出一个简单的东西,故编写了简易的计算器,之前也写过一个坦克大战,坦克大战的有些基本功能没有实现, 故也没有记录下来,想来,对这行初来咋到的,还是需 ...

  8. 查询表达式和LINQ to Objects

    查询表达式实际上是由编译器“预处理”为“普通”的C#代码,接着以完全普通的方式进行编译.这种巧妙的发式将查询集合到了语言中,而无须把语义改得乱七八糟 LINQ的介绍 LINQ中的基础概念 降低两种数据 ...

  9. 55 Jump Game i && 45 Jump Game ii

    Jump Game Problem statement: Given an array of non-negative integers, you are initially positioned a ...

  10. PHP获取指定页面的指定内容

    在刚入手PHP的时候,经理让我自己做一个文章的管理系统为了方便管理微信端发的消息.除了简单的添加分类.管理分类.添加文章.管理文章,还有一个功能就是要从微信文章网址中拿到网址上的标题.作者以及发表时间 ...