一、生成一个二维码
//1、创建一个二维码滤镜
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator”];
恢复滤镜的默认设置
[filter setDefaults];
//2、设置滤镜输入内容
[filter setValue:data forKey:@"inputMessage”];
//3、直接从二维码滤镜中获取需要的二维码图片
CIImage *outputImage = [filter outputImage];
UIImage * image = [UIImage imageWithCIImage:outputImage];
imageView.image =image;
NSLog(@"%@",NSStringFromCGSize(image.size));
- 1、通过滤镜CIFilter生成二维码
- 2、如果想要给滤镜设置输入数据,只能通过KVC的形式,设置inputMessage。输入的数据,只能是NSData
- 3、直接获取的二维码图片的size是{27, 27},直接在imageView上显示会显得模糊,因此大多数时候我们需要借助位图处理放大图片,获取一个高清图片。
CIImage *outputImage = [filter outputImage];
imageView.image = [self createNonInterpolatedUIImageFormCIImage:outputImage withSize:300];
/**
* 根据CIImage生成指定大小的UIImage
*
* @param image CIImage
* @param size 图片宽度
*/
- (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;
CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
CIContext *context = [CIContext contextWithOptions:nil];
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);
return [UIImage imageWithCGImage:scaledImage];
}
二维码部分被遮挡时,还是被识别的,这是因为二维码是有纠错率(inputCorrectionLevel):L,M,Q,H 。 L水平7%的字码可被修正,M水平15%的字码可被修正,Q水平25%的字码可被修正,H水平30%的字码可被修正。
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *imageView = [[UIImageView alloc]init];
[self.view addSubview:imageView];
imageView.frame = CGRectMake(10, 100, 300, 300);
imageView.backgroundColor = [UIColor redColor];
NSString *str = @"你好,世界”;
NSData*data = [str dataUsingEncoding:NSUTF8StringEncoding];
//1、创建一个二维码滤镜
CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator”];
[filter setDefaults];
//2、设置滤镜输入内容
[filter setValue:data forKey:@"inputMessage”];
[filter setValue:@"H" forKey:@"inputCorrectionLevel”];
//3、直接从二维码滤镜中获取需要的二维码图片
CIImage *outputImage = [filter outputImage];
UIImage *image = [self createNonInterpolatedUIImageFormCIImage:outputImage withSize:300];
UIImage *iconImage = [UIImage imageNamed:@"1”];
UIImage *newImage = [self creatnewImage:image smallImage:iconImage size:60];
imageView.image = newImage;
}
#pragma mark - 多张图重新绘制成一张图
- (UIImage *)creatnewImage:(UIImage*)bigImage smallImage:(UIImage*)smallimage size:(CGFloat)size{
UIGraphicsBeginImageContext(bigImage.size);
[bigImage drawInRect:CGRectMake(0, 0, bigImage.size.width, bigImage.size.height)];
CGFloat x = (bigImage.size.width -size)/2;
CGFloat y = (bigImage.size.height-size)/2;
[smallimage drawInRect:CGRectMake(x, y, size, size)];
UIImage *newImage =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
二、识别图片二维码
//01、创建一个探测器
CIContext *contex = [[CIContext alloc]init];
CIDetector *detecor =[CIDetector detectorOfType:CIDetectorTypeQRCode context:contex options:@{CIDetectorAccuracy :CIDetectorAccuracyHigh}];
//02、直接开始识别图片,获取特征
CIImage *ciImage = [[CIImage alloc]initWithImage:[UIImage imageNamed:@"0”]];
NSArray *features = [detecor featuresInImage:ciImage];
if (features.count>0) {
//03、读取特征
[features enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
CIQRCodeFeature *feature = obj;
NSLog(@"当前当前二维码的内容是%@",feature.messageString);
}];
}else{
NSLog(@"无法识别当前二维码”);
}
三、二维码扫描
3.1、扫描动画
其实实现冲击波的动画效果,就需要一个图片和以下做个简单的动画
qrcode_scanline_qrcode@2x.png
UIImageView *imageView = [[UIImageView alloc]init];
imageView.image = [UIImage imageNamed:@"qrcode_border"];
[self.view addSubview:imageView];
imageView.clipsToBounds = YES;
imageView.frame = CGRectMake(60, 100, 200, 200);
imageView.backgroundColor = [UIColor colorWithRed:255/255.0f green:127/255.0 blue:0/255.f alpha:1];
UIImageView *animationImageView = [[UIImageView alloc]init];
[imageView addSubview:animationImageView];
animationImageView.frame = CGRectMake(0, -imageView.frame.size.height, imageView.frame.size.width, imageView.frame.size.height);
animationImageView.image = [UIImage imageNamed:@"qrcode_scanline_qrcode@2x"];
self.animationImageView = animationImageView;
[self beginAnmition];
- (void)beginAnmition{
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionRepeat animations:^{
self.animationImageView.frame = CGRectMake(0, 0, self.animationImageView.frame.size.width, self.animationImageView.frame.size.height);
} completion:nil];
}
3.2、扫描功能实现
- 1、扫描输出数据
// 1. 获取摄像头设备
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 2. 把摄像头设备当做输入设备
AVCaptureDeviceInput *inputDevice = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
// 3. 设置"元数据"处理, -> 输出
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
// 3.1 设置元数据处理代理, 接收处理好的结果
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 4. 创建一个会话, 连接输入和输出
AVCaptureSession *session = [[AVCaptureSession alloc]init];
// 4.1 添加输入, 和输出
if ([session canAddInput:inputDevice]&&[session canAddOutput:output]) {
[session addInput:inputDevice];
[session addOutput:output];
}
// 4.2 设置输出处理的编码类型
// output.availableMetadataObjectTypes
// 注意: 设置元数据处理类型, 一定要写在元数据输出添加到会话之后, 否则, 无效, 扫描不到结果
output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
[session startRunning];
self.seesion = session;
#pragma mark - 获得扫描结果
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
[metadataObjects enumerateObjectsUsingBlock:^(__kindof AVMetadataObject * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {
AVMetadataMachineReadableCodeObject *codeObject = obj;
NSLog(@"%@",codeObject.stringValue);
}
}];
}
- 2、添加一个视频预览图层
AVCaptureVideoPreviewLayer *preLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:session];
preLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:preLayer atIndex:0];
- 3、限定扫描区域
一般的,扫描区域就是预览视图previewLayer的frame对应的矩形框,一般是设置全屏。如果我们想要设置一个有效区域怎么办,如同支付宝、微信等将扫码区域限制在一个小正方形内。这就要用到输出流AVCaptureMetadataOutput的一个rectOfInterest属性。
CGRect bounds = [UIScreen mainScreen].bounds;
CGFloat x = self.imageView.frame.origin.x/bounds.size.width;
CGFloat y = self.imageView.frame.origin.y/bounds.size.height;
CGFloat w = self.imageView.frame.size.width/bounds.size.width;
CGFloat h = self.imageView.frame.size.height/bounds.size.height;
output.rectOfInterest = CGRectMake(y, x, h, w);
rectOfInterest 的默认值是 CGRectMake(0, 0, 1, 1),它的坐标值范围是0–1,而且坐标系:0,0是右上角(横屏状态下的坐标)
网友评论