您的位置:首页 > 移动开发 > IOS开发

iOS开发二维码生成和扫描

2017-01-06 11:03 387 查看

准备工作

导入
<CoreImage/CoreImage.h>
,生成二维码用

导入
<AVFoundation/AVFoundation.h>
,读取二维码用

设置代理协议
AVCaptureMetadataOutputObjectsDelegate
,这是有关摄像设备输出的相关代理

注意:扫描二维码的时候,要在info.plist文件中添加字段,否则会崩溃(iOS10之后的隐私权限问题)

<!-- 相册 -->
<key>NSPhotoLibraryUsageDescription</key>
<string>App需要您的同意,才能访问相册</string>
<!-- 相机 -->
<key>NSCameraUsageDescription</key>
<string>App需要您的同意,才能访问相机</string>


二维码的生成

1.生成二维码的步骤:

1.导入CoreImage框架
2.通过滤镜CIFilter生成二维码


2.代码如下

调用下方根据字符串生成二维码的方法即可获得二维码
// 生成二维码
- (UIImage *)createImageWithString:(NSString *)string{

// 1.实例化二维码滤镜
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
// 2.恢复滤镜的默认属性(因为滤镜可能保存上一次的属性)
[filter setDefaults];

// 3.讲字符串转换为NSData
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];*

// 4.通过KVO设置滤镜inputMessage数据
[filter setValue:data forKey:@"inputMessage"];

// 5.通过了滤镜输出的图像
CIImage *outputImage = [filter outputImage];

// 6.因为生成的二维码模糊,所以通过createNonInterpolatedUIImageFormCIImage:outputImage来获得高清的二维码图片

UIImage *image = [self getErWeiMaImageFormCIImage:outputImage withSize:200];

return image;
}


// 获取高清二维码图片
- (UIImage *)getErWeiMaImageFormCIImage:(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.读取二维码的步骤:

1.读取二维码需要导入AVFoundation框架(上方准备工作的时候已经说了)
2.利用相机识别二维码中的内容(只能是真机)
3.会话将相机采集到的二维码图像转换成字符串数据


2.原生扫描中用到的几个类

AVCaptureDevice                        // 拍摄设备
AVCaptureDeviceInput                   // 输入设备
AVCaptureMetadataOutput                // 元数据输出
AVCaptureSession                       // 拍摄会话
AVCaptureVideoPreviewLayer             // 视频预览图层


3.代码如下

- (void)readQRCode{

// 1.实例化拍摄装备
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

// 2.设置输入设备
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];

// 3.设置元数据输出
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];   // 设置代理

// 4.添加拍摄会话
self.session = [[AVCaptureSession alloc] init];
[self.session addInput:input];       // 添加会话输入
[self.session addOutput:output];     // 添加会话输出

[output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];      // 设置输出数据类型(需要将元数据输出添加到会话后才能制定元数据类型,否则会报错)

// 5.视频预览图层
self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session]; // 传递session是为了告诉图层将来显示什么内容
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;   // 显示方式
// 设置videoGravity,顾名思义就是视频播放时的拉伸方式,默认是AVLayerVideoGravityResizeAspect
// AVLayerVideoGravityResizeAspect 保持视频的宽高比并使播放内容自动适应播放窗口的大小。
// AVLayerVideoGravityResizeAspectFill 和前者类似,但它是以播放内容填充而不是适应播放窗口的大小。最后一个值会拉伸播放内容以适应播放窗口.
// 因为考虑到全屏显示以及设备自适应,这里我们采用fill填充

self.previewLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:self.previewLayer atIndex:0]; // 将图层插入当前图层

// 6.启动会话
[self.session startRunning];
}


AVCaptureMetadataOutputObjectsDelegate 的代理方法
/**
扫描结果处理

@param captureOutput 输出数据源
@param metadataObjects 扫描结果数组
@param connection 用于协调输入与输出之间的数据流
*/
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{

// 1.判断扫描结果的数据是否存在
if ([metadataObjects count] > 0) {
// 2.如果存在数据,则停止会话
[self.session stopRunning];
// 3.删除预览图层
[self.previewLayer removeFromSuperlayer];

AVMetadataMachineReadableCodeObject *metadataObject = metadataObjects[0];

// AVMetadataMachineReadableCodeObject 是AVMetadataObject的具体子类定义的特性检测一维或二维条形码。
// AVMetadataMachineReadableCodeObject代表一个单一的照片中发现机器可读的代码。这是一个不可变对象描述条码的特性和载荷。
// 在支持的平台上,AVCaptureMetadataOutput输出检测机器可读的代码对象的数组

NSString *stringValue = metadataObject.stringValue;

if ([stringValue containsString:@"http"]) {

// 如果是字符串,则打开连接
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:stringValue] options:[NSDictionary dictionary] completionHandler:^(BOOL success) {

if (success) {
NSLog(@"成功");
}
}];
}else{
NSLog(@"普通字符串:%@",stringValue);     // 可以将字符串放到需要用到的地方(比如label)
}
}
}


传送门:https://github.com/yangchao970093824/CreateAndReadQRCode
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息