参考:
网上世界,QRCode无处不在,生成和识别QRCode的功能在macOS项目开发中也很常见(比如识别桌面二维码及拖拽二维码图片到窗口自动识别这样的需求),本文是简单的实现方法。
如果需要调用mac摄像头进行扫描二维码,可以使用ZXingObjC
思路
- 利用Core Image的二维码滤镜生成
CIImage
,CIImage
可以与NSImage
或UIImage
互相转化,达成生成二维码图片的目的; - Core Image为我们提供了
CIDetector
类,可以帮我们读取二维码信息。
代码
- 生成二维码图片
/// 生成原始二维码
///
/// - 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中的方法生成的图片是模糊的(跟加了个模糊滤镜似的),需要根据你需要的尺寸进行放大,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
}
- 识别二维码图片
在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
网友评论