[关闭]
@xifenglang-33250 2016-10-19T23:56:14.000000Z 字数 6362 阅读 1587

Swift3.0朝圣之路-生成彩色二维码图片、识别二维码图片

《Swift3.0朝圣之路》


Xcode8 / Swift3.0 / iOS8.0+

二维码在生活中应用非常广泛,在开发中也经常遇到,以前多数使用第三方库/框架生成或识别二维码,今天将介绍使用Swift(OC)原生框架类进行二维码图片的识别和生成,顺便造个Swift3.0版的轮子:

  • 识别图片中的二维码
  • 生成二维码图片
  • 用CIImage重绘UIImage
  • 生成RGB彩色二维码图片
  • 在二维码上添加Logo

识别二维码图片

识别二维码图片将使用CIDetector类,CIDetector类还支持人脸识别,即使用CIDetectorTypeFace类型,识别二维码则使用CIDetectorTypeQRCode

  1. /// 识别图片二维码
  2. class func jk_recognizeQRCodeImage(_ image: UIImage?, completionHandle: @escaping((String?, NSError?) -> Void)) -> Void {
  3. /// CIDetector可用于人脸识别 CIDetectorTypeFace CIDetectorTypeText
  4. let detector = CIDetector.init(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
  5. /// 获取的特征组
  6. let features = detector?.features(in: CIImage.init(cgImage: (image?.cgImage)!))
  7. if features != nil && (features?.count)! > 0 {
  8. /// 读取结果
  9. let feature:CIQRCodeFeature = features?.first as! CIQRCodeFeature
  10. completionHandle(feature.messageString, nil)
  11. }
  12. }

生成二维码图片

CIFilter是一个滤镜类,主要用于图片处理,也可用于生成二维码图片,CIFilter类的基本使用方法可以参考这篇文章《iOS 中的CIFilter(基础用法)》。CIFilter导出CIImage对象,可在此基础上绘制自定义的图片,更改大小、颜色等。

  1. /// 生成黑白二维码ciImage
  2. private class func jk_QRCodeImage(withString content: String?, completionHandle: @escaping((CIImage?, NSError?) -> Void)) -> Void{
  3. let data = content?.data(using: .utf8)
  4. /// 创建二维码滤镜
  5. let filter = CIFilter.init(name: "CIQRCodeGenerator")
  6. filter?.setDefaults()
  7. /// 数据源
  8. filter?.setValue(data, forKey: "inputMessage")
  9. /// L M Q H 修正等级,应该跟采样有关
  10. filter?.setValue("H", forKey: "inputCorrectionLevel")
  11. /// 黑白色的图片
  12. let ciImage = filter?.outputImage
  13. completionHandle(ciImage,nil)
  14. }

img1img2img3

用CIImage重绘UIImage

绘图的方法除了Swift3.0格式外,较网上流传的代码还做了点更改,这里传入目标大小CGSize,而不是传缩放因子scale,直接传sclae不容易理解,传CGSize更直观,内部通过Size计算contextRef?.scaleBy(x: scale, y: scale)用到的scale即可。contextRef?.scaleBy即OC中的CGContextScaleCTM,可查看此文章了解《CGContextTranslateCTM,CGContextScaleCTM,CGContextRotateCTM详解

  • Swift3.0中传入多个枚举值的方法,使用.rawValue | .rawValue
    CGImageAlphaInfo.noneSkipFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
  1. /// 用CIImage重绘UIImage
  2. class func jk_resize(ciImage: CIImage, size: CGSize, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void {
  3. let width = size.width * UIScreen.main.scale
  4. let height = size.height * UIScreen.main.scale
  5. /// 计算合适的缩放比例
  6. let scale = min(width, height) / min(ciImage.extent.width, ciImage.extent.height)
  7. /// 适合生成RGB色值的彩色图片(兼容黑白色)
  8. let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
  9. var contextRef = CGContext.init(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpaceRef, bitmapInfo:CGImageAlphaInfo.noneSkipFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue)
  10. /// 如果不需要更改二维码的颜色,即黑白色,用下面的代码即可
  11. // let colorSpaceRef = CGColorSpaceCreateDeviceGray()
  12. // var contextRef = CGContext.init(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpaceRef, bitmapInfo:CGImageAlphaInfo.none.rawValue)
  13. let context = CIContext.init(options: nil)
  14. var imageRef = context.createCGImage(ciImage, from: ciImage.extent)
  15. contextRef?.interpolationQuality = CGInterpolationQuality.init(rawValue: CGInterpolationQuality.none.rawValue)!
  16. contextRef?.scaleBy(x: scale, y: scale)
  17. contextRef?.draw(imageRef!, in: ciImage.extent)
  18. let newImage = contextRef?.makeImage()
  19. /// Swift3.0应该对CG/CF开头的类/结构体做了ARC适配,已经没了Release方法。
  20. contextRef = nil
  21. imageRef = nil
  22. completionHandle(UIImage.init(cgImage: newImage!),nil)
  23. }

生成RGB彩色二维码图片 / 修改二维码图片

生成黑白色的二维码图片

  1. /// 生成二维码图片
  2. class func jk_QRCodeImage(withString content: String?, size: CGSize, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void{
  3. self.jk_QRCodeImage(withString: content) { (ciImage, error) in
  4. if (error != nil){
  5. completionHandle(nil, error)
  6. }else {
  7. self.jk_resize(ciImage: ciImage!, size: size, completionHandle: completionHandle)
  8. }
  9. }
  10. }

生成RGB色值二维码图片
主要是在通过ciImage创建新的颜色滤镜CIFilter.init(name: "CIFalseColor"),通过KVC替换普通二维码中的黑色和白色。colorFilter?.setValue(rgbColor, forKey: "inputColor0"),inputColor0可用替换黑色,inputColor1可用于替换白底色。

  1. /// 生成彩色的二维码
  2. class func jk_QRCodeImage(withString content: String?, rgbColor: CIColor, size: CGSize, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void{
  3. self.jk_QRCodeImage(withString: content) { (ciImage, error) in
  4. if (error != nil) {
  5. completionHandle(nil, error)
  6. }else {
  7. /// 创建颜色滤镜
  8. let colorFilter = CIFilter.init(name: "CIFalseColor")
  9. colorFilter?.setDefaults()
  10. colorFilter?.setValue(ciImage, forKey: "inputImage")
  11. /// 替换黑色
  12. colorFilter?.setValue(rgbColor, forKey: "inputColor0")
  13. /// 默认白色,可自行替换
  14. colorFilter?.setValue(CIColor.init(red: 1, green: 1, blue: 1), forKey: "inputColor1")
  15. let codeImage = colorFilter?.outputImage
  16. self.jk_resize(ciImage: codeImage!, size: size, completionHandle: completionHandle)
  17. }
  18. }

突然想起我面试中的机试便是合成2张多线程队列下载的图片,跟下面的代码相似。

  • Logo的宽度取二维码图片的1/4宽度比较合适,位置放中间。如果对二维码的规则好奇,可戳二维码生成细节和原理
  1. /// 添加LOGO小图
  2. class func jk_addLogo(logo: UIImage?, forQRCodeImage QRImage: UIImage?, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void {
  3. let qrImageBounds = CGRect.init(x: 0, y: 0,
  4. width: (QRImage?.size.width)!,
  5. height: (QRImage?.size.height)!)
  6. let logoSize = CGSize.init(width: qrImageBounds.size.width * 0.25,
  7. height: qrImageBounds.size.height * 0.25)
  8. let x = (qrImageBounds.width - logoSize.width) * 0.5
  9. let y = (qrImageBounds.height - logoSize.height) * 0.5
  10. UIGraphicsBeginImageContext(qrImageBounds.size)
  11. QRImage?.draw(in: qrImageBounds)
  12. logo?.draw(in: CGRect.init(x: x, y: y,
  13. width: logoSize.width,
  14. height: logoSize.height))
  15. let resultImage = UIGraphicsGetImageFromCurrentImageContext()
  16. UIGraphicsEndImageContext()
  17. completionHandle(resultImage,nil)
  18. }
  19. }

栗子

  1. /// 识别二维码图片
  2. JKQRCodeTool.jk_recognizeQRCodeImage(UIImage.init(named: "JKSwiftGitHub"), completionHandle: { (str, error) in
  3. if error != nil {
  4. JKLOG(error)
  5. } else {
  6. JKLOG(str)
  7. /// 生成二维码图片
  8. /// 黑白色
  9. /*
  10. JKQRCodeTool.jk_QRCodeImage(withString: str, size: CGSize.init(width: 500, height: 500), completionHandle: { (image, error1) in
  11. if error1 != nil {
  12. JKLOG(error1)
  13. } else {
  14. imageView.image = image
  15. }
  16. })
  17. */
  18. /// 彩色
  19. JKQRCodeTool.jk_QRCodeImage(withString: str, rgbColor: CIColor.init(red: 1, green: 0, blue: 0, alpha: 1), size: CGSize.init(width: 200, height: 200), completionHandle: { (image, error2) in
  20. if error2 != nil {
  21. JKLOG(error2)
  22. } else {
  23. self.imageView?.image = image
  24. /// 添加LOGO
  25. JKQRCodeTool.jk_addLogo(logo: UIImage.init(named: "logo"), forQRCodeImage: image, completionHandle: { (qrImage, error3) in
  26. if error3 != nil {
  27. JKLOG(error3)
  28. } else {
  29. self.imageView?.image = qrImage
  30. /// 识别二维码图片
  31. JKQRCodeTool.jk_recognizeQRCodeImage(qrImage, completionHandle: { (str, error4) in
  32. if error4 != nil {
  33. JKLOG(error4)
  34. } else {
  35. JKLOG(str)
  36. }
  37. })
  38. }
  39. })
  40. }
  41. })
  42. }

--------------------------------------------

我所有Swift3.0练习Demo都放到了Github上,并且在不断更新。
Swift3.0朝圣之路-全集地址

  1. Swift3.0闭包的使用详解,简单封装GET/POST网络请求
  2. WKWebView的使用详解,包括JS交互
  3. 原来MapKit的简单使用,包括定位+地图+地理编码
  4. OC+Swift混编,介绍高德地图SDK的简单使用,包括定位+地图+POI搜索+导航+UISearchController使用
  5. 协议代理的基础用法
  6. 分类/类别的使用和封装
  7. 【Then协议库】-眼前一亮的初始化方式
  8. 使用Runtime在分类Extension中添加属性
  9. 封装UIAlertController
  10. 自定义相册【尚未完成】
  11. 用原生框架扫描、识别二维码图片,生成黑白色、彩色二维码图片
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注