美文网首页
二维码扫描并实现简单聚焦

二维码扫描并实现简单聚焦

作者: alige | 来源:发表于2017-01-17 12:57 被阅读145次

    二维码/条形码工作框图:

       输入设备 <————> 会话 <————> 输出设备      
    

    设置扫描区域

    • 特别要注意的是输出设备的属性:rectOfInterest的坐标系是横屏坐标系,因此要进行转换

    1. 懒加载

        //1,输入设备
        private lazy var inputDevice:AVCaptureDeviceInput? = {
            let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
            return try! AVCaptureDeviceInput.init(device: device)
        }()
        //2,会话
        private lazy var session:AVCaptureSession? = {
             return AVCaptureSession.init()
        }()
        //3,输出设备,设置输出对象解析数据时聚焦的区域,默认值是全屏幕,也就是屏幕哪里扫到了二维码就聚焦哪, CGRect(x: 0, y: 0, width: 1, height: 1),现在要求只聚焦制定框内的二维码
        private lazy var outputDevice:AVCaptureMetadataOutput? = {
           let output = AVCaptureMetadataOutput()
            // 通过对这个值的观察, 我们发现传入的是比例
            // 注意: 参照是以横屏的左上角作为, 而不是以竖屏
            // 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;
            
             output.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)
            
            return output
        }()
        //4,预览扫描
        private lazy var previewLayer:AVCaptureVideoPreviewLayer = {
            return AVCaptureVideoPreviewLayer.init(session: self.session)
        }()
    
        //5,聚焦框
        private lazy var focusLayer:CALayer = {
            var va = CALayer.init()
            return va
        }()
    

    2.开始扫描

    //二维码扫描
        func QRScanning() -> Void {
            
            //1,确认session是否可以添加输入设备
            if !(session?.canAddInput(inputDevice))!{
                return
            }
            //2,确认session是否可以添加输出设备
            if !(session?.canAddOutput(outputDevice))! {
                return
            }
            //3,添加输入输出设备
            session?.addInput(inputDevice)
            session?.addOutput(outputDevice)
            
            //4,设置输出设备能够解析的数据
            outputDevice?.metadataObjectTypes = outputDevice?.availableMetadataObjectTypes
        
            //5,设置监听输出解析到的数据,调用代理方法
            outputDevice?.setMetadataObjectsDelegate(self, queue:dispatch_get_main_queue())
            
            //6,添加预览图层,使得预览曾扫描框在一个限定范围内
            previewLayer.frame = view.frame
            view.layer.insertSublayer(previewLayer, atIndex: 0)
            
            //7,添加自定义的聚焦框
            focusLayer.frame = view.bounds
            view.layer.addSublayer(focusLayer)
    
            //8,开始扫描
            session?.startRunning()
        }
    

    3.实现代理方法

    extension QRBarCodeViewController:AVCaptureMetadataOutputObjectsDelegate{
        func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!)
        {
            //metadataObjects元素类型是AVMetadataObject
            guard let metadata: AVMetadataObject? = metadataObjects.last as? AVMetadataObject else{
                return
            }
    
            //通过预览图层将数据,转换为能识别的数据类型
            let canReadData = previewLayer.transformedMetadataObjectForMetadataObject(metadata)
            
            // DyLog(metadata)  before:corners:{ 0.5,0.6 0.6,0.6 0.6,0.3 0.5,0.3 },
            //DyLog(canReadData as! AVMetadataMachineReadableCodeObject)
            //after convert:corners:{ 162.5,309.2 166.7,401.7 260.1,401.6 258.7,307.2 },
            
            //清除之前的图层
            clearLayer()
            guard let pointArrMetaData = canReadData as? AVMetadataMachineReadableCodeObject else{
                return
            }
            //画框
            drawLine(pointArrMetaData)
            
    
        }
        
        
        func drawLine(data:AVMetadataMachineReadableCodeObject!) -> Void {
            
    
            //校验数据,查看数据的数组中是否含有corners,没有直接返回,否则会数组越界
            guard let array = data!.corners else{
                return
            }
            
            //1,创建会话图层,画贝塞尔曲线的图层CAShapeLayer
            let drawLayer = CAShapeLayer.init()
            //设置边框宽度和颜色
            drawLayer.fillColor = UIColor.clearColor().CGColor
            drawLayer.strokeColor = UIColor.greenColor().CGColor
            drawLayer.lineWidth = 3
            
            //2,创建贝塞尔曲线
            let bezierPath = UIBezierPath.init()
            var index = 0;
            //将数组中的字典转为CGPoint
            var start = CGPointZero
            CGPointMakeWithDictionaryRepresentation((array[index] as! CFDictionary), &start)
            
            bezierPath.moveToPoint(start)
            
            //3,画框
            while index < array.count-1 {
                index += 1
                DyLog(index)
                CGPointMakeWithDictionaryRepresentation((array[index] as! CFDictionary),&start)
                bezierPath.addLineToPoint(start)
            }
            //4,关闭路径
            bezierPath.closePath()
            
            //5,将贝塞尔曲线添加到图层上
            drawLayer.path = bezierPath.CGPath
            
            //6,将图层添加到聚焦界面上
            focusLayer.addSublayer(drawLayer)
        }
        
        func clearLayer() -> Void {
            guard let sublayers = focusLayer.sublayers else{
                return
            }
            for layer in sublayers {
                layer.removeFromSuperlayer()
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:二维码扫描并实现简单聚焦

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