美文网首页
摄像头抓捕二维码

摄像头抓捕二维码

作者: 沁晓Chr | 来源:发表于2015-12-22 18:01 被阅读140次

摄像头抓捕二维码

AVCaptureDeviceInput,AVCaptureSession,AVCaptureMetadataOutput,AVCaptureVideoPreviewLayer

AVMetadataMachineReadableCodeObject,AVMetadataObject

相关类

    /// 输入对象
    private lazy var input: AVCaptureDeviceInput? = {
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
        return try? AVCaptureDeviceInput(device: device)
    }()
    
    /// 会话
    private lazy var session: AVCaptureSession = AVCaptureSession()
    
    /// 输出对象
    private lazy var output: AVCaptureMetadataOutput = {
       let out = AVCaptureMetadataOutput()
        // 设置输出对象解析数据时感兴趣的范围
        // 默认值是 CGRect(x: 0, y: 0, width: 1, height: 1)全屏比例算
        // 通过对这个值的观察, 我们发现传入的是比例
        // 注意: 参照是以横屏(竖屏逆时针90度,Landscape Left)的左上角作为, 而不是以竖屏
//        out.rectOfInterest = CGRect(x: 0, y: 0, width: 0.5, height: 0.5)
        
        // 1.获取屏幕的frame
        let viewRect = self.view.frame
        // 2.获取扫描容器的frame
        let containerRect = self.customContainerView.frame
        let x = containerRect.origin.y / viewRect.height;
        let y = containerRect.origin.x / viewRect.width;
        let width = containerRect.height / viewRect.height;
        let height = containerRect.width / viewRect.width;
        
         out.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)
        
        return out
    }()
    
    /// 预览图层
    private lazy var previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session)
    
    /// 专门用于保存描边的图层
    private lazy var containerLayer: CALayer = CALayer()
}

        // 1.判断输入能否添加到会话中
       
        // 2.判断输出能够添加到会话中
        
        // 3.添加输入和输出到会话中
        
        // 4.设置输出能够解析的数据类型
        
        // 注意点: 设置数据类型一定要在输出对象添加到会话之后才能设置
        
        // 5.设置监听监听输出解析到的数据
       
        // 6.添加预览图层
        
        // 7.添加容器图层,专门用于保存描边的图层
        
        // 8.开始扫描
//  QRCodeViewController.swift

import UIKit
import AVFoundation

class QRCodeViewController: UIViewController {
    
    /// 扫描容器
    @IBOutlet weak var customContainerView: UIView!
    /// 底部工具条
    @IBOutlet weak var customTabbar: UITabBar!
    /// 结果文本
    @IBOutlet weak var customLabel: UILabel!
   /// 容器视图高度约束
    @IBOutlet weak var containerHeightCons: NSLayoutConstraint!

    
    override func viewDidLoad() {
        super.viewDidLoad()

        // 1.设置默认选中
        customTabbar.selectedItem = customTabbar.items?.first
        
        // 2.添加监听, 监听底部工具条点击
        customTabbar.delegate = self
        
        // 3.开始扫描二维码
        scanQRCode()
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        
        startAnimation()
    }
    
    // MARK: - 内部控制方法
    private func scanQRCode()
    {
        // 1.判断输入能否添加到会话中
        if !session.canAddInput(input)
        {
            return
        }
        // 2.判断输出能够添加到会话中
        if !session.canAddOutput(output)
        {
            return
        }
        // 3.添加输入和输出到会话中
        session.addInput(input)
        session.addOutput(output)
        
        // 4.设置输出能够解析的数据类型
        // 注意点: 设置数据类型一定要在输出对象添加到会话之后才能设置
        output.metadataObjectTypes = output.availableMetadataObjectTypes
        
        // 5.设置监听监听输出解析到的数据
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        
        // 6.添加预览图层
        view.layer.insertSublayer(previewLayer, atIndex: 0)
        previewLayer.frame = view.bounds
        
        // 7.添加容器图层,专门用于保存描边的图层
        view.layer.addSublayer(containerLayer)
        containerLayer.frame = view.bounds
        
        // 8.开始扫描
        session.startRunning()
        
    }
    

    }
    
    @IBAction func photoBtnClick(sender: AnyObject) {
    }
    @IBAction func closeBtnClick(sender: AnyObject) {
        dismissViewControllerAnimated(true, completion: nil)
    }
    
    // MARK: - 懒加载
    /// 输入对象
    private lazy var input: AVCaptureDeviceInput? = {
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
        return try? AVCaptureDeviceInput(device: device)
    }()
    
    /// 会话
    private lazy var session: AVCaptureSession = AVCaptureSession()
    
    /// 输出对象
    private lazy var output: AVCaptureMetadataOutput = {
       let out = AVCaptureMetadataOutput()
        // 设置输出对象解析数据时感兴趣的范围
        // 默认值是 CGRect(x: 0, y: 0, width: 1, height: 1)全屏比例算
        // 通过对这个值的观察, 我们发现传入的是比例
        // 注意: 参照是以横屏(竖屏逆时针90度,Landscape Left)的左上角作为, 而不是以竖屏
//        out.rectOfInterest = CGRect(x: 0, y: 0, width: 0.5, height: 0.5)
        
        // 1.获取屏幕的frame
        let viewRect = self.view.frame
        // 2.获取扫描容器的frame
        let containerRect = self.customContainerView.frame
        let x = containerRect.origin.y / viewRect.height;
        let y = containerRect.origin.x / viewRect.width;
        let width = containerRect.height / viewRect.height;
        let height = containerRect.width / viewRect.width;
        
         out.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)
        
        return out
    }()
    
    /// 预览图层
    private lazy var previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session)
    
    /// 专门用于保存描边的图层
    private lazy var containerLayer: CALayer = CALayer()
}

extension QRCodeViewController: AVCaptureMetadataOutputObjectsDelegate
{
    /// 只要扫描到结果就会调用
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!)
    {
        // 1.显示结果
        customLabel.text =  metadataObjects.last?.stringValue
        
        clearLayers()
        
        // 2.拿到扫描到的数据
        guard let metadata = metadataObjects.last as? AVMetadataObject else
        {
            return
        }
        // 通过预览图层将corners值转换为我们能识别的类型
        let objc = previewLayer.transformedMetadataObjectForMetadataObject(metadata)
        // 2.对扫描到的二维码进行描边
        drawLines(objc as! AVMetadataMachineReadableCodeObject)
    }
    
    /// 绘制描边
    private func drawLines(objc: AVMetadataMachineReadableCodeObject)
    {
        
        // 0.安全校验
        guard let array = objc.corners else
        {
            return
        }
        
        // 1.创建图层, 用于保存绘制的矩形
        let layer = CAShapeLayer()
        layer.lineWidth = 2
        layer.strokeColor = UIColor.greenColor().CGColor
        layer.fillColor = UIColor.clearColor().CGColor
        
        // 2.创建UIBezierPath, 绘制矩形
        let path = UIBezierPath()
        var point = CGPointZero
        var index = 0
        CGPointMakeWithDictionaryRepresentation((array[index++] as! CFDictionary), &point)
        
        // 2.1将起点移动到某一个点
        path.moveToPoint(point)
        
        // 2.2连接其它线段
        while index < array.count
        {
            CGPointMakeWithDictionaryRepresentation((array[index++] as! CFDictionary), &point)
            path.addLineToPoint(point)
        }
        // 2.3关闭路径
        path.closePath()
        
        layer.path = path.CGPath
        // 3.将用于保存矩形的图层添加到界面上
        containerLayer.addSublayer(layer)
    }
    
    /// 清空描边
    private func clearLayers()
    {
        guard let subLayers = containerLayer.sublayers else
        {
            return
        }
        for layer in subLayers
        {
            layer.removeFromSuperlayer()
        }
    }
}

extension QRCodeViewController: UITabBarDelegate
{
    func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
      //约束改变导致动画有bug所以先移除动画,重新开始就行了
        // 根据当前选中的按钮重新设置二维码容器高度
        containerHeightCons.constant = (item.tag == 1) ? 150 : 300
        view.layoutIfNeeded()
        
        // 移除动画
        scanLineView.layer.removeAllAnimations()
        
        // 重新开启动画
        startAnimation()
    }
}

其他知识点

 1.从数组中取出字典传为CGPoint
 var point = CGPointZero
 CGPointMakeWithDictionaryRepresentation((array[index++] as! CFDictionary), &point)
 2.约束改变导致动画有bug所以先移除动画,重新开始就行了
 3. 创建图层, 用于保存绘制的矩形
    let layer = CAShapeLayer()
 4.    /// 预览图层
    private lazy var previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session)  

相关文章

  • 摄像头抓捕二维码

    摄像头抓捕二维码 AVCaptureDeviceInput,AVCaptureSession,AVCaptureM...

  • macOS swiftUI之二维码扫描(AVFoundation

    需求:用macOS的摄像头作为二维码扫描器扫描二维码获取信息基本流程:1、创建session(捕捉会话) let ...

  • 二维码扫码采集与相册二维码提取 - iOS

    二维码扫码和相册二维码提取的方法在原生系统 AVFoundation 的 SDK 中提供了摄像头设备扫描捕获和检测...

  • ios 二维码扫描的步骤

    二维码扫描的步骤: 1、创建设备会话对象,用来设置设备数据输入 2、获取摄像头,并且将摄像头对象加入当前会话中 3...

  • iOS 11 碎碎念

    相机支持扫描二维码 你的摄像头可自动侦测到镜头画面中的二维码。扫描之后,可立即打开相关网站或 app。你甚至还可以...

  • iOS QRcode识别及相册图片 和 Zbar的使用

    近期使用系统原生二维码扫描 摄像头扫码没问题,但是出现了在相册中的存在部分二维码识别不出来的情况。。查阅资料了解到...

  • 抓捕

    江城每年的夏天都是炎热的,吸入的每一口空气都能把肺点燃。偶尔下一场雨,即使是凉凉的雨水,穿过燥热的空气后也变得温吞...

  • 抓捕

    蛮子实在是憋不住了,外面风声紧着,他就把婆娘送到一个同乡家的渔船上安顿了下来,他带着三个孩子在几里外的玉米地里蹲了...

  • 抓捕

    01村民雨天玩纸牌 二十年前的初夏。早晨,天阴沉沉的。树梢纹丝不动,尽管没有太阳,却闷热难耐…… 吃完早饭,天湖派...

  • 抓捕

    我又一次把目光投向车窗外,白茫茫一望无垠的雪,尽管是阴天,还是很刺眼。雪是三天前下的,好像是没有化一点,有一尺来厚...

网友评论

      本文标题:摄像头抓捕二维码

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