ios开发-OC使用CIFilter生成二维码图片

作者: 夜半敲门话不语 | 来源:发表于2016-09-26 19:18 被阅读1412次

    二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型:比如:字符,数字,日文,中文等等。

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

    • 使用CIFilter滤镜类生成二维码
    • 对生成的二维码进行加工,使其更清晰
      经过上面两步得到会得到原始的二维码图片,在这基础上可以进行以下个性化定制
    • 自定义二维码背景色、填充色
    • 自定义定位角标
    • 在二维码中心插入小图片

    二维码生成

    本文通过类的方式来生成个性化二维码定制。

    初始化二维码信息尺寸和默认值

    - (instancetype)init
    {
        if (self = [super init]) {
            //默认值
            _info = @"http://mkiltech.com";
            _backgroundColor = [UIColor whiteColor];
            _fillColor = [UIColor blackColor];
        }
        return self;
    }
    
    - (void)setInfo:(NSString *)info withSize:(CGFloat)size
    {
        _info = info;
        
        CGFloat scale = [UIScreen mainScreen].scale;
        CGRect rect = CGRectMake(0, 0, size, size);
        _size = CGRectGetWidth(rect) * scale;
    
    }
    

    使用CIFilter滤镜类生成二维码

    - (void)generateQRCodeFilter
    {
        CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
        [filter setDefaults];
        NSData *data = [_info dataUsingEncoding:NSUTF8StringEncoding];
        [filter setValue:data forKey:@"inputMessage"];              //通过kvo方式给一个字符串,生成二维码
        [filter setValue:@"H" forKey:@"inputCorrectionLevel"];      //设置二维码的纠错水平,越高纠错水平越高,可以污损的范围越大
        
        //设置背景颜色和填充颜色 默认白色背景黑色填充
        
        CIColor *color1 = [CIColor colorWithCGColor:_fillColor.CGColor];
        CIColor *color2 = [CIColor colorWithCGColor:_backgroundColor.CGColor];
        NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys: filter.outputImage ,@"inputImage",
                                    color1,@"inputColor0",
                                    color2,@"inputColor1",nil];
        CIFilter *newFilter = [CIFilter filterWithName:@"CIFalseColor" withInputParameters:parameters];
        
        _outPutImage = [newFilter outputImage];                     //拿到二维码图片
    }
    

    对生成的二维码进行加工,使其更清晰

    - (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat) size {
        CGRect extent = CGRectIntegral(image.extent);
        CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
        
        // 1.创建bitmap;
        size_t width = CGRectGetWidth(extent) * scale;
        size_t height = CGRectGetHeight(extent) * scale;
        //创建一个DeviceRGB颜色空间
        CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
        //CGBitmapContextCreate(void * _Nullable data, size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow, CGColorSpaceRef  _Nullable space, uint32_t bitmapInfo)
        //width:图片宽度像素
        //height:图片高度像素
        //bitsPerComponent:每个颜色的比特值,例如在rgba-32模式下为8
        //bitmapInfo:指定的位图应该包含一个alpha通道。
    
        CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
        CIContext *context = [CIContext contextWithOptions:nil];
        //创建CoreGraphics image
        CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
        
        CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
        CGContextScaleCTM(bitmapRef, scale, scale);
        CGContextDrawImage(bitmapRef, extent, bitmapImage);
        
        // 2.保存bitmap到图片
        CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
        CGContextRelease(bitmapRef); CGImageRelease(bitmapImage);
        
        //原图
        UIImage *outputImage = [UIImage imageWithCGImage:scaledImage];
        return outputImage;
    }
    

    获取二维码定位图案位置

    二维码一共有40个尺寸。官方叫版本Version。Version 1是21 x 21的矩阵,Version 2是 25 x 25的矩阵,Version 3是29的尺寸,每增加一个version,就会增加4的尺寸,公式是:(V-1)4 + 21(V是版本号) 最高Version 40,(40-1)4+21 = 177,所以最高是177 x 177 的正方形。

    下面我们看看一个二维码的样例:


    QR-Code-Overview.jpeg

    定位图案

    • Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。
    • Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。
    • Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。

    功能性数据

    • Format Information 存在于所有的尺寸中,用于存放一些格式化数据的。
    • Version Information 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。

    数据码和纠错码

    • 除了上述的那些地方,剩下的地方存放 Data Code 数据码 和 Error Correction Code 纠错码。

    获取Version

    - (CGFloat)fetchVersion {
        
        return ((_outPutImage.extent.size.width - 21)/4.0 + 1);
    }
    

    换算成绘制坐标

    定位图案外层坐标

    - (UIBezierPath *) outerPositionPathWidth:(CGFloat)width withVersion:(CGFloat )version wihtPosition:(MKQRPosition) position
    {
        CGFloat zonePathWidth = width/((version - 1) * 4 + 21);
        CGFloat positionFrameWidth = zonePathWidth * outerPositionPathOriginLength;
        CGPoint topLeftPoint = CGPointMake(zonePathWidth * 1.5, zonePathWidth * 1.5);
        CGRect rect = CGRectMake(topLeftPoint.x - 0.2, topLeftPoint.y - 0.2, positionFrameWidth, positionFrameWidth);
        
        rect = CGRectIntegral(rect);
        rect = CGRectInset(rect, 1, 1);
        UIBezierPath *path;
        CGFloat offset;
        switch (position) {
            case TopLeft:
                
                path = [UIBezierPath bezierPathWithRect:rect];
                path.lineWidth = zonePathWidth + 1.5;
                path.lineCapStyle = kCGLineCapSquare;
                break;
            case TopRight:
                
                offset = width - positionFrameWidth - topLeftPoint.x * 2;
                rect = CGRectOffset(rect, offset, 0);
                path = [UIBezierPath bezierPathWithRect:rect];
                path.lineWidth = zonePathWidth + 1.5;
                path.lineCapStyle = kCGLineCapSquare;
                break;
            case BottomLeft:
                
                offset = width - positionFrameWidth - topLeftPoint.x * 2;
                rect = CGRectOffset(rect, 0, offset);
                path = [UIBezierPath bezierPathWithRect:rect];
                path.lineWidth = zonePathWidth + 1.5;
                path.lineCapStyle = kCGLineCapSquare;
                break;
            case QuietZone:
                rect = CGRectMake(zonePathWidth * 0.5, zonePathWidth * 0.5, width - zonePathWidth, width - zonePathWidth);
                path = [UIBezierPath bezierPathWithRect:rect];
                path.lineWidth = zonePathWidth + [UIScreen mainScreen].scale;
                path.lineCapStyle = kCGLineCapSquare;
                break;
            default:
                
                path = [UIBezierPath bezierPath];
                break;
        }
        return path;
        
    }
    

    定位图案内层坐标包括中心图片位置

    - (CGRect)innerPositionRectWidth:(CGFloat )width withVersion:(CGFloat )version wihtPosition:(MKQRPosition) position
    {
        CGFloat leftMargin = width * 3 / ((version - 1) * 4 + 21);
        CGFloat tileWidth = leftMargin;
        CGFloat centerImageWith = width * 7 / ((version - 1) * 4 + 21);
        
        CGRect rect = CGRectMake(leftMargin + 1.5, leftMargin + 1.5, leftMargin - 3, leftMargin - 3);
        rect = CGRectIntegral(rect);
        rect = CGRectInset(rect, -1, -1);
        
        CGFloat offset;
        switch (position) {
            case TopLeft:
                
                break;
            case TopRight:
                
                offset = width - tileWidth - leftMargin*2;
                rect = CGRectOffset(rect, offset, 0);
                break;
            case BottomLeft:
                
                offset = width - tileWidth - leftMargin * 2;
                rect = CGRectOffset(rect, 0, offset);
                break;
            case Center:
                
                rect = CGRectMake(CGPointZero.x, CGPointZero.y, centerImageWith, centerImageWith);
                offset = width/2 - centerImageWith/2;
                rect = CGRectOffset(rect, offset, offset);
                break;
            default:
                rect = CGRectZero;
                break;
        }
        
        return rect;
    }
    

    效果图

    QRCodeRendering.png

    完整代码请前往 https://github.com/ymkil/MKQRCode 如果满意的话,给个星哦!!
    转载请注明出处。

    相关文章

      网友评论

        本文标题:ios开发-OC使用CIFilter生成二维码图片

        本文链接:https://www.haomeiwen.com/subject/gvqqyttx.html