二维码系列(三)扫描二维码

1、搭界面(把-54这根约束拖为代码中的属性@IBOutletweakvar scanlineBottomConstraint:NSLayoutConstraint!

同时在info.plist加入NSCameraUsageDescription


2、代码

//
//  ViewController.swift
//  ScanQR
//
//  Created by targetcloud on 2016/12/3.
//  Copyright © 2016年 targetcloud. All rights reserved.
//

import UIKit
import AVFoundation

class ViewController: UIViewController {

    @IBOutlet weak var scanline: UIImageView!
    @IBOutlet weak var scanBackView: UIView!
    @IBOutlet weak var scanlineBottomConstraint: NSLayoutConstraint!
    
    var session: AVCaptureSession?
    weak var previewShapelayer: AVCaptureVideoPreviewLayer?
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        startScanAnimation()
        startScan()
    }
    
    //add NSCameraUsageDescription key in info.plist!
    override func viewDidLoad() {
        super.viewDidLoad()
        scanBackView.backgroundColor = UIColor.clear
        scanBackView.clipsToBounds = true
    }
    
    func startScan()  {
        let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        var input: AVCaptureDeviceInput?
        do {
            input = try AVCaptureDeviceInput(device: device)
        }catch {
            return
        }
        
        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        
        session = AVCaptureSession()
        if session!.canAddInput(input) && session!.canAddOutput(output) {
            session!.addInput(input)
            session!.addOutput(output)
        }else {
            return
        }
        
        output.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
        
        let bounds = UIScreen.main.bounds
        let x: CGFloat = scanBackView.frame.origin.x / bounds.size.width
        let y: CGFloat = scanBackView.frame.origin.y / bounds.size.height
        let width: CGFloat = scanBackView.frame.size.width / bounds.size.width
        let height: CGFloat = scanBackView.frame.size.height / bounds.size.height
        output.rectOfInterest = CGRect(x: y, y: x, width: height, height: width)
        
        let layer = AVCaptureVideoPreviewLayer(session: session)
        layer?.frame = view.layer.bounds
        view.layer.insertSublayer(layer!, at: 0)
        self.previewShapelayer = layer
        session!.startRunning()
    }
}

extension ViewController:  AVCaptureMetadataOutputObjectsDelegate {
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
        removeFrameLayer()
        print(metadataObjects)
        for obj in metadataObjects {
            if (obj as AnyObject).isKind(of: AVMetadataMachineReadableCodeObject.self){
                let resultObj = self.previewShapelayer?.transformedMetadataObject(for: obj as! AVMetadataObject)
                let qrCodeObj = resultObj as! AVMetadataMachineReadableCodeObject
                print(qrCodeObj.stringValue,qrCodeObj.corners)
                drawFrame(qrCodeObj)
            }
        }
    }
    
    func drawFrame(_ qrCodeObj: AVMetadataMachineReadableCodeObject) {
        let corners = qrCodeObj.corners
        let shapeLayer = CAShapeLayer()
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.lineWidth = 5
        let path = UIBezierPath()
        var index = 0
        for corner in corners! {
            let pointDic = corner as! CFDictionary
            let point = CGPoint(dictionaryRepresentation:pointDic)!
            if index == 0 {
                path.move(to: point)
            }else {
                path.addLine(to: point)
            }
            index += 1
        }
        path.close()
        shapeLayer.path = path.cgPath
        self.previewShapelayer?.addSublayer(shapeLayer)
    }
    
    func  removeFrameLayer() {
        guard let subLayers = self.previewShapelayer?.sublayers else {return}
        for subLayer in subLayers {
            if subLayer.isKind(of: CAShapeLayer.self){
                subLayer.removeFromSuperlayer()
            }
        }
    }
}

extension ViewController {
    func startScanAnimation() {
        scanlineBottomConstraint.constant = scanBackView.frame.size.height
        view.layoutIfNeeded()
        
        scanlineBottomConstraint.constant = -scanBackView.frame.size.height
        UIView.animate(withDuration: 1, animations: {
            UIView.setAnimationRepeatCount(MAXFLOAT)
            self.view.layoutIfNeeded()
        })
    }
    
    func removeScanAnimation() {
        scanline.layer.removeAllAnimations()
    }
}
/*
 print(metadataObjects)
 
 [<AVMetadataMachineReadableCodeObject: 0x16d81590, type="org.iso.QRCode", bounds={ 0.4,0.4 0.1x0.2 }>corners { 0.4,0.6 0.5,0.6 0.5,0.4 0.4,0.4 }, time 44181676151916, stringValue "http://weixin.qq.com/r/iEyyqvnEfaQCrb3J9xma"]

 print(qrCodeObj.stringValue,qrCodeObj.corners)
 
 https://github.com/targetcloud/DYZB [{
 X = "86.91517";
 Y = "186.571";
 }, {
 X = "88.79387";
 Y = "311.6888";
 }, {
 X = "212.8607";
 Y = "313.2776";
 }, {
 X = "215.6975";
 Y = "187.0925";
 }]
 
 */


3、运行效果(在限定的框内扫描到会画出红框)




使用工具类扫描二维码见二维码系列(4)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值