第三天--二维码的扫描和生成高清二维码
前言
前两天我搭建了项目的大体架构,今天主要实现的的首页的二维码扫描和二维的生成。废话不多说,直奔主题。
1、二维码扫描
首先来张效果图
文章图片
8F7FD7B6-A03F-4594-8732-4F8DA709E1A3.png
界面的搭建我就不废话了,我用storybord搭建,因为懒的去写代码。我主要讲下实现二维码扫描的过程
1.1、扫描线的动画,通过不断改变扫描线于容器视图的约束,来实现的。
@IBOutlet weak var scannerLineConstraint: NSLayoutConstraint! // 扫描线的顶部约束
定义一个定时刷新界面的定时器
var timer:CADisplayLink? // 定义一个定时器// 设置冲击波的动画
private func startAnimation (){scannerLineConstraint.constant = -contentViewHeighCons.constant
sannerLineImageView.layoutIfNeeded()timer = CADisplayLink(target: self ,selector: "updateScanline")
let runloop = NSRunLoop.currentRunLoop()timer?.addToRunLoop(runloop, forMode: NSRunLoopCommonModes)
timer?.frameInterval = 3
}// 改变约束的方法
func updateScanline() {scannerLineConstraint.constant += 10;
if scannerLineConstraint.constant == 0 {self.scannerLineConstraint.constant = -contentViewHeighCons.constant}
}
1.2二维码扫描实现,AVFoundation 首先导入AVFoundation
思路:定义一个捕捉会话,然后往会话中添加输入对象(摄像头),添加输出对象,获取扫描结果。
实现:
// 会话
private lazy var captureSession:AVCaptureSession = AVCaptureSession()// 获取输入设备
private lazy var deviceInput:AVCaptureDeviceInput? = {//获取摄像头
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)do {let deviceInput = try AVCaptureDeviceInput(device: device)
return deviceInput}catch {print(error)return nil}}()//创建输出对象
private lazy var output:AVCaptureMetadataOutput = AVCaptureMetadataOutput()// 创建预览图层
private lazy var previewLayer: AVCaptureVideoPreviewLayer = {
let layer = AVCaptureVideoPreviewLayer(session: self.captureSession)
layer.frame = UIScreen.mainScreen().bounds
return layer
}()// 创建聚焦的图层
private lazy var focusLayer:CALayer = {let layer = CALayer()
layer.frame = UIScreen.mainScreen().bounds
return layer}()
创建好了上面的对象后,首先要判断输入对象和输出对象能否加入到会话中,如果能的才开始扫描。实现代码如下:
//MARK: 开启扫描
private func startScaning() {// 如果输入和输出不能添加到会话直接返回
if !captureSession.canAddInput(deviceInput) {
return
}if !captureSession.canAddOutput(output) {return
}//分别加输入和输出添加到会话层
captureSession.addInput(deviceInput)
captureSession.addOutput(output)// 设置输出对象的能够解析的类型
output.metadataObjectTypes = output.availableMetadataObjectTypes//设置输出代理
output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())// 添加预览图层
view.layer.insertSublayer(previewLayer, atIndex: 0)// 开始扫描
captureSession.startRunning()}
最后就是扫描成功后,数据在输出代理中处理,还有聚焦的实现也是在其中实现。
extension YJQCRScannerViewController:AVCaptureMetadataOutputObjectsDelegate {internal func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {print(metadataObjects)// 1、获取到扫描的数据
let dataString = metadataObjects.last?.stringValue// 2.获取扫描到的二维码的位置
// 2.1转换坐标
for object in metadataObjects
{
// 2.1.1判断当前获取到的数据, 是否是机器可识别的类型
if object is AVMetadataMachineReadableCodeObject
{
// 2.1.2将坐标转换界面可识别的坐标
let codeObject = previewLayer.transformedMetadataObjectForMetadataObject(object as! AVMetadataObject) as! AVMetadataMachineReadableCodeObject
// 2.1.3绘制图形
drawCorners(codeObject)
}
}}/**
绘制图形
:param: codeObject 保存了坐标的对象
*/
private func drawCorners(codeObject: AVMetadataMachineReadableCodeObject)
{
if codeObject.corners.isEmpty
{
return
}// 1.创建一个图层
let layer = CAShapeLayer()
layer.lineWidth = 4
layer.strokeColor = UIColor.redColor().CGColor
layer.fillColor = UIColor.clearColor().CGColor// 2.创建路径
let path = UIBezierPath()
var point = CGPointZero
var index: Int = 0
// 2.1移动到第一个点
// 从corners数组中取出第0个元素, 将这个字典中的x/y赋值给point
CGPointMakeWithDictionaryRepresentation((codeObject.corners[index++] as! CFDictionaryRef), &point)
path.moveToPoint(point)// 2.2移动到其它的点
while index < codeObject.corners.count
{
CGPointMakeWithDictionaryRepresentation((codeObject.corners[index++] as! CFDictionaryRef), &point)
path.addLineToPoint(point)
}
// 2.3关闭路径
path.closePath()// 2.4绘制路径
layer.path = path.CGPath// 3.将绘制好的图层添加到drawLayer上
focusLayer.addSublayer(layer)
}
/**
清空边线
*/
private func clearConers(){
// 1.判断drawLayer上是否有其它图层
if focusLayer.sublayers == nil || focusLayer.sublayers?.count == 0{
return
}// 2.移除所有子图层
for subLayer in focusLayer.sublayers!
{
subLayer.removeFromSuperlayer()
}
}}
最后就能实现扫描二维码的功能了,还是比较简单的。
2、生成二维的实现 界面如下
![第三天--二维码的扫描和生成高清二维码](https://img.it610.com/image/info10/d4a7483af1bb4dfba19ed65b2c6a3db7.jpg)
文章图片
DBF06CF3-B316-41E6-A2A3-1C486FE59B4E.png 二维的生成,主要用的是CoreImage中的CIFilter的滤镜功能。实现过程也是比较简单的。
2.1首先是创建一个滤镜对象
//1.创建滤镜
let filter = CIFilter(name: "CIQRCodeGenerator")
// 设置默认属性
filter?.setDefaults()
2.2 设置需要生成二维的字符串
/设置需要生成二维码的数filter?.setValue(QRString.dataUsingEncoding(NSUTF8StringEncoding), forKey: "inputMessage")
2.3 获取输出的对象CIImge
//从滤镜中取出生成好的图片
let ciImage = filter?.outputImage
获取的CIImage的二维码,是不清晰,需要处理一下,让其清晰点。我定义一个方法
//将模糊的生成高清的let bgImage = createNonInterpolatedUIImageFormCIImage(ciImage!, size: 200)
方法具体实现如下
/**
根据CIImage生成指定大小的高清UIImage
:param: image 指定CIImage
:param: size指定大小
:returns: 生成好的图片
*/
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)
}
【第三天--二维码的扫描和生成高清二维码】最后将生成好的二维码,用UIImageView来显示就OK。是不是很简单,到这结束了吧,晚安!有什么错误,望指正,我接触swift的时间也不长!!
推荐阅读
- CVE-2020-16898|CVE-2020-16898 TCP/IP远程代码执行漏洞
- 2018-02-06第三天|2018-02-06第三天 不能再了,反思到位就差改变
- 不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
- 工具|后天就是七夕节,你准备好了吗(送上几个七夕代码,展示你技能的时候到了!)
- Android事件传递源码分析
- 《机器学习实战》高清中文版PDF英文版PDF+源代码下载
- 分享!如何分分钟实现微信扫二维码调用外部浏览器打开指定页面的功能
- 霍兰德职业代码对照表
- Quartz|Quartz 源码解析(四) —— QuartzScheduler和Listener事件监听
- py连接mysql