一、识别过程
主要说我们目前经常接触到的二维码,它在系统中格式的标志位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];
}