二维码的扫描和生成原生实现

一、识别过程

主要说我们目前经常接触到的二维码,它在系统中格式的标志位QR。二维码的比起条形码是多了是多了一个维度,二维码在水平和垂直方向上都可以进行。仔细看二维码是由一个黑白的小方块组成,黑白小方块的排列代表了我们所需要的信息。简单的来说,二维码实际上也是展现的一个二进制的信息。只不过这些二进制信息变为以黑白方块代替。对于QR类型的二维码,它的三个角是有对应的一个大黑正方形的,它是用来做定位的。所以不论我们手机扫描方向,都可以正确的识别。

如果我们要实现一个二维码扫描,它的整个过程我们需要改:

1、配置系统硬件也就是摄像头,这其中很重要的一点就是设置数据输出(将摄像头捕捉到的数据)。我们需要拿到摄像头的实时数据,并设置它的输出格式为二维码元数据类型。系统提供了相关的代理,在代理方法中我们可以拿到我们设置好的摄像头输出的数据。当我们配置好摄像头后,最重要的是设置AVCaptureMetadataOutput输出类,和实现它的代理。

AVCaptureMetadataOutput的配置:

此方法将摄像头捕捉到的预览层画面返回,只需要将AVCaptureVideoPreviewLayer添加到UIVIew的Layer上即可看到画面。
关于预览层和配置摄像头中出现的其余类的解释,看前面的博客可以找的到
 -(AVCaptureVideoPreviewLayer *)configurationDeviceAddToView:(UIView *)withView{
    
    //初始化捕捉设备,并配置类型。
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    //使用captureDevice创建输入流
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil];
    //输出流
    AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
    
    //范围输出的范围
    captureMetadataOutput.rectOfInterest = CGRectMake(0.2f, 0.2f, 0.8f, 0.8f);
    _captureSession = [[AVCaptureSession alloc] init];
    //添加输入输出
    if ([_captureSession canAddInput:input] && [_captureSession canAddOutput:captureMetadataOutput]) {
        
        [_captureSession addInput:input];
        [_captureSession addOutput:captureMetadataOutput];

    }
    
    //输出代理
    [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    //设置输出媒体数据类型为QRCode类型的二维码,同时还可以添加更多的类型,比如条形码,Aztec类型的二维码等
    [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
    
    //预览层配置
    _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [_videoPreviewLayer setFrame:withView.bounds];
    
    //开始
    [_captureSession startRunning];
    
    return _videoPreviewLayer;
}

获得数据的代理方法中

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    
    //判断是否有数据
    if (metadataObjects != nil && [metadataObjects count] > 0) {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        
        //判断回传的数据类型
        if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            //此处是一个简单的判断网址,是的话就加载网址
            NSRange range4 = NSMakeRange(0, 4);
            NSRange range3 = NSMakeRange(0, 3);
            
            NSString *string3 = [[metadataObj stringValue] substringWithRange:range3];
            NSString *string4 = [[metadataObj stringValue] substringWithRange:range4];
            
            //判断是否为网址,如果是就调用浏览器打开
            if ([string4 isEqualToString:@"http"] || [string3 isEqualToString:@"www"]) {
                
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[metadataObj stringValue]]];

            }else {
                
                将信息展示或者其他动作
            }
        }
    }
}

处理二维码或者条形码时出现的AVCaptureMetadataOutput其实在代理中是一个个的AVMetadataObjectTypeQRCode实例。这个对象定义了一个StringValue 属性用于提供码的实际数据值,此外还定义了两个属性用于表示码的集合特征(代码中并没有使用)bounds和corners。bounds提供了按坐标对齐的边界,corners提供了角字典表示的NSArray.

二、二维码创建过程

比如我们需要将一串字符转换成二维码的形式,我们在拿到字符后通过一个在图片处理中过程中需要使用到Core Image框架中最重要的几个类:

a、CIContext: 所有图像处理都是在它中完成的,类似于coreData中的上下文,或者将它位置理解成一辆车的发动机。
b、CIImage:它是可以从像素数据、UIImage图片、图像文件中提取出来。保存图形的数据信息。
c、CIFilter.:滤镜有很多种,我们在实现二维码生成中就使用到了一种。各种滤镜有对应的属性。我们通过设置属性得到我们想要的效果。如剪裁滤镜、色彩反转滤镜等等。

二维码是一串二进制信息。我们将字符转换成data类型,通过设置滤镜得到对应的CIImage,最后将CIImage转换为UIImage。

得到CIImage

-(void)configuration {
    
    self.imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 150, 150)];
    self.imageView.center = self.view.center;
    [self.view addSubview:self.imageView];
    
    //创建一个二维码的滤镜
    CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    //恢复滤镜的默认属性
    [filter setDefaults];
    //将字符串转换成NSData
    NSData *data = [self.textVie.text dataUsingEncoding:NSUTF8StringEncoding];
    //赋给滤镜数据
    [filter setValue:data forKey:@"inputMessage"];
    //获得滤镜输出的图像
    CIImage *outputImage=[filter outputImage];
    
    //将CIImage转换成UIImage,然后放大
    self.imageView.image=[self image:outputImage forSize:150];
}

转化过程

//将CIiamge转化为UIimage,并设置尺寸
- (UIImage *)image:(CIImage *)image forSize:(CGFloat) size {
    
    //返回一个整数,将矩形的值转变成整数,得到一个最小的矩形
    CGRect rect = CGRectIntegral(image.extent);
    //得到宽长比
    CGFloat scale = MIN(size/CGRectGetWidth(rect), size/CGRectGetHeight(rect));
    
    // 创建位图;
    size_t width  = CGRectGetWidth(rect) * scale;
    size_t height = CGRectGetHeight(rect) * scale;
    CGColorSpaceRef ref    = CGColorSpaceCreateDeviceGray();
    //配置bitmap
    CGContextRef contxteRef = CGBitmapContextCreate(nil, width, height, 8, 0, ref, (CGBitmapInfo)kCGImageAlphaNone);
    CIContext *ci = [CIContext contextWithOptions:nil];
    CGImageRef bitmap = [ci createCGImage:image fromRect:rect];
    CGContextSetInterpolationQuality(contxteRef, kCGInterpolationNone);
    CGContextScaleCTM(contxteRef, scale, scale);
    CGContextDrawImage(contxteRef, rect, bitmap);
    
    // 转换为图片
    CGImageRef scaledImage = CGBitmapContextCreateImage(contxteRef);
    CGContextRelease(contxteRef);
    CGImageRelease(bitmap);
    return [UIImage imageWithCGImage:scaledImage];
}

 

转载于:https://my.oschina.net/zhengjianhua/blog/698680

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值