第三天--二维码的扫描和生成高清二维码

前言
前两天我搭建了项目的大体架构,今天主要实现的的首页的二维码扫描和二维的生成。废话不多说,直奔主题。
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、生成二维的实现 界面如下

第三天--二维码的扫描和生成高清二维码
文章图片
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的时间也不长!!

    推荐阅读