@xifenglang-33250
2016-10-19T15:56:14.000000Z
字数 6362
阅读 1737
《Swift3.0朝圣之路》
Xcode8 / Swift3.0 / iOS8.0+ 二维码在生活中应用非常广泛,在开发中也经常遇到,以前多数使用第三方库/框架生成或识别二维码,今天将介绍使用Swift(OC)原生框架类进行二维码图片的识别和生成,顺便造个Swift3.0版的轮子:
- 识别图片中的二维码
- 生成二维码图片
- 用CIImage重绘UIImage
- 生成RGB彩色二维码图片
- 在二维码上添加Logo
识别二维码图片将使用CIDetector类,CIDetector类还支持人脸识别,即使用CIDetectorTypeFace类型,识别二维码则使用CIDetectorTypeQRCode。
/// 识别图片二维码class func jk_recognizeQRCodeImage(_ image: UIImage?, completionHandle: @escaping((String?, NSError?) -> Void)) -> Void {/// CIDetector可用于人脸识别 CIDetectorTypeFace CIDetectorTypeTextlet detector = CIDetector.init(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])/// 获取的特征组let features = detector?.features(in: CIImage.init(cgImage: (image?.cgImage)!))if features != nil && (features?.count)! > 0 {/// 读取结果let feature:CIQRCodeFeature = features?.first as! CIQRCodeFeaturecompletionHandle(feature.messageString, nil)}}
CIFilter是一个滤镜类,主要用于图片处理,也可用于生成二维码图片,CIFilter类的基本使用方法可以参考这篇文章《iOS 中的CIFilter(基础用法)》。CIFilter导出CIImage对象,可在此基础上绘制自定义的图片,更改大小、颜色等。
/// 生成黑白二维码ciImageprivate class func jk_QRCodeImage(withString content: String?, completionHandle: @escaping((CIImage?, NSError?) -> Void)) -> Void{let data = content?.data(using: .utf8)/// 创建二维码滤镜let filter = CIFilter.init(name: "CIQRCodeGenerator")filter?.setDefaults()/// 数据源filter?.setValue(data, forKey: "inputMessage")/// L M Q H 修正等级,应该跟采样有关filter?.setValue("H", forKey: "inputCorrectionLevel")/// 黑白色的图片let ciImage = filter?.outputImagecompletionHandle(ciImage,nil)}
绘图的方法除了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
/// 用CIImage重绘UIImageclass func jk_resize(ciImage: CIImage, size: CGSize, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void {let width = size.width * UIScreen.main.scalelet height = size.height * UIScreen.main.scale/// 计算合适的缩放比例let scale = min(width, height) / min(ciImage.extent.width, ciImage.extent.height)/// 适合生成RGB色值的彩色图片(兼容黑白色)let colorSpaceRef = CGColorSpaceCreateDeviceRGB()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)/// 如果不需要更改二维码的颜色,即黑白色,用下面的代码即可// let colorSpaceRef = CGColorSpaceCreateDeviceGray()// var contextRef = CGContext.init(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpaceRef, bitmapInfo:CGImageAlphaInfo.none.rawValue)let context = CIContext.init(options: nil)var imageRef = context.createCGImage(ciImage, from: ciImage.extent)contextRef?.interpolationQuality = CGInterpolationQuality.init(rawValue: CGInterpolationQuality.none.rawValue)!contextRef?.scaleBy(x: scale, y: scale)contextRef?.draw(imageRef!, in: ciImage.extent)let newImage = contextRef?.makeImage()/// Swift3.0应该对CG/CF开头的类/结构体做了ARC适配,已经没了Release方法。contextRef = nilimageRef = nilcompletionHandle(UIImage.init(cgImage: newImage!),nil)}
生成黑白色的二维码图片
/// 生成二维码图片class func jk_QRCodeImage(withString content: String?, size: CGSize, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void{self.jk_QRCodeImage(withString: content) { (ciImage, error) inif (error != nil){completionHandle(nil, error)}else {self.jk_resize(ciImage: ciImage!, size: size, completionHandle: completionHandle)}}}
生成RGB色值二维码图片
主要是在通过ciImage创建新的颜色滤镜CIFilter.init(name: "CIFalseColor"),通过KVC替换普通二维码中的黑色和白色。colorFilter?.setValue(rgbColor, forKey: "inputColor0"),inputColor0可用替换黑色,inputColor1可用于替换白底色。
/// 生成彩色的二维码class func jk_QRCodeImage(withString content: String?, rgbColor: CIColor, size: CGSize, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void{self.jk_QRCodeImage(withString: content) { (ciImage, error) inif (error != nil) {completionHandle(nil, error)}else {/// 创建颜色滤镜let colorFilter = CIFilter.init(name: "CIFalseColor")colorFilter?.setDefaults()colorFilter?.setValue(ciImage, forKey: "inputImage")/// 替换黑色colorFilter?.setValue(rgbColor, forKey: "inputColor0")/// 默认白色,可自行替换colorFilter?.setValue(CIColor.init(red: 1, green: 1, blue: 1), forKey: "inputColor1")let codeImage = colorFilter?.outputImageself.jk_resize(ciImage: codeImage!, size: size, completionHandle: completionHandle)}}
突然想起我面试中的机试便是合成2张多线程队列下载的图片,跟下面的代码相似。
- Logo的宽度取二维码图片的1/4宽度比较合适,位置放中间。如果对二维码的规则好奇,可戳二维码生成细节和原理
/// 添加LOGO小图class func jk_addLogo(logo: UIImage?, forQRCodeImage QRImage: UIImage?, completionHandle: @escaping((UIImage?, NSError?) -> Void)) -> Void {let qrImageBounds = CGRect.init(x: 0, y: 0,width: (QRImage?.size.width)!,height: (QRImage?.size.height)!)let logoSize = CGSize.init(width: qrImageBounds.size.width * 0.25,height: qrImageBounds.size.height * 0.25)let x = (qrImageBounds.width - logoSize.width) * 0.5let y = (qrImageBounds.height - logoSize.height) * 0.5UIGraphicsBeginImageContext(qrImageBounds.size)QRImage?.draw(in: qrImageBounds)logo?.draw(in: CGRect.init(x: x, y: y,width: logoSize.width,height: logoSize.height))let resultImage = UIGraphicsGetImageFromCurrentImageContext()UIGraphicsEndImageContext()completionHandle(resultImage,nil)}}
栗子
/// 识别二维码图片JKQRCodeTool.jk_recognizeQRCodeImage(UIImage.init(named: "JKSwiftGitHub"), completionHandle: { (str, error) inif error != nil {JKLOG(error)} else {JKLOG(str)/// 生成二维码图片/// 黑白色/*JKQRCodeTool.jk_QRCodeImage(withString: str, size: CGSize.init(width: 500, height: 500), completionHandle: { (image, error1) inif error1 != nil {JKLOG(error1)} else {imageView.image = image}})*//// 彩色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) inif error2 != nil {JKLOG(error2)} else {self.imageView?.image = image/// 添加LOGOJKQRCodeTool.jk_addLogo(logo: UIImage.init(named: "logo"), forQRCodeImage: image, completionHandle: { (qrImage, error3) inif error3 != nil {JKLOG(error3)} else {self.imageView?.image = qrImage/// 识别二维码图片JKQRCodeTool.jk_recognizeQRCodeImage(qrImage, completionHandle: { (str, error4) inif error4 != nil {JKLOG(error4)} else {JKLOG(str)}})}})}})}
我所有Swift3.0练习Demo都放到了Github上,并且在不断更新。
Swift3.0朝圣之路-全集地址