• 二维码扫描知识点


    二维码知识点总结

    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,  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框架
    • 利用摄像头识别二维码中的内容(模拟器不行)
  • 相关阅读:
    C语言的数据、常量和变量
    C语言关键字、标识符和注释
    关于C/C++的一些讨论
    C++ 复合类型(上)
    C 函数
    C 字符输入输出和输入确认
    C++数据处理
    C控制语句:分支与跳转
    C++ 预备知识#关于C++
    范型在java中的应用
  • 原文地址:https://www.cnblogs.com/coderwjq/p/6211138.html
Copyright © 2020-2023  润新知