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

前言

前两天我搭建了项目的大体架构,今天主要实现的的首页的二维码扫描和二维的生成。废话不多说,直奔主题。

1、二维码扫描

首先来张效果图

第三天--二维码的扫描和生成高清二维码_第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、生成二维的实现

界面如下


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

你可能感兴趣的:(第三天--二维码的扫描和生成高清二维码)