Swift开发小技巧--扫描二维码,二维码的描边与锁定,设置扫描范围,二维码的生成(高清,无码,你懂得!)
二维码的扫描,二维码的锁定与描边,二维码的扫描范围,二维码的生成(高清,无码,你懂得!),识别相册中的二维码
扫描二维码用到的三个重要对象的关系,如图:
1.懒加载各种类
// 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 out = 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;
// 3.设置输出对象解析数据时感兴趣的范围
out.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)
return out
}()
/// 预览图层 -- 显示相机扫描到的影像
private lazy var previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session)
/// 专门用于保存描边的图层 -- 方便删除没用的描边
private lazy var containerLayer: CALayer = CALayer()
2.开始扫描二维码
private func scanQRCode()
{
// 1.判断输入能否添加到会话中
if !session.canAddInput(input)
{
return
}
// 2.判断输出能够添加到会话中
if !session.canAddOutput(output)
{
return
}
// 3.添加输入和输出到会话中
session.addInput(input)
session.addOutput(output)
// 4.设置输出能够解析的数据类型
// 注意点: 设置数据类型一定要在输出对象添加到会话之后才能设置,否则会报错
output.metadataObjectTypes = output.availableMetadataObjectTypes
// 5.设置监听(这里是self当前控制器监听),监听输出对象解析到的数据,遵守协议`AVCaptureMetadataOutputObjectsDelegate`
output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
// 6.添加预览图层,用来展现影像
view.layer.insertSublayer(previewLayer, atIndex: 0)
previewLayer.frame = view.bounds
// 7.添加容器图层,containerLayer -- 专门用来存储描边的图层
view.layer.addSublayer(containerLayer)
containerLayer.frame = view.bounds
// 8.开始扫描
session.startRunning()
}
3.AVCaptureMetadataOutputObjectsDelegate代理方法,监听到扫描到的数据就会调用的方法 -- func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!)
- 参数metadataObjects中有扫描到的数据
metadataObjects.last?.stringValue
4.做完上述三步,就可以读取到二维码中的数据了.这一步做的是二维码的描边与锁定
(作用: 当用户扫描范围内有N多二维码的时候,需要告诉用户当前扫中的是哪个)
- 需要用到的参数也在metadataObjects中,代码如下:
/// 只要扫描到结果就会调用
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!)
{
// 1.显示结果
customLabel.text = metadataObjects.last?.stringValue
clearLayers() // 扫描到结果就清除描边的图层,只保留一个描边
// 2.拿到扫描到的数据
guard let metadata = metadataObjects.last as? AVMetadataObject else
{
return
}
// 通过预览图层将corners值转换为我们能识别的类型
let objc = previewLayer.transformedMetadataObjectForMetadataObject(metadata)
// 2.对扫描到的二维码进行描边
drawLines(objc as! AVMetadataMachineReadableCodeObject)
}
/// 绘制描边
private func drawLines(objc: AVMetadataMachineReadableCodeObject)
{
// 0.安全校验
guard let array = objc.corners else
{
return
}
// 1.创建图层, 用于保存绘制的矩形
let layer = CAShapeLayer()
layer.lineWidth = 2
layer.strokeColor = UIColor.greenColor().CGColor
layer.fillColor = UIColor.clearColor().CGColor
// 2.创建UIBezierPath, 绘制矩形
let path = UIBezierPath()
var point = CGPointZero
var index = 0
CGPointMakeWithDictionaryRepresentation((array[index++] as! CFDictionary), &point)
// 2.1将起点移动到某一个点
path.moveToPoint(point)
// 2.2连接其它线段
while index < array.count
{
CGPointMakeWithDictionaryRepresentation((array[index++] as! CFDictionary), &point)
path.addLineToPoint(point)
}
// 2.3关闭路径
path.closePath()
layer.path = path.CGPath
// 3.将用于保存矩形的图层添加到界面上
containerLayer.addSublayer(layer)
}
/// 清空描边
private func clearLayers()
{
guard let subLayers = containerLayer.sublayers else
{
return
}
for layer in subLayers
{
layer.removeFromSuperlayer()
}
}
5.扫描范围,只有在指定区域内才能扫描出数据 -- 输出对象中可以设置扫描的范围,通过属性rectOfInterest
来设置,属性中的值为比例值
,而且是以横屏时
的左上角
为坐标原点
/// 输出对象 -- 可以设置扫描范围
private lazy var output: AVCaptureMetadataOutput = {
let out = 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;
// 3.设置输出对象解析数据时感兴趣的范围
out.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)
return out
}()
6.二维码的生成,普通情况下生成的二维码图片不够清晰,代码中提供了一个返回高清图片的方法
/// 二维码容器
@IBOutlet weak var customImageVivew: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// 1.创建滤镜
let filter = CIFilter(name: "CIQRCodeGenerator")
// 2.还原滤镜默认属性
filter?.setDefaults()
// 3.设置需要生成二维码的数据到滤镜中
// OC中要求设置的是一个二进制数据
filter?.setValue("关注Chaos_G的博客".dataUsingEncoding(NSUTF8StringEncoding), forKeyPath: "InputMessage")
// 4.从滤镜从取出生成好的二维码图片
guard let ciImage = filter?.outputImage else
{
return
}
// customImageVivew.image = UIImage(CIImage: ciImage)
customImageVivew.image = createNonInterpolatedUIImageFormCIImage(ciImage, size: 500)
}
/**
生成高清二维码
- 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)
}
Swift开发小技巧--扫描二维码,二维码的描边与锁定,设置扫描范围,二维码的生成(高清,无码,你懂得!)的更多相关文章
- Swift开发小技巧--识别选中照片中的二维码
识别选中照片中的二维码 点击相册按钮,打开用户相册 @IBAction func photoBtnClick(sender: AnyObject) { // 打开相册 // 1.判断是否能够打开相册 ...
- Swift开发小技巧--自定义转场动画
自定义转场动画 个人理解为重写了被弹出控制器的modal样式,根据自己的样式来显示modal出来的控制器 例:presentViewController(aVC, animated: true, co ...
- Swift开发小技巧--private访问修饰符报错的情况
1.Swift中的访问修饰符(三个,作用:用来修饰属性,方法和类) public : 最大权限 -- 可以在当前framework和其他framework中访问 internal : 默认的权限 -- ...
- Swift开发小技巧--TabBar中间按钮的添加方案
TabBar中间按钮的添加方案 之前做百思项目的时候,也有一个中间按钮,当时是重写的TabBar,这里介绍一个新的方法 给TabbarVC多添加添加一个控制器,这个控制器的作用仅仅是用来占位的,多了这 ...
- Swift开发小技巧--自定义Log
Swift中的自定义Log OC中有宏的定义,可以定义自己的Log,但是Swif中没有宏的定义,想要实现类似OC中的自定义Log,必须实现以下操作 1.在AppDelegate.swift文件中定义一 ...
- 如何在有input() 语句下断点调试(内附高清无码福利)
困扰了半天,一直没找到如何在含有输入语句的情况下用pycharm进行断点调试(调试的同时进行输入交互), But 经过尝试,还是找到了~~~ 通过debug可以快速的找到报错信息,以及观察程序每步的运 ...
- 我决定!墙裂推荐高清无码Python电子书(文中福利)
@ 目录 前言 视频网站学习的优点和缺点 Python基础 游戏 网站开发 前言 近几年学了Python,查阅了不少资料,如B站,慕课网,我要自学网等等,然后自己边看学书自己整理学习资料,想分享下如何 ...
- PHP开发小技巧②—实现二维数组根据key进行排序
在PHP中内置了很多对数组进行处理的函数,有很多时候我们直接使用其内置函数就能达到我们的需求,得到我们所想要的结果:但是,有的时候我们却不能通过使用内置函数实现我们的要求,这就需要我们自己去编写算法来 ...
- PHP开发小技巧③—实现多维数组转化为一维数组
在平常的项目开发中我们多会用到让多维数组转化为一维数组的情况,但是很多Programmer不会将其进行转化,也有些没有想到很好的算法然后经过乱起八糟的运算方式将其勉强转化好,但是所写的程序代码冗余非常 ...
随机推荐
- Use getopt() & getopt_long() to Parse Arguments
Today I came across a function [getopt] by accident. It is very useful to parse command-line argumen ...
- Effective Java 读书笔记
创建和销毁对象 >考虑用静态工厂方法替代构造器. 优点: ●优势在于有名称. ●不必再每次调用他们的时候都创建一个新的对象. ●可以返回原返回类型的任何子类型的对象. ●在创建参数化类型实例的时 ...
- POJ 3384 Feng Shui --直线切平面
题意:房间是一个凸多边形,要在里面铺设两条半径为r的圆形地毯,可以重叠,现在要求分别铺设到哪,使地毯所占的地面面积最大. 解法:要使圆形地毯所占面积最大,圆形地毯一定是与边相切的,这样才能使尽量不重叠 ...
- NOIP2015子串[序列DP]
题目背景 无 题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重 叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个 ...
- AC日记——字符替换 openjudge 1.7 08
08:字符替换 总时间限制: 1000ms 内存限制: 65536kB 描述 把一个字符串中特定的字符全部用给定的字符替换,得到一个新的字符串. 输入 只有一行,由一个字符串和两个字符组成,中间用 ...
- 隐写-CTF中图片隐藏文件分离方法总结
0x00 前言 在安全的大趋势下,信息安全越来越来受到国家和企业的重视,所以CTF比赛场次越来越多,而且比赛形式也不断的创新,题目也更加新颖有趣,对选手的综合信息安全能力有一个较好的考验,当然更好的是 ...
- Fastlane为iOS带来持续部署
Fastlane是一组工具套件,旨在实现iOS应用发布流程的自动化,并且提供一个运行良好的持续部署流程,只需要运行一个简单的命令就可以触发这个流程. Fastlane是一个ruby脚本集合,其中囊括了 ...
- COGS 2. 旅行计划
2. 旅行计划 ★☆ 输入文件:djs.in 输出文件:djs.out 简单对比时间限制:3 s 内存限制:128 MB 过暑假了,阿杜准备出行旅游,他已经查到了某些城市的两两之间的距 ...
- HBase简介
HBase简介 HBase – Hadoop Database,是一个高可靠性.高性能.面向列.可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群. HB ...
- Ros集成开发环境配置
参考资料: http://blog.csdn.net/yangziluomu/article/details/50848357 ROS使用IDE Eclipse http://blog.csdn.ne ...