iOS开发二维码生成和扫描

准备工作

  1. 导入<CoreImage/CoreImage.h>,生成二维码
  2. 导入<AVFoundation/AVFoundation.h>,读取二维码用
  3. 设置代理协议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 = http://www.ithao123.cn/[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 = http://www.ithao123.cn/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

赞 (0) 评论 分享 ()