Mac开发云集iOS之MAC端开发Mac OSX开发

macOS实现二维码图片生成及识别

2018-05-09  本文已影响13人  Supremodeamor

参考:

网上世界,QRCode无处不在,生成和识别QRCode的功能在macOS项目开发中也很常见(比如识别桌面二维码及拖拽二维码图片到窗口自动识别这样的需求),本文是简单的实现方法。
如果需要调用mac摄像头进行扫描二维码,可以使用ZXingObjC

效果图

思路

  1. 利用Core Image的二维码滤镜生成CIImage, CIImage可以与 NSImageUIImage互相转化,达成生成二维码图片的目的;
  2. Core Image为我们提供了CIDetector类,可以帮我们读取二维码信息。

代码

  1. 生成二维码图片
/// 生成原始二维码
    ///
    /// - Parameter message: 二维码信息
    /// - Returns: 二维码图片 CIImage
    private func generateOriginQRImage(message: String) -> CIImage? {
        let messageData = message.data(using: .utf8)
        // 创建二维码滤镜
        let qrCIFilter = CIFilter(name: "CIQRCodeGenerator")
        guard qrCIFilter != nil else {
            fatalError("QRCIFilter is nil")
        }
        qrCIFilter!.setValue(messageData, forKey: "inputMessage")
        //L7% M15% Q25% H%30% 纠错级别. 默认值是M
        qrCIFilter!.setValue("H", forKey: "inputCorrectionLevel")
        
        return qrCIFilter!.outputImage
    }
  1. 优化二维码图片

步骤1中的方法生成的图片是模糊的(跟加了个模糊滤镜似的),需要根据你需要的尺寸进行放大,CIFalseColor滤镜则可以调整图片背景色和前景色。为了满足设置logo图的需求,我添加了图片合并的代码。
另外由于CIImage无法直接转成NSImage,我借助CGImage类型做了一下桥梁。

    /// 创建二维码图片
    ///
    /// - Parameters:
    ///   - message: 二维码信息 String
    ///   - size: 生成图片的大小
    ///   - backgroundColor: 图片背景色
    ///   - foregroundColor: 二维码颜色
    ///   - fillImage: 修饰图片(logo图之类的)
    /// - Returns: 二维码图片 NSImage
    func createQRImage(message: String, size: NSSize = NSSize(width: 200, height: 200), backgroundColor: CIColor = .white, foregroundColor: CIColor = .black, fillImage: NSImage? = nil) -> NSImage? {
        guard let originImage = generateOriginQRImage(message: message) else {
            fatalError("failed to generate a QRImage")
        }
        
        let colorFilter = CIFilter(name: "CIFalseColor")
        //输入图片
        colorFilter!.setValue(originImage, forKey: "inputImage")
        //输入颜色
        colorFilter!.setValue(foregroundColor, forKey: "inputColor0")
        colorFilter!.setValue(backgroundColor, forKey: "inputColor1")
        
        guard let colorImage = colorFilter?.outputImage?.transformed(by: CGAffineTransform(scaleX: size.width/originImage.extent.width, y: size.height/originImage.extent.height)) else {
            fatalError("failed to generate the colorImage")
        }
        
        let image = NSImage(cgImage: convertCIImageToCGImage(inputImage: colorImage)!, size: size)
        
        if let fillImage = fillImage {
            let fillRect = CGRect(x: (size.width - size.width/4)/2, y: (size.height - size.height/4)/2, width: size.width/4, height: size.height/4)
            image.lockFocus()
            fillImage.draw(in: fillRect)
            image.unlockFocus()
        }
        
        return image
    }

    /// CIImage转成CGImage
    ///
    /// - Parameter inputImage: CIImage
    /// - Returns: CGImage
    private func convertCIImageToCGImage(inputImage: CIImage) -> CGImage? {
        let context = CIContext(options: nil)
        if let cgImage = context.createCGImage(inputImage, from: inputImage.extent) {
            return cgImage
        }
        return nil
    }
  1. 识别二维码图片
    在macOS项目中需要将NSImage转成CIImage, 然后使用CIDetector类进行二维码的检测识别和信息读取。
    /// 识别二维码
    ///
    /// - Parameter targetImage: 目标图片
    /// - Returns: 二维码信息字符串
    func recognizeQRCode(targetImage: NSImage) -> String? {
        
        let imageData = targetImage.tiffRepresentation(using: .none, factor: 0)
        let ciImage = CIImage(data: imageData!)
        /*创建探测器 options 是字典key:
         CIDetectorAccuracy 精度
         CIDetectorTracking 轨迹
         CIDetectorMinFeatureSize 最小特征尺寸
         CIDetectorNumberOfAngles 角度**/
        let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: CIContext(), options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
        
        let featers = detector?.features(in: ciImage!) as? [CIQRCodeFeature]
        return featers?.last?.messageString
    }

Demo下载地址:Demo

上一篇 下一篇

猜你喜欢

热点阅读