Swift(十二):QRScanner 二维码封装总结

封装类 SQRCode.swift

//
//  SQRCode.swift 封装集成类
//  QRCode
//
//  Created by HMC on 16/8/16.
//  Copyright © 2016年 SKing. All rights reserved.
//

import UIKit
import AVFoundation

//闭包的别名
typealias result = (String)->()

class SQRCode: NSObject {
    
    //懒加载 闭包
    lazy var input : AVCaptureInput? = {
        
        //获取摄像头
        let hardWareDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
        
        //输入
        guard let input = try? AVCaptureDeviceInput(device: hardWareDevice) else{
            return nil
        }
        return input
        
    }()
    
    lazy var output : AVCaptureMetadataOutput? = {
        //输出
        let output = AVCaptureMetadataOutput()
        //设置输出的代理
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        
        return output
    }()
    
    lazy var captureLayer : AVCaptureVideoPreviewLayer = {
        
        let captureLayer = AVCaptureVideoPreviewLayer(session: self.session)
        return captureLayer
        
    }()
    
    lazy var session : AVCaptureSession = {
        
        let session = AVCaptureSession()
        return session
    }()
    //结果闭包
    private var resultClosures : result?
    
    //单例
    static let sharedObject = SQRCode()
    
    /**
     实例方法:扫描二维码
     
     - parameter view:   在哪个 VC 的 View
     - parameter result: 闭包输出结果 便于回传到对应的 VC 上
     */
    func scanQRCode(view:UIView , result:(String)->()) {
        
        //
        resultClosures = result
        //连接输入输出
        
        if session.canAddInput(input) && session.canAddOutput(output) {
            session.addInput(input)
            session.addOutput(output)
        }
        
        //输出的二维码识别的码制(所有的码)
        output!.metadataObjectTypes = output!.availableMetadataObjectTypes
        
        
        //设置扫描的区域 0.0-1.0
        //        let screenBounds = UIScreen.mainScreen().bounds
        //        let x :CGFloat = scanBackground.frame.origin.x / screenBounds.size.width
        //        let y :CGFloat = scanBackground.frame.origin.y / screenBounds.size.height
        //        let width :CGFloat = scanBackground.frame.size.width / screenBounds.size.width
        //        let height :CGFloat = scanBackground.frame.size.height / screenBounds.size.height
        //        output.rectOfInterest = CGRectMake(y, x, height, width)
        
        //添加摄像头图层 (其实不是必须的) 防止重复
        let sublayers = view.layer.sublayers!
        guard !sublayers.contains(captureLayer)  else {
            
            return
        }
        
        captureLayer.frame = view.layer.bounds
        view.layer.insertSublayer(captureLayer, atIndex: 0)
        
        // 启动回话: 此时开始采集数据,输出对象
        session.startRunning()
        
        
    }
    
    
    
    /**
     类方法:生成二维码
     
     - parameter string:        字符串
     - parameter iconImageName: 中心的 Icon
     
     - returns: 生成的二维码
     */
    class func createQR(string : String?,iconImageName: String?) -> UIImage? {
        
        //创建二维码滤镜 固定格式 参数必须为 : CIQRCodeGenerator
        let filter = CIFilter(name: "CIQRCodeGenerator")
        
        //复位滤镜,以便下次使用
        filter?.setDefaults()
        
        //KVC 设置输入值  ps:key 固定为inputMessage ,value 必须为 nsdata 类型
        guard string != nil else {
            return nil
        }
        let inputData = string!.dataUsingEncoding(NSUTF8StringEncoding)
        filter?.setValue(inputData, forKey: "inputMessage")
        
        //设置纠错率 一般设置为M
        filter?.setValue("M", forKey: "inputCorrectionLevel")
        
        //接收滤镜返回的图片,由于太小 需要拉伸放大
        guard let image = filter?.outputImage else {
            
            return nil
        }
        //颜色滤镜
        let colorFilter = CIFilter(name: "CIFalseColor")
        colorFilter?.setDefaults()
        colorFilter?.setValue(image, forKey: "inputImage")
        //前景色
        colorFilter?.setValue(CIColor(red: 225/255.0, green: 77/255.0,blue: 0), forKey: "inputColor0")
        //背景色
        colorFilter?.setValue(CIColor(red: 1, green: 1,blue: 1), forKey: "inputColor1")
        
        guard let colorImage = colorFilter?.outputImage else{
            return nil
        }
        //放大25倍 重绘
        let matrix = CGAffineTransformMakeScale(25, 25)
        //将 CIImage 转换为 UIImage
        let QRImage = UIImage(CIImage:colorImage.imageByApplyingTransform(matrix))
        
        //判定 icon 是否为空
        guard iconImageName != nil else {
            
            return nil
        }
        
        //重新绘制中心小图
        if let iconImage = UIImage(named: iconImageName!)  {
            
            let rect = CGRectMake(0, 0, QRImage.size.width, QRImage.size.height)
            UIGraphicsBeginImageContext(rect.size)
            QRImage.drawInRect(rect)
            
            
            let iconSize = CGSizeMake(rect.size.width * 0.25, rect.size.height * 0.25)
            let x = (rect.width - iconSize.width ) * 0.5
            let y = (rect.height - iconSize.height ) * 0.5
            
            iconImage.drawInRect(CGRectMake(x,y,iconSize.width,iconSize.height))
            let resultImage = UIGraphicsGetImageFromCurrentImageContext()
            
            UIGraphicsEndImageContext()
            
            return resultImage
        }
        
        
        return QRImage
    }
    
    
    /**
     类方法:识别二维码
     
     - parameter image: 被识别的图片
     
     - returns: 返回识别的结果
     */
    class func detectorQRFromImage(image:UIImage) -> (String?) {
        //转换为 CIImage
        let ciImage = CIImage(image: image)
        
        //创建探测器
        let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy : CIDetectorAccuracyHigh])
        
        //返回结果
        let features = detector.featuresInImage(ciImage!)
        //遍历结果
        for feature in features {
            let qrcode = feature as! CIQRCodeFeature
            
            //print(qrcode.messageString)
            return qrcode.messageString
            
        }
        return nil
        
    }

}


// MARK: - AVCaptureMetadataOutputObjectsDelegate
extension SQRCode : AVCaptureMetadataOutputObjectsDelegate {
    
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        
        guard metadataObjects.count > 0 else{
            
            return
        }
        var resultStr : String?
        
        for obj in metadataObjects {
            guard obj.isKindOfClass(AVMetadataMachineReadableCodeObject) else{
                
                return
            }
            
            let tmpObj = obj as! AVMetadataMachineReadableCodeObject
            
            print(tmpObj.stringValue)
            //print(tmpObj.corners)
            resultStr = tmpObj.stringValue
            
        }
        
        guard (resultClosures != nil) else{
            
            return
        }
        guard resultStr != nil else{
            
            return
        }
        resultClosures!(resultStr!)
    }
}

调用的例子:

例一

//
//  scanQRViewController.swift
//  QRCode
//
//  Created by HMC on 16/8/15.
//  Copyright © 2016年 SKing. All rights reserved.
//

import UIKit
import AVFoundation

class scanQRViewController: UIViewController {
    
    //lazy var session = AVCaptureSession()
    
    /// 扫描网格 距离 框的底部的长度
    @IBOutlet weak var lineToBottom: NSLayoutConstraint!
    /// 扫描框和扫描线的背景 View
    @IBOutlet weak var scanBackground: UIView!
    //扫描框
    @IBOutlet weak var scanDeadLine: UIImageView!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        //        startScan()
        
        SQRCode.sharedObject.scanQRCode(view) { (result:String) in
            
            let alert = UIAlertController(title: "识别结果", message: result, preferredStyle: .Alert)
            let action = UIAlertAction(title: "好", style: .Default, handler: { (action: UIAlertAction) in
                self.dismissViewControllerAnimated(true, completion: nil)
            })
            alert.addAction(action)
            
            self.presentViewController(alert, animated: true, completion: nil)
            
        }
    }
    override func viewDidAppear(animated: Bool) {
        
        super.viewDidAppear(animated)
        
        startAnimationOfLine()
        
    }
    
}


// MARK: - 有关的 UI 和动画
extension scanQRViewController{
    /**
     动画的设置
     */
    func startAnimationOfLine() {
        
        //初始化线的位置
        lineToBottom.constant = scanBackground.frame.height
        loadViewIfNeeded()
        
        //设置结束位置
        lineToBottom.constant = -scanBackground.frame.height
        
        //设置动画
        UIView.animateWithDuration(3, animations: {
            //设置重复
            UIView.setAnimationRepeatCount(MAXFLOAT)
            self.view.layoutIfNeeded()
            
        }) { (bool : Bool) in
            
            print("回扫")
            
            
        }
        
    }
    
    
}

例二

//
//  showQRController.swift
//  QRCode
//
//  Created by HMC on 16/8/11.
//  Copyright © 2016年 SKing. All rights reserved.
//

import UIKit
import CoreImage

class showQRController: UIViewController {
    
    @IBOutlet weak var QRImageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        QRImageView.image = SQRCode.createQR("香雨如酥贵如珠,万家未觉身却无。 一心只为他人事,浓绿艳妆为谁梳?", iconImageName: "123")

        
    }
}

例三

//
//  detectorViewController.swift
//  QRCode
//
//  Created by HMC on 16/8/12.
//  Copyright © 2016年 SKing. All rights reserved.
//

import UIKit

class detectorViewController: UIViewController {
    
    
    @IBOutlet weak var imageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 获得 image
        guard let image = imageView.image else{
            
            return
        }
        
        let returnStr = SQRCode.detectorQRFromImage(image)
        
        //alert 显示识别出的内容
        let alert = UIAlertController(title: "识别内容", message:returnStr, preferredStyle: .Alert)
        let action = UIAlertAction(title: "关闭", style: .Default, handler: { (action : UIAlertAction) in
            self.dismissViewControllerAnimated(true, completion: nil)
        })
        
        alert.addAction(action)
        presentViewController(alert, animated: true, completion: nil)
        
        
        
        
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容