二维码系列(五)综合DEMO演练,工具类效能提升

来源:互联网 发布:邵阳学院教务网络系统 编辑:程序博客网 时间:2024/05/29 14:46

https://github.com/targetcloud/QRToolDemo

上面是Github地址,读者可以自己下载下来观摩(欢迎STAR)


本文是对整个二维码系列的综合,读者若没有时间细究功能实现,可直接用本DEMO代码调用示例使用即可

首先是QRTool工具类(有升级,更加稳固),拖到你的工程中去

////  QRTool.swift////  Created by targetcloud on 2016/12/4.//  Copyright © 2016年 targetcloud. All rights reserved.//  http://blog.csdn.net/callzjyimport UIKitimport AVFoundationtypealias ScanResultBlock = ([String]) -> ()class QRTool: NSObject {    static let shareInstance = QRTool()        private lazy var input: AVCaptureDeviceInput? = {        let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)        var input: AVCaptureDeviceInput?        do {            input = try AVCaptureDeviceInput(device: device)            return input        }catch {            return nil        }    }()    private lazy var output: AVCaptureMetadataOutput = {        let output = AVCaptureMetadataOutput()        output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)        return output    }()    lazy var session: AVCaptureSession = AVCaptureSession()    lazy var previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session)    fileprivate var scanResultBlock: ScanResultBlock?    fileprivate var isDrawFrame: Bool = false    fileprivate var drawLindWidth:CGFloat = 1    fileprivate var drawStrokeColor:UIColor = UIColor.red        func scanQRCode(_ inView: UIView, isDrawFrame: Bool = true,drawStrokeColor:UIColor = UIColor.red,drawLindWidth:CGFloat = 5, resultBlock: @escaping (_ resultStrs: [String])->()) {        scanResultBlock = resultBlock        self.isDrawFrame = isDrawFrame        self.drawStrokeColor = drawStrokeColor        self.drawLindWidth = drawLindWidth        if session.inputs.count==0 && session.outputs.count==0{            if session.canAddInput(input) && session.canAddOutput(output) {                session.addInput(input)                session.addOutput(output)            }else {                return            }        }        output.metadataObjectTypes = [AVMetadataObjectTypeQRCode]        if inView.layer.sublayers == nil {            previewLayer.frame = inView.layer.bounds            inView.layer.insertSublayer(previewLayer, at: 0)        }else {            let subLayers = inView.layer.sublayers!            if  !subLayers.contains(previewLayer) {                previewLayer.frame = inView.layer.bounds                inView.layer.insertSublayer(previewLayer, at: 0)            }        }        session.startRunning()    }        func setRectInterest(_ orignRect: CGRect) {        let bounds = UIScreen.main.bounds        let x: CGFloat = orignRect.origin.x / bounds.size.width        let y: CGFloat = orignRect.origin.y / bounds.size.height        let width: CGFloat = orignRect.size.width / bounds.size.width        let height: CGFloat = orignRect.size.height / bounds.size.height        output.rectOfInterest = CGRect(x: y, y: x, width: height, height: width)    }        class func detectorQRCodeImage(_ image: UIImage, isDrawQRCodeFrame: Bool = true,drawLineWidth:CGFloat = 5) -> (resultStrs: [String]?, resultImage: UIImage) {        let imageCI = CIImage(image: image)        let dector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])        let features = dector?.features(in: imageCI!)        var resultImage = image        var resultStrings = [String]()        for feature in features! {            let qrFeature = feature as! CIQRCodeFeature            resultStrings.append(qrFeature.messageString!)            if isDrawQRCodeFrame {                resultImage = drawFrame(resultImage, feature: qrFeature,drawLineWidth:drawLineWidth)            }        }        return (resultStrings, resultImage)    }        class func generatorQRCode(_ inputStr: String, centerImage: UIImage?,scaleXY: CGFloat = 20,drawSize:CGSize = CGSize(width: 80, height: 80)) -> UIImage {        let filter = CIFilter(name: "CIQRCodeGenerator")        filter?.setDefaults()        filter?.setValue(inputStr.data(using: String.Encoding.utf8), forKey: "inputMessage")        filter?.setValue("M", forKey: "inputCorrectionLevel")        var image = filter?.outputImage        let transform = CGAffineTransform(scaleX: scaleXY, y: scaleXY)        image = image?.applying(transform)        var resultImage = UIImage(ciImage: image!)        if centerImage != nil {            resultImage = mergeImage(resultImage, centerImage: centerImage!,centerImageSize:drawSize)        }        return resultImage    }}extension QRTool {    class fileprivate func drawFrame(_ image: UIImage, feature: CIQRCodeFeature,drawLineWidth:CGFloat) -> UIImage {        let size = image.size        UIGraphicsBeginImageContext(size)        image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))        let context = UIGraphicsGetCurrentContext()        context?.scaleBy(x: 1, y: -1)        context?.translateBy(x: 0, y: -size.height)        let bounds = feature.bounds        let path = UIBezierPath(rect: bounds)        UIColor.red.setStroke()        path.lineWidth = drawLineWidth        path.stroke()        let resultImage = UIGraphicsGetImageFromCurrentImageContext()        UIGraphicsEndImageContext()        return resultImage!    }        class fileprivate func mergeImage(_ sourceImage: UIImage, centerImage: UIImage,centerImageSize : CGSize = CGSize(width: 80, height: 80)) -> UIImage {        let size = sourceImage.size        UIGraphicsBeginImageContext(size)        sourceImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))        centerImage.draw(in: CGRect(x: (size.width - centerImageSize.width) * 0.5, y: (size.height - centerImageSize.height) * 0.5, width: centerImageSize.width, height: centerImageSize.height))        let resultImage = UIGraphicsGetImageFromCurrentImageContext()        UIGraphicsEndImageContext()        return resultImage!    }}extension QRTool:  AVCaptureMetadataOutputObjectsDelegate {    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {        if isDrawFrame {            removeFrameLayer()        }        var resultStrs = [String]()        for obj in metadataObjects {            if (obj as AnyObject).isKind(of: AVMetadataMachineReadableCodeObject.self){                let resultObj = previewLayer.transformedMetadataObject(for: obj as! AVMetadataObject)                let qrCodeObj = resultObj as! AVMetadataMachineReadableCodeObject                if !resultStrs.contains(qrCodeObj.stringValue){                    resultStrs.append(qrCodeObj.stringValue)                }                if isDrawFrame {                    drawFrame(qrCodeObj)                }            }        }        if scanResultBlock != nil {            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {                print("--now--")                self.removeFrameLayer()                self.scanResultBlock!(resultStrs)//代理转闭包            }        }    }        func drawFrame(_ qrCodeObj: AVMetadataMachineReadableCodeObject) {        guard let corners = qrCodeObj.corners else { return }        let shapLayer = CAShapeLayer()        shapLayer.fillColor = UIColor.clear.cgColor        shapLayer.strokeColor = drawStrokeColor.cgColor        shapLayer.fillColor = UIColor.clear.cgColor        shapLayer.lineWidth = drawLindWidth        let path = UIBezierPath()        var index = 0        for corner in corners {            let point = CGPoint(dictionaryRepresentation:corner as! CFDictionary)            if index == 0 {                path.move(to: point!)            }else {                path.addLine(to: point!)            }            index += 1        }        path.close()        shapLayer.path = path.cgPath        previewLayer.addSublayer(shapLayer)    }        func  removeFrameLayer() {        guard let subLayers = previewLayer.sublayers else {return}        for subLayer in subLayers {            if subLayer.isKind(of: CAShapeLayer.self){                subLayer.removeFromSuperlayer()            }        }    }}


在你的调用处用如下示例代码

////  ViewController.swift//  QRToolDemo////  Created by targetcloud on 2016/12/4.//  Copyright © 2016年 targetcloud. All rights reserved.//import UIKitclass ViewController: UIViewController {    @IBOutlet weak var QRCodeResultStrings: UITextField!    @IBOutlet weak var scanline: UIImageView!    @IBOutlet weak var scanBackView: UIView!    @IBOutlet weak var scanlineBottomConstraint: NSLayoutConstraint!    @IBOutlet weak var qrImg: UIImageView!        deinit{        print("demo deinit");    }        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {        QRCodeResultStrings.resignFirstResponder()    }        override func viewDidLoad() {        super.viewDidLoad()        scanBackView.backgroundColor = UIColor.clear        scanBackView.clipsToBounds = true                self.title="--QRTool Demo--";        let leftItem=UIBarButtonItem(barButtonSystemItem:.action,target:self,action:#selector(ViewController.ItemClick));        self.navigationItem.leftBarButtonItem=leftItem;    }    func ItemClick(){        self.navigationController?.popViewController(animated: true);    }        //生成二维码图片    @IBAction func generatorQRImage(_ sender: UIButton) {        view.endEditing(true)        let resultImage = QRTool.generatorQRCode(QRCodeResultStrings.text ?? "", centerImage: UIImage(named: "targetcloud.png"))        qrImg.image = resultImage    }        //add NSPhotoLibraryUsageDescription key in your info.plist    //从相册检测到二维码    @IBAction func detectFromImagePickerController(_ sender: UIButton) {        if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary){            return        }        let imagePickerVC = UIImagePickerController()        imagePickerVC.delegate = self        present(imagePickerVC, animated: true, completion: nil)    }        //add NSCameraUsageDescription key in your info.plist    //从相机扫描二维码    @IBAction func startScan(_ sender: UIButton) {        startScanAnimation()        QRTool.shareInstance.setRectInterest(scanBackView.frame)        QRTool.shareInstance.scanQRCode(view) { [weak self] (resultStrs) in//需要加[weak self]            guard let str = resultStrs.first else { return }            self?.QRCodeResultStrings.text = str            QRTool.shareInstance.session.stopRunning();            QRTool.shareInstance.previewLayer.removeFromSuperlayer();            self?.removeScanAnimation()            //前往扫描结果            self?.go(str)        }    }        fileprivate 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()        })    }        fileprivate func removeScanAnimation() {        scanline.layer.removeAllAnimations()    }        fileprivate func go(_ str : String){        var msg:String        var title:String        if str.characters.count==0 {            msg = "没有得到相关信息。。。"            title = "OK"        }else{            msg = str.description            title = "前往"        }        let alertVC = UIAlertController(title: "结果", message: msg, preferredStyle: UIAlertControllerStyle.alert)        let action = UIAlertAction(title: title, style: UIAlertActionStyle.default) { (action: UIAlertAction) in            if str.characters.count>0{                UIApplication.shared.open(URL(string: str)!, options: [:], completionHandler: nil)            }        }        alertVC.addAction(action)        present(alertVC, animated: true, completion: nil)    }}extension ViewController:UINavigationControllerDelegate, UIImagePickerControllerDelegate{    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {        guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else{            return        }        let result = QRTool.detectorQRCodeImage(image)        QRCodeResultStrings.text = result.resultStrs?.last ?? ""        picker.dismiss(animated: true, completion: nil)        //前往检测结果        go(QRCodeResultStrings.text!)    }}


效果图




0 0
原创粉丝点击