二维码扫描、更新与创建

  • 二维码需要用到库AVFoundation
  • 导入库完毕后,按照下面几个步骤来做

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    /// 1.创建输入
    private lazy var inputDevice: AVCaptureDeviceInput? =
    {
    let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    do{
    let input = try AVCaptureDeviceInput(device: device)
    return input
    }catch
    {
    return nil
    }
    }()
    /// 2.创建输出
    private lazy var output: AVCaptureMetadataOutput = {
    let output = AVCaptureMetadataOutput()
    return output
    }()
    /// 3.创建会话
    private lazy var session: AVCaptureSession = {
    let s = AVCaptureSession()
    s.sessionPreset = "AVCaptureSessionPreset1920x1080"
    return s
    }()
    /// 4.创建预览图层
    private lazy var previewLayer: AVCaptureVideoPreviewLayer = {
    let layer = AVCaptureVideoPreviewLayer(session: self.session)
    layer.frame = UIScreen.mainScreen().bounds
    return layer
    }()
  • 代理捕捉扫描信息

    1
    2
    3
    4
    5
    6
    7
    8
    extension QRCodeViewController: AVCaptureMetadataOutputObjectsDelegate
    {
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!)
    {
    NJLog(metadataObjects.last?.stringValue)
    }
    }
  • 启动扫描

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    private func startScanQRCode()
    {
    // 1.判断是否可以添加输入设备
    if !session.canAddInput(inputDevice)
    {
    return
    }
    // 2.判断是否可以添加输出对象
    if !session.canAddOutput(output)
    {
    return
    }
    // 3.添加输入和输出到会话中
    session.addInput(inputDevice)
    session.addOutput(output)
    // 4.设置输出解析数据类型
    // 必须在输出对象添加到会话之后才可以设置, 否则会报错
    output.metadataObjectTypes = output.availableMetadataObjectTypes
    // 5.设置输出代理, 监听解析到得结果
    output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
    // 6.添加预览图层
    view.layer.insertSublayer(previewLayer, atIndex: 0)
    // 将绘制边框图层添加到预览图层上 previewLayer.addSublayer(drawLayer)
    // 6.利用会话开始扫描
    session.startRunning()
    }
  • 设置感兴趣范围

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /// 2.创建输出
    private lazy var output: AVCaptureMetadataOutput = {
    let output = AVCaptureMetadataOutput()
    // 设置兴趣点(感兴趣范围), 默认是全屏
    // 注意: 是以横屏的左上角为参照
    // output.rectOfInterest = CGRect(x: 0, y: 0, width: 0.5, height: 0.5)
    let frame = self.containerView.frame
    let size = self.view.frame.size
    // 由于是按照横屏来计算的, 所以需要将x变为y, y变为x, 将宽变为高, 高变为宽
    output.rectOfInterest = CGRect(x: frame.origin.y / size.height, y: frame.origin.x / size.width, width: frame.size.height / size.height, height: frame.size.width / size.width)
    return output
    }()
  • 描绘边框

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!)
    {
    // 0. 移除以前的描边
    clearCorners()
    for objc in metadataObjects
    {
    // 1.将扫描到二维码的坐标转换为我们能够识别的坐标
    let codeObjc = previewLayer.transformedMetadataObjectForMetadataObject(objc as! AVMetadataObject)
    // 2.根据转换好的坐标绘制二维码描边
    drawCorners(codeObjc as! AVMetadataMachineReadableCodeObject)
    }
    }
    ///绘制二维码描边
    private func drawCorners(codeObjc: AVMetadataMachineReadableCodeObject)
    {
    if codeObjc.corners == nil || codeObjc.corners.count == 0
    {
    return
    }
    // 1.绘制路径
    let subLayer = CAShapeLayer()
    subLayer.lineWidth = 4
    subLayer.strokeColor = UIColor.redColor().CGColor
    subLayer.fillColor = UIColor.clearColor().CGColor
    // 2.从传入对象中获取4个点, 创建Path
    let path = UIBezierPath()
    var point = CGPointZero
    var index = 0
    let dictArr = codeObjc.corners
    // 2.1取出第0个点
    // 将字典中的xy转换为CGPoint
    CGPointMakeWithDictionaryRepresentation(dictArr[index++] as! CFDictionaryRef, &point)
    // 2.2移动到第0个点
    path.moveToPoint(point)
    // 2.3添加其它的点
    while index < dictArr.count
    {
    CGPointMakeWithDictionaryRepresentation(dictArr[index++] as! CFDictionaryRef, &point)
    path.addLineToPoint(point)
    }
    // 2.4关闭路径
    path.closePath()
    subLayer.path = path.CGPath
    // 3.将layer添加到drawLayer上
    drawLayer.addSublayer(subLayer)
    }
    /// 移除以前的描边
    private func clearCorners()
    {
    if drawLayer.sublayers == nil || drawLayer.sublayers?.count == 0
    {
    return
    }
    for subLayer in drawLayer.sublayers!
    {
    subLayer.removeFromSuperlayer()
    }
    }

二维码创建

  • 根据信息创建二维码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 1.生成二维码
    // 1.创建滤镜
    let filter = CIFilter(name: "CIQRCodeGenerator")!
    // 2.还原滤镜默认设置
    filter.setDefaults()
    // 3.设置数据
    filter.setValue("极客江南".dataUsingEncoding(NSUTF8StringEncoding), forKey: "inputMessage")
    // 4.从滤镜从取出二维码
    let ciImage = filter.outputImage!
    // customImageView.image = UIImage(CIImage: ciImage)
    // customImageView.image = createNonInterpolatedUIImageFormCIImage(ciImage, size: 500)
    let QRCodeImage = createNonInterpolatedUIImageFormCIImage(ciImage, size: 500)
    // 5.设置图片到界面上
    image.image = QRCodeImage
  • 生成高清放大的图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
根据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)
}