美文网首页iOS 开发每天分享优质文章
iOS封装二维码的扫描和生成,可直接使用

iOS封装二维码的扫描和生成,可直接使用

作者: 丶人挫脸丑农村户口 | 来源:发表于2016-07-27 12:04 被阅读362次

    二维码可以很方便的分享一些信息而广泛使用,很多app也就有了生成二维码和扫瞄二维码的需求了,所以用到的地方不少, 再正常不过的一个功能了,早期开发的时候可能使用过ZBar或者ZXing这两个相对古老的第三方,在苹果没有开发原生二维码扫描和生成的时候,这两个第三方也给我们带来了很多方便,对于现在这两个使用的频率也不高了,因为苹果原生的意见有很高的效率了。

    效果实现

    二维码的生成
    • 不带Logo图标的二维码
      -> 导入 #import "JYErWeiCode.h" 头文件
     JYErWeiCode *erWeiCode = [[JYErWeiCode alloc] init];
        
        erWeiCode.source = @"http://www.jianshu.com/p/47bcb0422c4a";   // 设置二维码存储的资源信息
        //erWeiCode.erWeiCodeColor = setColor(56, 34, 230);    // 设置二维码的颜色,默认是黑白
       
        self.imgView.image = [erWeiCode erWeiCode];    // 生成一张高清的二维码图片,显示出来
    
    默认生成二维码黑白颜色.png
    erWeiCode.marginColor = [UIColor cyanColor];      // 自定义设置二维码的颜色
    
    自定义二维码颜色效果.png
    • 带Logo图标的二维码(基本上带有logo图片都会设置圆角)
    JYErWeiCode *erWeiCode = [[JYErWeiCode alloc] init];
        
        erWeiCode.source = @"http://www.jianshu.com/p/47bcb0422c4a";
        erWeiCode.logo = @"IMG_6396";                      // logo图片资源
        erWeiCode.rounde = 20.0f;                          // 图片圆角大小
        erWeiCode.margin = 4.0f;                           // 外边框的宽度
        erWeiCode.erWeiCodeColor = [UIColor cyanColor];
        erWeiCode.marginColor = [UIColor cyanColor];       // 外边框的颜色
        
        self.imgView.image = [erWeiCode erWeiCode];
    
    带logo图标的二维码.png

    !注意:在自定义的时候logo图片的大小不能过大,过大会遮住一下二维码的扫描位置从而影响二维码的扫描

    二维码的扫描

    -> 在控制器导入#import "JYScanErWeiCode.h" 、#import "JYPreviewView.h"
    1.创建一个相机捕获会话的view

    - (JYPreviewView *)previewView
    {
        if (!_previewView) {
            
            _previewView = [[JYPreviewView alloc] init];
            _previewView.cornerColor = [UIColor cyanColor];    // 设置四个角边框的颜色
            
            [self.view addSubview:_previewView];
        }
        return _previewView;
    }
    

    2.加载二维码扫描

    // 懒加载二维码扫描
    - (JYScanErWeiCode *)scanErWeiCode
    {
        if (!_scanErWeiCode) {
            
            _scanErWeiCode = [[JYScanErWeiCode alloc] initWithPreviewView:self.previewView];
            
            _scanErWeiCode.delegate = self;
        }
        return _scanErWeiCode;
    }
    

    3.开启相机扫描

    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        [self.scanErWeiCode startSession];
    }
    

    4.当控制器消耗时关闭相机

    - (void)viewDidDisappear:(BOOL)animated
    {
        [super viewDidDisappear:animated];
        [self.scanErWeiCode stopSession];
    }
    

    5.设置JYScanErWeiCodeDelegate的代理方法

    - (void)erWeiCodeScanStringValue:(NSString *)str
    {
        NSLog(@"扫描结果:%@", str);
        JYWebController *webCtl = [[JYWebController alloc] init];
        webCtl.urlStr = str;
        
        [self.navigationController pushViewController:webCtl animated:YES];
    }
    

    效果展示

    GIF.gif

    具体代码实现

    -> source 在创建生成二维码的对象时,一定要有值

    - (UIImage *)erWeiCode
    {
        if (self.source) {
            // 1.生成清晰的二维码图片
            UIImage *imgQRCode = [self createQRCodeImage:self.source];
            
            // 2.设置二维码的颜色 (默认是黑色)
            imgQRCode = [JYErWeiCode specialColorImage:imgQRCode color:self.erWeiCodeColor];
            
            // 3.生成一张有圆角外边框的logo图片
            UIImage *logoImg = [self createRoundeLogo];
            
            if (logoImg) {   // 如果需要设置logo图片
                // 4.合成一张有logo图标的二维码
                UIImage *needImg = [self addIconToQRCodeImage:imgQRCode icon:logoImg];
                
                return needImg;
                
            } else      // 不需要设置logo图片
            {
                return imgQRCode;
            }
        } else
        {
            NSLog(@"Error: source= nil,你创建了一个空的二维码,请设置二维码的内容");
            return nil;
        }
    }
    
    - (UIImage *)createRoundeLogo
    {
        if (self.logo.length) {
            if (self.rounde > 0) {
                // 1.生成一张圆角logo图片
                UIImage *logoImg = [self imageRoundeImage:[UIImage imageNamed:self.logo] rounde:self.rounde];
                
                if (self.margin > 0) {
                    // 2.生成一张有外边框的logo图片 (默认外边框颜色为白色)
                    UIColor *marginColor = (self.marginColor == NULL) ? [UIColor whiteColor] : self.marginColor;
                    UIImage *marginImg = [self imageAddColorBorder:logoImg color:marginColor margin:self.margin];
                    
                    // 3.设置有外边框logo图片的圆角
                    UIImage *mLogo = [self imageRoundeImage:marginImg rounde:self.rounde];
                    
                    return mLogo;
                } else {
                    return logoImg;
                }
            } else {
                return [UIImage imageNamed:self.logo];
            }
        } else {
            return nil;
        }
    }
    
    
    对图片处理的操作

    描述:使用iOS 7后的CIFilter对象操作,生成二维码图片imgQRCode(会拉伸图片,比较模糊,效果不佳, 使用核心绘图框架CG(Core Graphics)对象操作,进一步针对大小生成二维码图片imgAdaptiveQRCode(图片大小适合,清晰,效果好)
    source: 二维码中的数据可以是字符串和URL两种类型, 如果我们想要生成URL的二维码, 只需要把字符串替换为一个URL字符串即可
    rate: 越大,越清晰(未提供接口,默认50.0, 如果需要更高清的, 可修改这个值)

    - (UIImage *)createQRCodeImage:(NSString *)source
    {
        // 1. 给滤镜添加数据
        NSData *data = [source dataUsingEncoding:NSUTF8StringEncoding];
        
        // 2. 创建一个二维码滤镜实例(CIFilter)
        CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
        [filter setValue:data forKey:@"inputMessage"];
        [filter setValue:@"H" forKey:@"inputCorrectionLevel"];
        
        // 3.生成一张清晰度不高的二维码
        UIImage *image = [UIImage imageWithCIImage:filter.outputImage
                                             scale:1.0
                                       orientation:UIImageOrientationUp];
        
        // 4.对图片做处理, 使图片大小合适,清晰,效果好
        CGFloat width = image.size.width * 50.0;
        CGFloat height = image.size.height * 50.0;
        
        UIGraphicsBeginImageContext(CGSizeMake(width, height));
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetInterpolationQuality(context, kCGInterpolationNone);
        [image drawInRect:CGRectMake(0, 0, width, height)];
        UIImage *needImg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return  needImg;
    }
    

    默认产生的黑白色的二维码图片;我们可以让它产生其它颜色的二维码图片,例如:蓝白色的二维码图片
    color: 设置二维码的颜色

    + (UIImage *)specialColorImage:(UIImage *)image color:(UIColor *)color
    {
        CGFloat components[3];
        [JYErWeiCode getRGBComponents:components forColor:color];
        
        const CGFloat imageW = image.size.width;
        const CGFloat imageH = image.size.height;
        
        size_t bytesPerRow = imageW * 4;
        uint32_t *rgbImageBuf = (uint32_t *)malloc(bytesPerRow *imageH);
        
        CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
        
        CGContextRef contextRef = CGBitmapContextCreate(rgbImageBuf, imageW, imageH, 8, bytesPerRow, colorSpaceRef, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
        
        CGContextDrawImage(contextRef, CGRectMake(0, 0, imageW, imageH), image.CGImage);
        CGFloat pixelNum = imageW * imageH;
        uint32_t *pCurPtr = rgbImageBuf;
        for (int i = 0; i < pixelNum; i ++, pCurPtr ++) {
            if ((*pCurPtr & 0xFFFFFF00) < 0x99999900) {
                
                uint8_t *ptr = (uint8_t *)pCurPtr;
                ptr[3] = components[0];
                ptr[2] = components[1];
                ptr[1] = components[2];
            } else {
                uint8_t *ptr = (uint8_t *)pCurPtr;
                ptr[0] = 0;
            }
        }
        
        CGDataProviderRef dataProviderRef = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageH, preoviderReleaseData);
        
        CGImageRef imageRef = CGImageCreate(imageW, imageH, 8, 32, bytesPerRow, colorSpaceRef, kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProviderRef, NULL, true, kCGRenderingIntentDefault);
        CGDataProviderRelease(dataProviderRef);
        
        UIImage *img = [UIImage imageWithCGImage:imageRef];
        
        CGImageRelease(imageRef);
        CGContextRelease(contextRef);
        CGColorSpaceRelease(colorSpaceRef);
        
        return img;
    }
    

    设置图片的圆角
    rounde: 设置圆角大小
    注明:在这设置的图片在圆角周围有羽化的现象,不知道啥情况,有大神知道可留言一下,谢谢

    - (UIImage *)imageRoundeImage:(UIImage *)image rounde:(CGFloat)rounde
    {
        CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
        
        UIGraphicsBeginImageContextWithOptions(image.size, NO, 1.0);
        
        [UIBezierPath bezierPathWithRect:rect];
        [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, image.size.width, image.size.height) cornerRadius:rounde] addClip];
        
        [image drawInRect:rect];
        
        UIImage *needImg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return needImg;
    }
    

    给图片添加不同颜色的边框
    color: 外边框颜色
    margin: 外边框大小

    - (UIImage *)imageAddColorBorder:(UIImage *)image color:(UIColor *)color margin:(CGFloat)margin
    {
        CGFloat imageW = image.size.width;
        CGFloat imageH = image.size.height;
        CGFloat colorW = imageW + margin * 2;
        CGFloat colorH = imageH + margin * 2;
        
        // 用颜色来转换成一张图片
        UIImage *colorImg = [JYErWeiCode imageWithColor:color size:CGSizeMake(colorW, colorH)];
        
        UIGraphicsBeginImageContext(colorImg.size);
        
        [colorImg drawInRect:CGRectMake(0, 0, colorW, colorH)];
        [image drawInRect:CGRectMake(margin, margin, imageW, imageH)];
        
        UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
        
        UIGraphicsEndImageContext();
        
        return img;
    }
    

    两张图片合成一张
    image: 二维码
    icon: 中间Logo图标

    - (UIImage *)addIconToQRCodeImage:(UIImage *)image icon:(UIImage *)icon
    {
        UIGraphicsBeginImageContext(image.size);
        
        CGFloat imageW = image.size.width;
        CGFloat imageH = image.size.height;
        CGFloat iconW = imageW * 0.25;
        CGFloat iconH = imageH * 0.25;
        
        [image drawInRect:CGRectMake(0, 0, imageW, imageH)];
        [icon drawInRect:CGRectMake((imageW - iconW) * 0.5, (imageH - iconH) * 0.5, iconW, iconH)];
        
        UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
        
        UIGraphicsEndImageContext();
        
        return img;
    }
    

    扫描代码实现

    • 初始化相机会话 (一开始最好判断有没有相机权限,没有的话跳转到设置中设置允许使用相机,当前没有做着个处理)
    - (void)initSession
    {
        self.captureSession = [[AVCaptureSession alloc] init];
        
        // Setup the preview view.
        self.previewView.session = self.captureSession;
        
        // 与此队列中的会话和其他会话对象进行通信
        self.sessionQueue = dispatch_queue_create( "session queue", DISPATCH_QUEUE_SERIAL );
        
        // 设置捕追会话
        // 一般来说是不安全的 AVCaptureSession 突变 或 其任何输入,输出,或连接多个线程,在同一时间
        dispatch_async( self.sessionQueue, ^{
            
            NSError *error = nil;
            AVCaptureDevice *videoDevice = [JYScanErWeiCode deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
            AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
            
            if ( ! videoDeviceInput ) {
                NSLog( @"Could not create video device input: %@", error );
            }
            
            [self.captureSession beginConfiguration];
            
            if ( [self.captureSession canAddInput:videoDeviceInput] ) {
                [self.captureSession addInput:videoDeviceInput];
                self.deviceInput = videoDeviceInput;
                
                AVCaptureDevice *currentVideoDevice = self.deviceInput.device;
                self.captureDevice = currentVideoDevice;
            } else
            {
                // 无法将视频设备输入到会话中
                NSLog( @"Could not add video device input to the session" );
            }
            
            dispatch_async( dispatch_get_main_queue(), ^{
                
                AVCaptureVideoPreviewLayer *previewLayer = (AVCaptureVideoPreviewLayer *)self.previewView.layer;
                previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
            });
            
            
            self.metadataOutput = [[AVCaptureMetadataOutput alloc]init];
            [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
            
            if ([self.captureSession canAddOutput:self.metadataOutput]) {
                [self.captureSession addOutput:self.metadataOutput];
            }
            
            // 条码类型 AVMetadataObjectTypeQRCode
            self.metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
            
            [self.captureSession commitConfiguration];
        });
    }
    
    • 设置AVCaptureMetadataOutput代理
    • AVCaptureMetadataOutputObjectsDelegate获取扫描的信息
    #pragma mark AVCaptureMetadataOutputObjectsDelegate
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
    {
        NSString *stringValue;
        
        if ([metadataObjects count] >0){
            AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
            stringValue = metadataObject.stringValue;
            
            if (self.delegate && [self.delegate respondsToSelector:@selector(erWeiCodeScanStringValue:)]) {
                [self.delegate erWeiCodeScanStringValue:stringValue];
            }
            [self stopSession];
        }
    }
    

    Demo代码还还有完善好,等完善好在上传

    相关文章

      网友评论

        本文标题:iOS封装二维码的扫描和生成,可直接使用

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