zoukankan      html  css  js  c++  java
  • 二维码的扫描、识别与生成

    详细易懂的二维码的扫描、识别与生成。

    ios7之前我们实现二维码扫描是借助第三方(ZBarZXing等)来实现的,在ios7之后系统自己提供二维码扫描的方法,性能也要比第三方更好。

    今天就来介绍一下原生二维码的使用,包括扫描二维码从图片扫描二维码生成二维码。讲解中只展示部分代码,具体请看Github Demo,里面的代码不多,也很容易看懂。

    扫描二维码

    二维码扫描需要用到AVFoundation.framework,需要用先创建一个AVCaptureSession,然后设置输入输出流,以及扫描区域和支持的格式:

    //获取摄像设备
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //创建输入流
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    if (!input)
    {
        return nil;
    }
    
    //创建输出流
    AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
    //设置代理 在主线程里刷新
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    //设置扫描区域的比例
    CGFloat width = 300 / CGRectGetHeight(self.view.frame);
    CGFloat height = 300 / CGRectGetWidth(self.view.frame);
    output.rectOfInterest = CGRectMake((1 - width) / 2, (1- height) / 2, width, height);
    
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    //高质量采集率
    [session setSessionPreset:AVCaptureSessionPresetHigh];
    [session addInput:input];
    [session addOutput:output];
    
    //设置扫码支持的编码格式(这里设置条形码和二维码兼容)
    output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
                                   AVMetadataObjectTypeEAN13Code,
                                   AVMetadataObjectTypeEAN8Code,
                                   AVMetadataObjectTypeCode128Code];

    然后用这个session生成一个AVCaptureVideoPreviewLayer加到某个view的layer上,就可以实时显示摄像头捕捉的内容了:

    AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    layer.frame = self.view.layer.bounds;
    [self.view.layer insertSublayer:layer atIndex:0];

    然后调用[self.session startRunning];开始捕获,当扫描出结果后会调用下面的代理方法,其中metadataObject.stringValue就是扫描后的结果。

    #pragma mark - AVCaptureMetadataOutputObjectsDelegate
    -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
    {
        if (metadataObjects.count > 0)
        {        
            AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects firstObject];
        }
    }

    为了在黑夜也可以很好的扫描,可以设置一个闪光灯的开关:

    #pragma mark - 开关闪光灯
    - (void)rightBarButtonDidClick:(UIBarButtonItem *)item
    {
        self.flashOpen = !self.flashOpen;
    
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
        if ([device hasTorch] && [device hasFlash])
        {
            [device lockForConfiguration:nil];
    
            if (self.flashOpen)
            {
                device.torchMode = AVCaptureTorchModeOn;
                device.flashMode = AVCaptureFlashModeOn;
            }
            else
            {
                device.torchMode = AVCaptureTorchModeOff;
                device.flashMode = AVCaptureFlashModeOff;
            }
    
            [device unlockForConfiguration];
        }
    }

    扫描二维码

    从图片扫描

    有时候我们需要从图片中扫描二维码,或者从相册选择一张图片,代码如下,具体可以看demo。其中feature.messageString就是扫描后的结果。

    - (void)findQRCodeFromImage:(UIImage *)image
    {
        CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode
                                                  context:nil
                                                  options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
    
        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
        if (features.count >= 1)
        {
            CIQRCodeFeature *feature = [features firstObject];
        }
    }

    从图片扫描

    生成二维码

    生成二维码的代码很简单,代码如下。

    /** 生成指定大小的黑白二维码 */
    - (UIImage *)createQRImageWithString:(NSString *)string size:(CGSize)size
    {
        NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
    
        CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
        //    NSLog(@"%@",qrFilter.inputKeys);
        [qrFilter setValue:stringData forKey:@"inputMessage"];
        [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"];
    
        CIImage *qrImage = qrFilter.outputImage;
        //放大并绘制二维码 (上面生成的二维码很小,需要放大)
        CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent];
        UIGraphicsBeginImageContext(size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetInterpolationQuality(context, kCGInterpolationNone);
        //翻转一下图片 不然生成的QRCode就是上下颠倒的
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
        UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        CGImageRelease(cgImage);
    
        return codeImage;
    }

    黑白二维码

    上面默认生成的时黑白二维码,不过我们也可以改颜色:

    /** 为二维码改变颜色 */
    - (UIImage *)changeColorForQRImage:(UIImage *)image backColor:(UIColor *)backColor frontColor:(UIColor *)frontColor
    {
        CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"
                                           keysAndValues:
                                 @"inputImage",[CIImage imageWithCGImage:image.CGImage],
                                 @"inputColor0",[CIColor colorWithCGColor:frontColor.CGColor],
                                 @"inputColor1",[CIColor colorWithCGColor:backColor.CGColor],
                                 nil];
    
        return [UIImage imageWithCIImage:colorFilter.outputImage];
    }

    为二维码改变颜色

    有的二维码也会在中心加一个小图片,例如用户头像,代码如下:

    /** 在二维码中心加一个小图 */
    - (UIImage *)addSmallImageForQRImage:(UIImage *)qrImage
    {
        UIGraphicsBeginImageContext(qrImage.size);
        [qrImage drawInRect:CGRectMake(0, 0, qrImage.size.width, qrImage.size.height)];
        UIImage *image = [UIImage imageNamed:@"small"];
        CGFloat imageW = 50;
        CGFloat imageX = (qrImage.size.width - imageW) * 0.5;
        CGFloat imgaeY = (qrImage.size.height - imageW) * 0.5;
        [image drawInRect:CGRectMake(imageX, imgaeY, imageW, imageW)];
        UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return result;
    }

    中心加小图的二维码

    其实也可以扫描条形码,大家可以对着条形码试一试,代码都是通用的。

  • 相关阅读:
    IDEA下同时使用Git和svn
    IDEA进行activiti-archetype-unittest脚手架的安装
    正则表达式
    关于JS堆栈与拷贝
    按值传递--
    JS---变量、作用域和内存问题
    laod
    待解决
    闭包2
    闭包1
  • 原文地址:https://www.cnblogs.com/zyjzyj/p/6029982.html
Copyright © 2011-2022 走看看