iOS--各种样式的二维码生成

不得不说,二维码是小日本的一个伟大发明,它密度小、信息容量大、容错能力强、成本低、制作难度低等优点,使得二维码得到广泛的运用,我们可以在二维码里面存储各种信息,如网站链接、移动支付,非常方便,用户只需扫一扫就行,所以我们越来越多的移动应用也将一些信息封装成二维码了。

iOS--各种样式的二维码生成_第1张图片
二维码

二维码其实就是由很多0、1组成的数字矩阵,用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息;二维码能够在横向和纵向两个方位同时表达信息,因此能在很小的面积内表达大量的信息。在iOS当中,iOS7以后,系统自身集成了二维码的生成与读取功能,不需要我们再集成第三方了;iOS7以下使用libqrencode库来生成二维码图片。二维码样式大概有以下三种:

1、普通形式的二维码
2、自定义颜色的二维码
3、中间带logo的二维码

下面介绍下二维码生成的详细步骤:

一、普通二维码

我们可以把生成 二维码方法封装到一个工具类或者UIImage类别当中,方便以后调用,先拟好方法名:

+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size;

首先,我们需要导入头文件

#import 

然后把封装的文字contentUTF-8转一下,不转的话可能导致崩溃,再实例化一个CIFilter对象,使用CIFilter滤镜类生成二维码,再通过kvo方式给一个字符串,生成二维码。

NSData *stringData = [content dataUsingEncoding: NSUTF8StringEncoding];
CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
[qrFilter setValue:stringData forKey:@"inputMessage"];//通过kvo方式给一个字符串,生成二维码

二维码都有一定的容错能力,就是有部分污损或者破损都没有关系,照常识别。但是也是有限度的,这根据生成时使用的纠错级别而定,可以有7%~30%左右的损坏,实际上保守一点更好。官方文档显示:

字母代表的容错能力分别为:
L  : 7%
M : 15%
Q : 25%
H : 30%

注意:
基本原则:
1、三个角上的“回”及“回”字周围的底色不要动
2、中间部分和不带“回”字的一角是可以填图片的(中间最好)
3、如果中间有小的“回”字,能不变就不变,能少变就少变
4、尽可能放大二维码后再添加图片,不要添加图片后放大
5、生成时尽量选择较高的纠错级别

所以再给qrFilter设置一个容错属性:

[qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"];//设置二维码的纠错水平,越高纠错水平越高,可以污损的范围越大

其实到这里二维码显示就完成了,通过imageWithCGImage方法转为UIImage用UIImageView显示就可以。但是这样显示会有点模糊,我们需要清晰化处理一下,使二维码更清楚,代码如下:

CIImage *image = qrFilter.outputImage;
CGRect extent = CGRectIntegral(image.extent);
CGFloat scale = MIN(size.width / CGRectGetWidth(extent), size.width / CGRectGetHeight(extent));
size_t width = CGRectGetWidth(extent) * scale;
size_t height = CGRectGetHeight(extent) * scale;
    
//创建DeviceGray灰度色调空间
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
//创建bitmap
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, colorSpace, (CGBitmapInfo)kCGImageAlphaNone);
CIContext * context = [CIContext contextWithOptions: nil];
CGImageRef bitmapImage = [context createCGImage: image fromRect: extent];
CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
CGContextScaleCTM(bitmapRef, scale, scale);
CGContextDrawImage(bitmapRef, extent, bitmapImage);
//保存bitmap到图片
CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
CGContextRelease(bitmapRef);
CGImageRelease(bitmapImage);
CGColorSpaceRelease(colorSpace);

return [UIImage imageWithCGImage: scaledImage];

还有一种绘画方法,也能达到相同效果,代码如下:

//上色
UIColor *onColor = [UIColor blackColor];
UIColor *offColor = [UIColor whiteColor];
CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"
                                       keysAndValues:
                             @"inputImage",qrFilter.outputImage,
                             @"inputColor0",[CIColor colorWithCGColor:onColor.CGColor],
                             @"inputColor1",[CIColor colorWithCGColor:offColor.CGColor],
                             nil];
    
CIImage *qrImage = colorFilter.outputImage;
    
//绘制
CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent];
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
    
CGImageRelease(cgImage);
    
return codeImage;

得到效果图如下:

iOS--各种样式的二维码生成_第2张图片
二维码效果

  有一点非常有趣,比如你封装的格式越复杂二维码密度越大,如果你封装的只有数字,比如@"111111",三个"回"字显示的比较大,密度较小,自己体会!显示的效果如下:

iOS--各种样式的二维码生成_第3张图片
格式简单二维码

二、自定义颜色二维码

由上面显示的二维码可知,一般二维码都是黑白相间的格子组成,但有时我们需要个性化一点的二维码,那就需要定制一个专属颜色,这里所用的方法就是遍历像素, 改变像素点颜色,代码如下:

//改变二维码颜色
+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size red:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue{
    
    UIImage *image = [self createQRImageWithContent:content size:size];
    int imageWidth = image.size.width;
    int imageHeight = image.size.height;
    size_t bytesPerRow = imageWidth * 4;
    uint32_t *rgbImageBuf = (uint32_t *)malloc(bytesPerRow * imageHeight);
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpaceRef, kCGBitmapByteOrder32Little|kCGImageAlphaNoneSkipLast);
    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
    //遍历像素, 改变像素点颜色
    int pixelNum = imageWidth * imageHeight;
    uint32_t *pCurPtr = rgbImageBuf;
    for (int i = 0; i

效果图如下:

iOS--各种样式的二维码生成_第4张图片
自定义颜色二维码

  细心的同学发现,用生成普通二维码的时候所用的第二种绘制方法,改变二维码颜色方法更简单,关键代码是这两种颜色:

UIColor *onColor = [UIColor blackColor];//黑点
UIColor *offColor = [UIColor whiteColor];//白点

你只需要把onColor改为定制颜色就OK了,非常简单!

三、带logo的二维码

我们在外面看到的海报附带的二维码一般都会带个logo,这样又展示了公司的logo又使二维码变的更加漂亮!如果logo不需要切圆角,使用drawInRect就能实现,代码如下:

+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size red:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue withLogo:(UIImage *)logo logoFrame:(CGRect)logoFrame{
    
    UIImage *image = [self createQRImageWithContent:content size:size red:red green:green blue:blue];
    //有 logo 则绘制 logo
    if (logo != nil) {
        UIGraphicsBeginImageContext(image.size);
        [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
        [logo drawInRect:logoFrame];
        
        UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return resultImage;
    }else{
        return image;
    }
}

效果图如下:

iOS--各种样式的二维码生成_第5张图片
带logo不切圆角的二维码

  但如果我们需要切圆角而且设计的漂亮点的的话,则需要额外处理,首先处理logo图片,分为五个步骤:

1.先对画布进行裁切
2.填充背景颜色
3.执行绘制logo
4.添加并绘制白色边框
5.白色边框的基础上进行绘制黑色分割线

代码如下:

+ (UIImage *)clipCornerRadius:(UIImage *)image withSize:(CGSize) size{
    
    // 白色border的宽度
    CGFloat outerWidth = size.width/15.0;
    // 黑色border的宽度
    CGFloat innerWidth = outerWidth/10.0;
    // 设置圆角
    CGFloat corenerRadius = size.width/5.0;
    // 为context创建一个区域
    CGRect areaRect = CGRectMake(0, 0, size.width, size.height);
    UIBezierPath *areaPath = [UIBezierPath bezierPathWithRoundedRect:areaRect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(corenerRadius, corenerRadius)];  
    // 因为UIBezierpath划线是双向扩展的 初始位置就不会是(0,0)
    // origin position
    CGFloat outerOrigin = outerWidth/2.0;
    CGFloat innerOrigin = innerWidth/2.0 + outerOrigin/1.2;
    CGRect outerRect = CGRectInset(areaRect, outerOrigin, outerOrigin);
    CGRect innerRect = CGRectInset(outerRect, innerOrigin, innerOrigin);
    //  外层path
    UIBezierPath *outerPath = [UIBezierPath bezierPathWithRoundedRect:outerRect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(outerRect.size.width/5.0, outerRect.size.width/5.0)];
    //  内层path
    UIBezierPath *innerPath = [UIBezierPath bezierPathWithRoundedRect:innerRect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(innerRect.size.width/5.0, innerRect.size.width/5.0)];
    // 创建上下文
    UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);{
        // 翻转context
        CGContextTranslateCTM(context, 0, size.height);
        CGContextScaleCTM(context, 1, -1);
        // 1.先对画布进行裁切
        CGContextAddPath(context, areaPath.CGPath);
        CGContextClip(context);
        // 2.填充背景颜色
        CGContextAddPath(context, areaPath.CGPath);
        UIColor *fillColor = [UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1];
        CGContextSetFillColorWithColor(context, fillColor.CGColor);
        CGContextFillPath(context);
        // 3.执行绘制logo
        CGContextDrawImage(context, innerRect, image.CGImage);
        // 4.添加并绘制白色边框
        CGContextAddPath(context, outerPath.CGPath);
        CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
        CGContextSetLineWidth(context, outerWidth);
        CGContextStrokePath(context);
        // 5.白色边框的基础上进行绘制黑色分割线
        CGContextAddPath(context, innerPath.CGPath);
        CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
        CGContextSetLineWidth(context, innerWidth);
        CGContextStrokePath(context);
    }CGContextRestoreGState(context);
    UIImage *radiusImage  = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return radiusImage;
}

经过上面的代码我们实现了白色边框黑色分割线的logo,完成了对logo的处理,当然你想设计自己的形式也是可以的。
处理好了logo,接下来就要把logo绘制到二维码上了,一般头像大小不能大于画布的1/4 。因为这个大小之内的不会遮挡二维码的有效信息,代码如下:

+ (UIImage *)imageWithQRImage:(UIImage *)qrImage logo:(UIImage *)logo logoSize:(CGSize)size{
    
    
    BOOL opaque = 1.0;
    // 获取当前设备的scale
    CGFloat scale = [UIScreen mainScreen].scale;
    // 创建画布Rect
    CGRect bgRect = CGRectMake(0, 0, size.width, size.height);
    // 头像大小不能大于画布的1/4 (这个大小之内的不会遮挡二维码的有效信息)
    CGFloat logoWidth = (size.width/4);
    CGFloat logoHeight = logoWidth;
    //调用一个新的切割绘图方法(裁切头像图片为圆角,并添加bored   返回一个newimage)
    logo = [self clipCornerRadius:logo withSize:CGSizeMake(logoWidth, logoHeight)];
    // 设置头像的位置信息
    CGPoint position = CGPointMake(size.width/2, size.height/2);
    CGRect logoRect = CGRectMake(position.x-(logoWidth/2), position.y-(logoHeight/2), logoWidth, logoHeight);
    // 设置画布信息
    UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);{// 开启画布
    // 翻转context (画布)
    CGContextTranslateCTM(context, 0, size.height);
    CGContextScaleCTM(context, 1, -1);
    // 根据 bgRect 用二维码填充视图
    CGContextDrawImage(context, bgRect, qrImage.CGImage);
    //  根据newAvatarImage 填充头像区域
    CGContextDrawImage(context, logoRect, logo.CGImage);
    }CGContextRestoreGState(context);// 提交画布
    // 从画布中提取图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    // 释放画布
    UIGraphicsEndImageContext();
    return image;
}

最终合成传递多参数的方法:

+ (UIImage *)createQRImageWithContent:(NSString *)content size:(CGSize)size red:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue withLogo:(UIImage *)logo{
    
    UIImage *image = [self createQRImageWithContent:content size:size red:red green:green blue:blue];
    //为空则返回
    if (!logo) { return image;}
    
    UIImage *resultImage = [self imageWithQRImage:image logo:logo logoSize:logo.size];
    
    
    return resultImage;
}

该方法包含前面所介绍的三种样式的二维码,需要logo则传logo,需要自定义颜色则传rgb值;效果图如下(明显比对logo不处理时好看):

iOS--各种样式的二维码生成_第6张图片
带logo的二维码

  以上就是二维码显示的一般样式处理!如有其它则特殊处理某部分,万变不离其宗!学会了怎么生成,不如再学习下 iOS--二维码的扫描

声明: 转载请注明出处http://www.jianshu.com/p/52abb62d0d39

你可能感兴趣的:(iOS--各种样式的二维码生成)