二维码扫描知识点

二维码知识点总结

01-二维码简介

1.概念

  • 二维码:用某种特定的集合图形按照一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号的信息
  • 生成二维码:根据给定的信息,将其按照二维码的编码方式生成一张图片
  • 读取二维码:识别二维码图像里面存储的数据

2.使用场景

  • 信息获取(名片/WiFi密码/资料)
  • 手机电商(用户扫码/手机直接购物下单)
  • 加好友(QQ/微信/扫一扫加好友)
  • 手机支付(扫描商品二维码,通过银行或第三方支付提供的手机端通道完成支付)

3.生成方式

  • 从iOS7开始集成了二维码的生成和读取功能
  • 此前被广泛使用的zbarsdk目前不支持64位处理器
  • 2015年2月1日起,不允许不支持64位处理器的APP上架

4.二维码读取

  • 直接从图片中识别,最低支持iOS8.0
  • 利用摄像头扫描识别,需要真机设备

02-生成/识别/读取二维码

1.生成二维码

  • 导入CoreImage框架
    • 一些图片处理操作的功能,都是用这个框架实现,比如:滤镜效果/毛玻璃/美颜相机等
    • #import <CoreImage/CoreImage.h>
  • 通过滤镜CIFilter生成二维码
    1. 实例化二维码滤镜 CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    2. 恢复滤镜的默认属性 [filter setDefault];
    3. 将字符串转换成NSData NSData *data = [@"木喳喳的夏天" dataUsingEncoding:NSUTF8StringEncoding];
    4. 通过KVC设置滤镜inputMessage数据 [filter setValue:data forKey:@"inputMessage"];
    5. 获得滤镜输出的图像,大小默认是23*23 CIImage *outputImage = [filter outputImage];
    6. 将CIImage转换成UIImage,并放大显示 return [UIImage imageWithCIImage:outputImage scale:20.0 orientation:UIImageOrientationUp];
    7. 通过位图创建高清图片
/**
     根据CIImage生成指定大小的高清UIImage
     :param: image 指定CIImage
     :param: size    指定大小
     :returns: 生成好的图片
     */
    private func createBigImage(image: CIImage, size: CGFloat) -> UIImage {

        let extent: CGRect = CGRectIntegral(image.extent)
        let scale: CGFloat = min(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent))

        // 1.创建bitmap;
        let width = CGRectGetWidth(extent) * scale
        let height = CGRectGetHeight(extent) * scale
        let cs: CGColorSpaceRef = CGColorSpaceCreateDeviceGray()!
        let bitmapRef = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, cs, 0)!

        let context = CIContext(options: nil)
        let bitmapImage: CGImageRef = context.createCGImage(image, fromRect: extent)

        CGContextSetInterpolationQuality(bitmapRef,  CGInterpolationQuality.None)
        CGContextScaleCTM(bitmapRef, scale, scale);
        CGContextDrawImage(bitmapRef, extent, bitmapImage);

        // 2.保存bitmap到图片
        let scaledImage: CGImageRef = CGBitmapContextCreateImage(bitmapRef)!

        return UIImage(CGImage: scaledImage)
    }

2.自定义二维码

  • 所谓自定义二维码,就是指给二维码添加一些图片(前景或背景图片),或者改变下颜色
  • 可以添加前景图片的前提是因为二维码具备一定的"容错率"
    • 如果二维码被部分遮挡,可以根据其他部分,计算出遮挡部分的内容;
    • 但是要保证三个角不能被遮挡;
    • 三个角用作扫描定位使用(可能用户倒着拍/斜着拍等)
  • 通过KVC设置滤镜的inputCorrectionLevel(容错率)
    • @"L",@"M",@"Q",@"H"中的一个
    • L水平:7%的字码可被修正
    • M水平:15%的字码可被修正
    • Q水平:25%的字码可被修正
    • H水平:30%的字码可被修正
func createImage(bgImage: UIImage?, iconImage: UIImage?) -> UIImage?
{
    if bgImage == nil || iconImage == nil
    {
        return nil
    }
    // 1.开启图片上下文
    UIGraphicsBeginImageContext(bgImage!.size)
    // 2.绘制背景
    bgImage!.drawInRect(CGRect(origin: CGPointZero, size: bgImage!.size))
    // 3.绘制图标
    let w:CGFloat = 50
    let h = w
    let x = (bgImage!.size.width - w) * 0.5
    let y = (bgImage!.size.height - h) * 0.5
    iconImage!.drawInRect(CGRect(x: x, y: y, width: w, height: h))
    // 4.取出图片
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    // 5.关闭上下文
    UIGraphicsEndImageContext()

    return newImage
}

3.识别二维码

  • 识别图片二维码
    1. 创建一个上下文 let context = CIContext()
    2. 创建一个探测器 let detector = CIDetector(ofType:CIDetectorTypeQRCode,context:context,option:[CIDetectorAccuracy:CIDetectorAccuracyHigh])
    3. 转换图片为CIImage let image = CIImage(CGImage:sourceImage.CGImage)
    4. 获取探测器识别的图像特征 let features = detector.featuresInImage(image)
    5. 遍历图片特征,获取数据
      • var tempArray = [String]()
      • for feature in features {}
      • let resultFeature: CIQRCodeFeature = feature as! CIQRCodeFeature
      • tempArray.append(resultFeature.messageString)
    6. 绘制识别到的二维码边框
private class func drawRectInImage(qrFeature: CIQRCodeFeature, image: UIImage) -> UIImage
{
    let size = image.size
    UIGraphicsBeginImageContext(size)

    image.drawInRect(CGRectMake(0, 0, size.width, size.height))

    // 反转坐标系(因为是别的二维码坐标是相对于图片的坐标, 坐标系是以, 左下角为0, 0, 所以需要上下翻转坐标系)
    let context = UIGraphicsGetCurrentContext()
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextTranslateCTM(context, 0, -image.size.height);

    let path: UIBezierPath = UIBezierPath(rect: qrFeature.bounds)

    UIColor.redColor().set()
    path.lineWidth = 6
    path.stroke()

    let resultImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()
    
    return resultImage 
}

3.2 扫描二维码

  • 二维码扫描动画
  • 二维码扫描功能
    1. 实例化拍摄设备
      • AVCaptureDevice *device = [AVCaputureDevice defalutDeviceWithMediaType:AVMediaTypeVideo];
    2. 设置输入设备
      • AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    3. 设置元数据输出处理对象
      • 实例化拍摄元数据输出
      • AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
      • 设置输出数据代理
      • [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    4. 添加拍摄会话
      • 实例化拍摄会话
      • AVCaptureSession *session = [[AVCaptureSession alloc] init];
      • 添加会话输入
      • [session addInput:input];
      • 添加会话输出
      • [session addOutput:output];
      • 设置输出数据类型,需要将元数据输出添加到会话后,才能指定元数据类型,否则报错
      • [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
    5. 视频预览图层(不是必须)
      • 实例化预览图层
      • AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:_session];
      • preview.frame = self.view.bounds;
      • 将图层插入当前视图
      • [self.view.layer addSublayer:preview];
      • self.previewLayer = preview;
    6. 启动会话
      • [_session startRunning];
    7. 监听元数据处理后的结果
      • 当扫描到数据就会执行captureOutput:didOutputMetadataObjects:fromConnection
  • 二维码边框描绘
    • 提示:获取到二维码后,可以获得二维码的四个角,但是需要使用预览图层进行坐标转换
    • previewLayer.transformedMetadataObjectForMetadataObject(object as! AVMetadataObject)
    • 创建CAShapLayer,并设置path
  • 二维码扫描区域限定
    • 设置兴趣点
    • 注意:每个参数的取值都是对应的比例
    • 注意:坐标系是横屏状态下的坐标系
    • 而且值域范围是0-1
    • output.rectOfInterest = rect

3.3 使用注意

  • 读取二维码需要导入AVFoundation框架
  • 利用摄像头识别二维码中的内容(模拟器不行)
posted @ 2016-12-22 14:33  喳喳的夏天  阅读(738)  评论(0编辑  收藏  举报