Swift3.0实现二维码扫描与生成

作者: 薄阳映初雪 | 来源:发表于2017-06-22 17:43 被阅读600次

    自己的项目大多都是以OC写的,随着swift版本的更新和苹果的力推,学习swift成为刻不容缓的事情,今天我们就聊一下怎样实现一个二维码的扫描与生成,好了废话不多说,直接进入撸吗阶段

    1.二维码的扫描()

    1.1 导入AVFoundation框架

    import AVFoundation

    1.2设置扫描会话,输入,输出

    //MARK:内部控制方法

    private func scanQRcode()

    {

    //1.判断输入是否添加到会话中

    if !session.canAddInput(input)

    {

    return

    }

    //2.判断输出能够添加到会话中

    if !session.canAddOutput(outPut){

    return

    }

    //3.添加输入和输出到会话中

    session.addInput(input)

    session.addOutput(outPut)

    //4.设置输出能够与解析的数据类型

    //注意点:设置数据类型一定要在输出对象添加之后才能设置

    //availableMetadataObjectTypes解析所有类型的你也可以写自己相关类型的

    outPut.metadataObjectTypes = outPut.availableMetadataObjectTypes

    //5.设置监听,监听输出解析到数据()

    outPut.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)

    //6.添加预览图层

    view.layer.insertSublayer(previewLayer, at: 0)

    previewLayer.frame = view.bounds

    //7.开始扫描

    session.startRunning()

    }


    //MARK:懒加载

    //1.输入对象

    private lazy var input: AVCaptureDeviceInput = {

    let device =  AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)

    return try! AVCaptureDeviceInput(device: device)

    }()

    //2.会话

    private lazy var session: AVCaptureMetadataOutput =

    {

    let out = AVCaptureMetadataOutput()

    //设置输出对象解析数据是感兴趣的范围(二维码扫描范围)

    //默认值是CGRect(x: 0, y: 0, width: 1, height: 1) 传入是比例,是以横屏左上角作(x,y)相反和竖屏为参照的

    //获取屏幕的frame

    let viewRect = self.view.frame

    //获取扫描容器的frame

    let containRect = self.containView.frame

    let x =  containRect.origin.y / viewRect.height

    let y =  containRect.origin.x / viewRect.width

    let width = containRect.height / viewRect.height

    let height = containRect.width / viewRect.width

    out.rectOfInterest = CGRect(x: x, y: x, width: width, height: height)

    return out

    }()

    //3.输出对象

    private lazy var outPut:AVCaptureMetadataOutput = AVCaptureMetadataOutput()

    //4.专门用于保存二维码描边的图层

    lazy var containLayer: CALayer = CALayer()


    //MARK:AVCaptureMetadataOutputObjectsDelegate代理

    extension QRCodeViewController:AVCaptureMetadataOutputObjectsDelegate

    {

     //所有的内有都在metadataObjects

    //1.显示扫描到的结果

    let object = metadataObjects.last

    guard let contentStr: String = (object as AnyObject).stringValue else {

    return

    }

    //2.定位二维码()

    clearLayers()//每次有数据都要清空之前的描边

    //安全校验(拿到扫描数据)

    guard let metadata = metadataObjects.last as? AVMetadataObject else {

    return

    }

    //转换数据(二维码的点)

    //通过预览图层将Corners转换为我们能识别的点

    let objc =  previewLayer.transformedMetadataObject(for: metadata)

    //2.对扫描到二维码进行描边

    drawLines(objc:(objc as? AVMetadataMachineReadableCodeObject)! )

    }

    //绘制描边

    private func drawLines(objc:AVMetadataMachineReadableCodeObject)

    {

    clearLayers()

    //安全校验

    guard let array = objc.corners

    else {

    return

    }

    //1.创建图层

    let layer = CAShapeLayer()

    layer.lineWidth = 2

    layer.strokeColor = UIColor.red.cgColor

    layer.fillColor = UIColor.clear.cgColor

    //2.创建UIbesizerPath

    let path = UIBezierPath()

    var point = CGPoint.zero

    var index : Int = 0

    point =  CGPoint.init(dictionaryRepresentation: array[index] as! CFDictionary)!

    index += 1

    //2.1将起点移动到某一个点

    path.move(to: point)

    //2.2连接其他的片段

    while index < array.count {

    point =  CGPoint.init(dictionaryRepresentation: array[index] as! CFDictionary)!

    index += 1

    path.addLine(to: point)

    }

    //2.3关闭路径

    path.close()

    layer.path = path.cgPath

    //用于保存矩形的图层添加到界面上

    containLayer.addSublayer(layer)

    }

    //清空描边

    private func clearLayers()

    {

    guard let subLayers = containLayer.sublayers  else {

    return

    }

    for layer in subLayers {

    layer.removeFromSuperlayer()

    }

    }

    }


    2.识别相册中的二维码

    2.1建立相册,弹出相册

    func initPhoto(){

    //1.判断是否能够打开

    if !UIImagePickerController.isSourceTypeAvailable(.photoLibrary)

    {

    return

    }

    //2.创建相册控制器

    let imagePickVc = UIImagePickerController()

    imagePickVc.delegate = self

    //3.弹出相册控制器

    present(imagePickVc, animated: true, completion: nil)

    }


    2.实现相册的相关代理

    extension QRCodeViewController:UIImagePickerControllerDelegate,UINavigationControllerDelegate

    {

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])

    {

    //1.获取照片

    guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {

    return

    }

    guard let ciIamge = CIImage(image: image) else {

    return

    }

    //2.从相册中读取二维码

    //2.1创建一个探测器(CIDetector是CoreImage框架中提供的一个识别类,包括对人脸、形状、条码、文本的识别)。

    let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])

    //2.2利用探测器探测数据

    guard  let results =  detector?.features(in: ciIamge) else {

    return

    }

    //2.3取出探测器数据

    for result in results {

    NJLog(message: (result as! CIQRCodeFeature).messageString)

    }

    //3.如果实现代理方法系统不自动关闭相册

    picker.dismiss(animated: true, completion: nil)

    }

    }


    3.生成二维码

    fun creteScancode

    {

    //1.创建滤镜

    let filter =  CIFilter(name: "CIQRCodeGenerator")

    //2.还原滤镜默认属性

    filter?.setDefaults()

    //3设置需要生产二维码的数据到滤镜中

    filter?.setValue("黄泽".data(using: .utf8), forKey: "inputMessage")

    //4.从滤镜中取生产好的图片

    guard let ciImage = filter?.outputImage

    else {

    return

    }

    let QRCodeImage = createNonInterpolatedUIImageFormCIImage(image: ciImage, size: 300)

    let bgIcon = UIImage(named: "tabbar_compose_lbs")

    customImageVIew.image = creatImage(bgImage: QRCodeImage, iconImage: bgIcon!)

    }

    //MARK: - 根据CIImage生成指定大小的高清UIImage

    func createNonInterpolatedUIImageFormCIImage(image: CIImage, size: CGFloat) -> UIImage {

    //CIImage没有frame与bounds属性,只有extent属性

    let ciextent: CGRect = image.extent.integral

    let scale: CGFloat = min(size/ciextent.width, size/ciextent.height)

    let context = CIContext(options: nil)  //创建基于GPU的CIContext对象,性能和效果更好

    let bitmapImage: CGImage = context.createCGImage(image, from: ciextent)! //CIImage->CGImage

    let width = ciextent.width * scale

    let height = ciextent.height * scale

    let cs: CGColorSpace = CGColorSpaceCreateDeviceGray() //灰度颜色通道

    let info_UInt32 = CGImageAlphaInfo.none.rawValue

    let bitmapRef = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: info_UInt32)! //图形上下文,画布

    bitmapRef.interpolationQuality = CGInterpolationQuality.none //写入质量

    bitmapRef.scaleBy(x: scale, y: scale) //调整“画布”的缩放

    bitmapRef.draw(bitmapImage, in: ciextent)  //绘制图片

    let scaledImage: CGImage = bitmapRef.makeImage()! //保存

    return UIImage(cgImage: scaledImage)

    }

    //MARK: - 根据背景图片和头像合成头像二维码

    func creatImage(bgImage: UIImage, iconImage:UIImage) -> UIImage{

    //开启图片上下文

    UIGraphicsBeginImageContext(bgImage.size)

    //绘制背景图片

    bgImage.draw(in: CGRect(origin: CGPoint.zero, size: bgImage.size))

    //绘制头像

    let width: CGFloat = 50

    let height: CGFloat = width

    let x = (bgImage.size.width - width) * 0.5

    let y = (bgImage.size.height - height) * 0.5

    iconImage.draw(in: CGRect(x: x, y: y, width: width, height: height))

    //取出绘制好的图片

    let newImage = UIGraphicsGetImageFromCurrentImageContext()

    //关闭上下文

    UIGraphicsEndImageContext()

    //返回合成好的图片

    return newImage!

    }

    相关文章

      网友评论

      本文标题:Swift3.0实现二维码扫描与生成

      本文链接:https://www.haomeiwen.com/subject/praxcxtx.html