前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >swift手撕二维码一、简介二、二维码综合案例

swift手撕二维码一、简介二、二维码综合案例

作者头像
谦谦君子修罗刀
发布2018-05-02 10:51:15
1.7K0
发布2018-05-02 10:51:15
举报

超市付款扫一扫,免费wifi扫一扫,添加好友扫一扫。 二维码就像是神一般的存在!! 可是到底二维码是个啥呢?

QRCode.jpg

一、简介

1、概念

用某种特定的几何图形按照一定规律在平面分布的黑白相间的图形记录数据符号信息的。所谓生成二维码就是根据给定的信息,将其按照二维码的编码方式来生成一张图片,而读取二维码就是识别二维码图形里面存储的数据。

2、场景

信息获取:比如说获取个人资料、wifi密码 手机电商:用户扫码 加好友:QQ微信扫一扫

3、生成方式

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

4、二维码读取

常用两种方式:一种是从图片中识别,最低支持iOS8.0,另一种是利用摄像头扫描识别,需要真机设备。

二、二维码综合案例

案例1、生成二维码

1、导入CoreImage框架 import CoreImage 该框架专用于做一些图片处理操作,如滤镜效果,毛玻璃,美颜相机等效果

2、通过滤镜CIFilter生成二维码 其实主要步骤就是创建滤镜将数据输入到滤镜中,再由滤镜输出二维码图片。可细分为以下步骤。

  • 实例化二维码滤镜
  • 恢复滤镜的默认属性
  • 将字符串转换成NSData数据
  • 通过KVC设置滤镜inputMessage数据
  • 获得滤镜输出的图像
  • 将CIImage转换成UIImage,并放大显示
  • 通过位图创建高清图片

2.1 创建滤镜 在创建滤镜的时候使用带name的函数,后面跟的值一定要写成“CIQRCodeGenerator”

代码语言:javascript
复制
let filter = CIFilter(name:"CIQRCodeGenerator")

2.2 设置滤镜的输入数据

滤镜的输入数据必须要转换成NSData数据,然后通过KVC方式设置滤镜的inputMessage数据

代码语言:javascript
复制
let data = "456".data(using:String.Encoding.utf8)
filter?.setValue(data, forKey: "inputMessage")

2.3 从二维码中获取结果

为了代码的健壮性,在操作之前先判断从滤镜中输出的图片是否为nil。若有值,将CIImage图片转换成UIImage类型的图片。

代码语言:javascript
复制
if let image = filter?.outputImage {
            let resultImage = UIImage(ciImage: image)
            print(resultImage.size)
            //显示结果
            qrCoderImageView.image = resultImage
        }

生成二维码的基本步骤就到此为止,但是如果此时运行代码,会发现生成的二维码是非常模糊 的。

依上图所示,计算机获取到的二维码图片大小为(23,23),而我们给要显示它的ImageView设定的范围必定远远超过该大小,所以就会造成图片拉伸而导致的显示不清晰的效果。 解决方法就是将滤镜输出的图片按照比例放大20倍。

代码语言:javascript
复制
if var  image = filter?.outputImage {
            let transform = CGAffineTransform(scaleX: 20, y: 20)
            image = image.transformed(by: transform)
            let resultImage = UIImage(ciImage: image)
            print(resultImage.size)
            //显示结果
            qrCoderImageView.image = resultImage
        }

此时可以看到输出size的值为(460,460),二维码瞬间清晰了不少呢。 用手机软件扫描该二维码会显示456字样

案例2、自定义二维码

1、简述

啥叫自定义二维码呢,其实就是指给二维码做添加图片或改变颜色的操作。 改变二维码的颜色或者添加背景图片不会对二维码扫描造成影响,可是若在二维码上添加了前景则必定会遮挡住二维码的某些部分,那么我们又怎么确保能正确的扫描到二维码指定的地址去呢? 那么这里就不得不提到“纠错率”的概念了。二维码中有三个角用来做扫描定位使用,只要保证这三个角不被遮挡,就算其他部分有被遮挡的地方,也能根据其他部分计算出被遮挡的数据。

2、设置纠错率

如上所示,也是通过KVC的形式来设置滤镜的inputCorrectionLevel。 value有如下几个:L水平表示7%的字码可以修正,M水平表示15%的字码可以修正,Q水平代表25%的字码可以修正,H水平代码30%的字码可以纠正。 水平越高,二维码的信息的细节分散得越开。但是,也并不是说水平越高就越好,因为随着level的升高,扫描的时间也会越长。

代码语言:javascript
复制
        filter?.setValue("M", forKey: "inputCorrectionLevel")

下面来做图片处理的操作,给二维码加上前景图片。 创建一个方法,传入二维码图片与要加入的前景图片作为参数,返回值为一张加了前景图的二维码图片。

代码语言:javascript
复制
 func getNewImage(sourceImage:UIImage,center:UIImage) -> UIImage {
 }

在方法中首先要通过传入的二维码图片开启图像的上下文

代码语言:javascript
复制
let size = sourceImage.size
  //开启图形上下文
UIGraphicsBeginImageContext(size)

之后绘制大小图片,大图片即为二维码,设置大小边框为0,0,宽度,高度

代码语言:javascript
复制
  sourceImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))

小图片要放在大图片中心,可以给出固定的宽高,而它的位置则放在(二维码宽度或高度-小图片的宽度或高度)* 0.5

代码语言:javascript
复制
  //绘制小图片
        let width:CGFloat = 80
        let height:CGFloat = 80
        let x :CGFloat = (size.width-width)*0.5
        let y:CGFloat = (size.height-height)*0.5
        
        center.draw(in: CGRect(x: x, y: y, width: width, height: height))

接下来取出结果图片,关闭上下文,返回结果就能够完成这个方法了

代码语言:javascript
复制
 //取出结果图片
   let resultImage = UIGraphicsGetImageFromCurrentImageContext()
   //关闭上下文
   UIGraphicsEndImageContext()
   //返回图片
   return resultImage!

回到touchsBegin方法中,创建需要嵌入到二维码中的小图片,并用二维码图片调用封装好的方法得到返回的图片

代码语言:javascript
复制
 let center = UIImage(named: "img_1.jpg")
  resultImage = getNewImage(sourceImage: resultImage, center: center!)

当然,为了在未编辑时回收键盘,可以加上一句

代码语言:javascript
复制
        view.endEditing(true)

image.png

案例3、识别二维码

工欲善其事必先利其器,先把需要的imageView组件和UIButton方法及需要识别的图片统统加入到Xcode。 1、在按钮的实现方法中,首先要获取需要识别的图片

代码语言:javascript
复制
 @IBOutlet weak var souceImageView: UIImageView!
    
    @IBAction func detectorQRCode(_ sender: Any) {
        // 1、获取需要识别的图片
        let image = souceImageView.image
        }

2、第二步进行识别。 2.1先创建一个二维码的探测器

探测器的类型为二维码类型,场景可以由自己选择,在这里我们选择用识别度较高的CIDetectorAccuracyHigh

代码语言:javascript
复制
 //2.1创建一个二维码探测器
        let dector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])

2.2探测二维码特征 获取到二维码的所有特征并遍历,在这里获取特征的方法传入的参数是一个CIImage,所以要先将二维码图片转换CIImage类型。遍历特征,将取出的特征转换为CIQRcodeFeature即二维码特征。

代码语言:javascript
复制
 let ciImage = CIImage(image: image!)
let features = dector?.features(in: ciImage!)
        for feature in features! {
            let qrFeature = feature as!CIQRCodeFeature
            print(qrFeature.messageString as Any)
        }

案例4、扫描二维码

1、二维码的扫描动画 底部添加一个View,约束:w:200,h:200,水平和垂直都居中 在View上面添加一个imageView,存放扫描框的图片。约束:上下左右为0 在View上面添加一个imageView,存放线的图片。在现实中,扫描线是会随时间而发生变化的。最好的方法就是改变图片底部的约束。为它做出动画的效果。约束条件为:左:0,下:0,与View等宽等高。

将底部的约束拖入到代码中,命名为toButtom

代码语言:javascript
复制
 @IBOutlet weak var toButtom: NSLayoutConstraint!

接下来要为扫描线设置动画,创建一个类扩展自ScanQRCode,添加一个扫描方法。 在扫描的时候,线是从最上方往最下方开始扫描,因此底部的约束最开始的时候是停留在最上方。可以将背景View拖入代码中给底部约束做参考。进行重新约束之后添加动画。而且要求动画一直循环滚动。

代码语言:javascript
复制
extension ScanQRCode {
    func startScanAnimation() -> () {
        toButtom.constant = scanBgView.frame.size.height
        //重新布局
        view.layoutIfNeeded()
        //修改
        toButtom.constant = -scanBgView.frame.size.height
        //添加动画
        UIView.animate(withDuration: 1) {
            UIView.setAnimationRepeatCount(MAXFLOAT)
            self.view.layoutIfNeeded()
        } 
    }

接下来在viewDidAppear方法中调用

代码语言:javascript
复制
override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startScanAnimation()
    }

至此已经有了扫描的功能,但是因为约束的关系,扫描线会超出页面,因此,我们要将背景View绘制成Clip to Bounds,切除背景图以外的图片。

2、二维码的扫描功能实现 输入仪器有很多种,比如说摄像仪器,话筒仪器,因此在扫描之前要先设置输入仪器为摄像仪器,将摄像仪器作为输入设备再识别图片,识别出来之后通过会话将源数据处理对象连接起来,接着启动会话,让输入仪器开始采集数据,输出对象开始处理数据。这就是二维码扫描功能的实现。

创建一个方法,用来做扫描操作 2.1设置输入

  • 导入设备所需要的框架
代码语言:javascript
复制
import AVFoundation
  • 创建扫描的方法
代码语言:javascript
复制
 func startScan() -> () {}
  • 获取摄像头
代码语言:javascript
复制
 let device = AVCaptureDevice.default(for: AVMediaType.video)
  • 把摄像头设备当做输入设备
代码语言:javascript
复制
var input:AVCaptureDeviceInput?
        do {
            input = try AVCaptureDeviceInput(device: device!)
        } catch {
            print(error)
            return
        }

2.2设置输出

代码语言:javascript
复制
   let output = AVCaptureMetadataOutput()
  • 设置结果处理的代理
代码语言:javascript
复制
        output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
  • 实现代理方法
代码语言:javascript
复制
 //扫描到结果之后调用
extension ScanQRCode:AVCaptureMetadataOutputObjectsDelegate{
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        print("test")
    }
}

2.3创建会话,连接输入和输出

  • 因为输入和输出到最后都放到了session中处理,所以可以在方法之外定义一个全局的session变量
代码语言:javascript
复制
var session:AVCaptureSession?
代码语言:javascript
复制
session = AVCaptureSession()
        //并非所有的设备都能被添加进来,所以要做判断
        if session!.canAddInput(input!)&&session!.canAddOutput(output){
            session!.addInput(input!)
            session!.addOutput(output)
        }else{
            return
        }
  • 设置二维码可以识别的编码制度
代码语言:javascript
复制
output.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
  • 添加视频预览图层 (让用户可以看到界面)
代码语言:javascript
复制
        let layer = AVCaptureVideoPreviewLayer(session:session!)
        layer.frame = view.layer.bounds
        view.layer.addSublayer(layer)
  • 插入边框
代码语言:javascript
复制
 // 这样是没有二维码的边框的,所以插入边框
  view.layer.insertSublayer(layer, at: 0)
  • 此时还是会有一个背景色,所以到storybord中将scanBgView的背景颜色去除

2.4启动会话,让输入开始采集数据,输出对象开始处理数据

代码语言:javascript
复制
   session!.startRunning()

2.5调用扫描方法 为了测试,设定在touchesBegan方法中调用扫描方法

代码语言:javascript
复制
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        startScan() 
    }

最后再友情提示,若是升级到iOS10.0以上,需要在plist文件中设置启动相机权限,否则会导致crash

3、处理二维码扫描结果

若觉得书读百遍不如实地演练,可以戳下面github地址吖: 二维码Demo传送门 若觉得文字读来太过枯燥无味,可以戳下面小姐姐视频讲解传送门吖: 视频讲解传送门

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.11.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、简介
    • 1、概念
      • 2、场景
        • 3、生成方式
          • 4、二维码读取
          • 二、二维码综合案例
            • 案例1、生成二维码
              • 案例2、自定义二维码
                • 案例3、识别二维码
                  • 案例4、扫描二维码
                  相关产品与服务
                  图片处理
                  图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档