iOS开发-定制多样式二维码

原文作者:Sindri的小巢(简书作者)

原文链接: http://www.jianshu.com/p/d90cd2cb41d7

本文将原文中的Objective-C语言改为Swift语言。

 

  二维码/条形码是按照某种特定的几何图形按一定规律在平台(一维/二维方向上)分布的黑白相间的图形纪录符号信息。使用若干个与二进制对应的几何形体来表示文字数值信息。

  最常见的二维码功能包括信息获取、网站跳转、电商交易、手机支付等等,其拥有密度小、信息容量大、容错能力强、成本低、制作难度低等优点。在移动开发中,二维码的地位也越来越重要,掌握二维码的基本操作是重要的本领之一。

  在iOS7之后,苹果自身集成了二维码的生成和读取功能。生成二维码包括以下步骤:

  1. 导入CoreImage/CoreImage.h头文件

  2. 使用CIFilter滤镜类生成二维码
  3. 对生成的二维码进行加工,使其更清晰

  除了上述三个步骤之外,我们还可以对二维码进行进一步的拓展处理

  1. 自定义二维码图案颜色

  2. 在二维码中心插入圆角小图片

  3. 在圆角图片下面加上一层圆角白色图片 

二维码生成

  码农们生产代码的同时永远不要忘记尽可能的复用,那么为了实现这种目的,本文的代码通过类别拓展UIImage的方法来完成。我们先声明并实现一个类方法用来接收二维码存储数据以及二维码尺寸的方法:

    static func imageOfQRFromURL(networkAddress: String?, codeSize: CGFloat) -> UIImage? {
        
        if let address = networkAddress where address.characters.count > 0 {
            let size = validateCodeSize(codeSize)
            let originImage = createQRFromAddress(address)
            if let image = originImage {
                return UIImage(CIImage: image)
            }
            return nil
        }
        return nil
    }

  在上面的代码里面,我们总共做了四件事情:验证存储信息的有效性;验证二维码尺寸的合理大小;使用存储信息生成二维码;将二维码转成UIImage返回。这些方法的实现分别如下:

    //验证二维码尺寸的合法性
    func validateCodeSize(codeSize: CGFloat) -> CGFloat {
        var size = max(codeSize, 160)
        size = min(CGRectGetWidth(UIScreen.mainScreen().bounds) - 80, size)
        return size
    }  
    //利用系统滤镜生成二维码
    static func createQRFromAddress(networkAddress: String) -> CoreImage.CIImage? {
        let stringData = networkAddress.dataUsingEncoding(NSUTF8StringEncoding)
        let qrFilter = CIFilter(name: "CIQRCodeGenerator")
        qrFilter?.setValue(stringData, forKey: "inputMessage")
        qrFilter?.setValue("H", forKey: "inputCorrectionLevel")
        return qrFilter?.outputImage
    }

  ps:对于CIFilter想要更进一步了解,可以在xcode中使用快捷键shift+command+0打开文档,然后搜索core image filter reference获取更多滤镜的使用方法,这些滤镜可以用来实现类似美图秀秀的修图功能

  上面的代码生成了一个粗略的二维码图,我们需要对图片再进行一次处理,使其清晰化。因为,我们需要另外一个类别方法: 

    //图像进行清晰化处理
    static func excludeFuzzyImageFromCIImage(image: CoreImage.CIImage, size: CGFloat) -> UIImage {
        let extent = CGRectIntegral(image.extent)
        let scale = min(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent))
        let width = CGRectGetWidth(extent) * scale
        let height = CGRectGetHeight(extent) * scale
        //创建灰度色调空间
        let colorSpace = CGColorSpaceCreateDeviceGray()
        let bitmapRef = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, colorSpace, CGImageAlphaInfo.None.rawValue)
        
        let context = CIContext(options: nil)
        let bitmapImage = context.createCGImage(image, fromRect: extent)
        CGContextSetInterpolationQuality(bitmapRef, .None)
        CGContextScaleCTM(bitmapRef, scale, scale)
        CGContextDrawImage(bitmapRef, extent, bitmapImage)
        
        let scaledImage = CGBitmapContextCreateImage(bitmapRef)
        
        return UIImage(CGImage: scaledImage!)
    }

  那么这时候,我们把imageOfQRFromURL方法中的

return UIImage(CIImage: image)

改为

return UIImage.excludeFuzzyImageFromCIImage(image, size: size)

示例完成后生成的二维码效果图如下:

二维码拓展

  单一的黑白色二维码并不一定总能满足开发的需求或者说领导的需求。好比现在的应用很多功能界面上都在朝着微信学习,这就包括了更多色彩,更多样式的二维码。本文将从颜色、二维码中心小图案这两点入手讲解如何制作类似微信生成我的二维码的样式。

  自定义二维码颜色的实现思路是,遍历生成的二维码的像素点,将其中为白色的像素点填充为透明色,非白色则填充为我们自定义的颜色。但是,这里的白色并不单单指纯白色,rgb值高于一定数值的灰色我们也可以视作白色处理。在这里我对白色的定义为rgb值高于0xd0d0d0的颜色值为白色,这个值并不是确定的,大家可以自己设置。基于颜色的设置,我们将原有生成二维码的方法接口改成这样:

    static func imageOfQRFromURL(networkAddress: String?, codeSize: CGFloat, red: NSInteger, green: NSInteger, blue: NSInteger) -> UIImage? {
        
        if let address = networkAddress where address.characters.count > 0 {

            //颜色不可能太接近白色
            let rgb = (red << 16) + (green << 8) + blue
            assert((rgb & 0xffffff00) <= 0xd0d0d000, "The color of QR code is two close to white color, than it will diffculty to scan.")
            
            let size = validateCodeSize(codeSize)
            let originImage = createQRFromAddress(address)
            if let image = originImage {
                let progressImage = UIImage.excludeFuzzyImageFromCIImage(image, size: size)
                
                //对生成的二维码进行颜色填充
                let effecticeImage = imageFillBlackColorAndTransparent(progressImage, red: red, green: green, blue: blue)
                return effecticeImage
            }
            return nil
        }
        return nil
    }

  相较于前面的代码,多了两个步骤:判断rgb的有效值;对二维码进行颜色渲染。颜色渲染的过程包括获取图像的位图上下文、像素替换、二进制图像转换等操作,具体代码如下:



 



 

posted @ 2016-09-23 15:52  紫洁  阅读(646)  评论(0编辑  收藏  举报