二维码的扫描,识别相册二维码以及制作

1⃣️二维码的扫描

扫描.png

🍓二维码的扫描模块,都会有个扫描的动画,首先我们将动画做出来,如何布局(创建了DimensionViewController和对应的storyboard),对于实现重复扫描动画很关键.首先我们在弹出扫描页面放入一个view,约束固定大小以及垂直和水平的约束;接下来是在view放入二维码扫描的边框图片qrcode_border,按住command键选中view和边框,设置他们上下左右的距离都为0;最后我们放上冲击波的图片wave,设置它与view的约束关系为左,上右的距离为0,同时设置他们等高.接下来我们需要把✨view的高度codeHeight,wave的top的约束codeScanTop, view的横向约束viewCenterY✨拖线成为对应的属性.

private func startAnimate() {
        //设置冲击波底部和视图底部对齐
        codeScanTop.constant = -codeHeight.constant
        view.layoutIfNeeded()
        UIView.animateWithDuration(2.0) {
          //设置动画重复无数次
            UIView.setAnimationRepeatCount(MAXFLOAT)
            self.codeScanTop.constant = self.codeHeight.constant
            self.view.layoutIfNeeded()
        }
    }

🍓识别扫描的二维码,代码某些部分相对固定,不需要死记硬背哦,需要的童鞋也可以改成OC代码使用嘞.

  //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 output = AVCaptureMetadataOutput()
        //默认值为CGRectMake(0, 0, 1, 1),这个是传入的比例,横屏的左上角作为原点
        output.rectOfInterest = CGRectMake((0.5-(110-self.viewCenterY.constant/2)/self.view.bounds.size.height),(0.5-110/self.view.bounds.size.width), 260/self.view.bounds.size.height, 260/self.view.bounds.size.width)
        return output
    }()
    //预览图层
    private lazy var previewLayer : AVCaptureVideoPreviewLayer = {
        return AVCaptureVideoPreviewLayer(session :self.session)
    }()
 //专门用于描边的图层
    private lazy var lineLayer : CALayer = CALayer()
 //MARK:内部控制方法,扫描二维码
    private func startCode(){
        //判断输入能否添加到对话
        if !session.canAddInput(input) {
            DMLog("输入没有添加")
            return
        }
        //判断输出能否添加到会话中
        if !session.canAddOutput(output) {
            DMLog("输出没有添加")
            return
        }
        //添加输入和输出会话中
        session.addInput(input)
        session.addOutput(output)
        //设置输出能够解析的数据类型
        //设置数据类型一定要在输出对象添加到会话之后才能设置
        output.metadataObjectTypes = output.availableMetadataObjectTypes
        //设置监听输出解析到的数据
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        //添加预览图预览图层
        view.layer.insertSublayer(previewLayer, atIndex: 0)
        previewLayer.frame = view.bounds
        //视图上加载的是二维码的描边
        view.layer.addSublayer(lineLayer)
        lineLayer.frame = view.bounds
        //开始扫描
        session.startRunning()
    }

接下来还需要执行相对应的代理方法,对扫描的消息进行相应的处理,还有扫描到二维码我们需要进行相应的描边,这样可以定位到扫描的二维码,即使当你手机是成角度扫描的时候,依旧可以扫描出形状(比如四边形),这里用贝塞尔曲线画图

extension DimensionViewController:AVCaptureMetadataOutputObjectsDelegate{
 func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!){
        //只要扫描到就会调用
        message.text = metadataObjects.last?.stringValue
        //DMLog(metadataObjects.last?.stringValue)
        //DMLog(metadataObjects.last)
        //corners { 0.4,0.9 0.5,0.9 0.5,0.6 0.4,0.7 },是二维码边线的四个点
        //转换后corners { 140.3,238.3 141.7,317.6 220.6,318.9 222.4,238.8 },
        cleanLayers()
        guard let meta = metadataObjects.last as? AVMetadataObject else{
            DMLog("没有扫描到二维码")
            return
        }
        let objc = previewLayer.transformedMetadataObjectForMetadataObject(meta)
        guard let newObj = objc as? AVMetadataMachineReadableCodeObject else{
            return
        }
        //DMLog(newObj)
        //对扫描二维码进行描边
        drawLine(newObj)
    }
    private func drawLine(objc : AVMetadataMachineReadableCodeObject){
        //安全校验
        guard let arr = objc.corners else{
            return
        }
        //创建图层,用于保存绘制的矩形
        let layer = CAShapeLayer()
        layer.lineWidth = 3
        layer.strokeColor = UIColor.orangeColor().CGColor
        layer.fillColor = UIColor.clearColor().CGColor //填充颜色
        //创建UIBezierPat,绘制矩形,
        //let path = UIBezierPath.init(rect: CGRect(x: 100,y: 100,width: 220,height: 220))
        //贝塞尔曲线:将点移动到某一点;连接其他点,关闭路径
        var point : CGPoint = CGPointZero
        var index = 0
        //把数组字典中的xy转化为CGPoint
CGPointMakeWithDictionaryRepresentation(arr[index++] as! CFDictionary, &point)
        let  path = UIBezierPath()
        path.moveToPoint(point)
        //连接
        while index < arr.count {   CGPointMakeWithDictionaryRepresentation(arr[index++] as! CFDictionary, &point)
            path.addLineToPoint(point)
        }
        path.closePath()
        layer.path = path.CGPath
        lineLayer.addSublayer(layer)
    }
    private func cleanLayers(){
        //清除扫描二维码出现多个图层
        guard let subLayers = lineLayer.sublayers else{
            return
        }
        for layer in subLayers {
            layer.removeFromSuperlayer()
        }
    }
}

🍓接下来就到了识别相册中的二维码了,请看以下代码

//从相册中识别二维码
        if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
            return
        }
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        presentViewController(imagePicker, animated: true, completion: nil)

extension DimensionViewController : UIImagePickerControllerDelegate,UINavigationControllerDelegate{
    //实现该代理方法,选中一张图片时系统不会自动关闭
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
        guard let image = info["UIImagePickerControllerOriginalImage"] as? UIImage else{
            return
        }
        let cimage = CIImage(image:image)
        //创建一个探测器
        let detector = CIDetector(ofType: CIDetectorTypeQRCode,context: nil,options: [CIDetectorAccuracy : CIDetectorAccuracyHigh]) //最后一个参数是扫描的精确度
        let result = detector.featuresInImage(cimage!)
        //去除探测的数据
        for result in result{
            let codeInfo = (result as! CIQRCodeFeature).messageString
//这里的message是一个table,显示扫描到的信息的
            message.text = codeInfo
        }
        picker.dismissViewControllerAnimated(true, completion: nil)
    }
}

🍓制作二维码哦,可以填入自己预设的消息,比如"小敏萌萌哒"😄,这些代码都是非常固定,需要的时候复制粘贴下就可以了哦.

class CreatQrCodeViewController: UIViewController {

    @IBOutlet weak var qrCodeImage: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
        //创建滤镜
        let filter = CIFilter(name: "CIQRCodeGenerator")
        //还原默认属性
        filter?.setDefaults()
        //设置需要生成二维码的数据到滤镜中
        filter?.setValue("小敏萌萌哒".dataUsingEncoding(NSUTF8StringEncoding), forKeyPath: "InputMessage")
        //从滤镜中取出生成好的二维码
        guard let ciImage = filter?.outputImage else{
            DMLog("没有二维码")
            return
        }
        qrCodeImage.image =  createNonInterpolatedUIImageFormCIImage(ciImage, size: 220)
    }
    /**
     生成高清二维码
     
     - parameter image: 需要生成原始图片
     - parameter size:  生成的二维码的宽高
     */
    private func createNonInterpolatedUIImageFormCIImage(image: CIImage, size: CGFloat) -> UIImage {
        let extent: CGRect = CGRectIntegral(image.extent)
        let scale: CGFloat = min(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent))
        // 1.创建bitmap;
        let width = CGRectGetWidth(extent) * scale
        let height = CGRectGetHeight(extent) * scale
        let cs: CGColorSpaceRef = CGColorSpaceCreateDeviceGray()!
        let bitmapRef = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, cs, 0)!
        let context = CIContext(options: nil)
        let bitmapImage: CGImageRef = context.createCGImage(image, fromRect: extent)
        CGContextSetInterpolationQuality(bitmapRef,  CGInterpolationQuality.None)
        CGContextScaleCTM(bitmapRef, scale, scale);
        CGContextDrawImage(bitmapRef, extent, bitmapImage);
        // 2.保存bitmap到图片
        let scaledImage: CGImageRef = CGBitmapContextCreateImage(bitmapRef)!
        return UIImage(CGImage: scaledImage)
    }
}

以上😄

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,359评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,010评论 4 62
  • 绡帷冷,珠帘静,舒尔轻唤无人应。妆奁乱,人慵倦,无心懵懂,惹了卿怨。念。念。念。 紫毫重,青萝病,夜来欺我当炉梦。...
    宋怀众阅读 456评论 5 3
  • 所有的成功都不可能是一帆风顺的,哪怕是你认为绝对能成功的事情,其中的经历也需要绝大努力还有坚持,以及百分之百的信念。
    尚善若水007阅读 200评论 0 0
  • 最近马苏又因拍摄《男人装》封面火了,那性感的小蛮腰和翘臀着实惹火。 马苏生于1981年,已经37岁,但是看起来却像...
    抠抠网阅读 860评论 0 0