ios原生AVFoudation扫描在同时支持二维码和条码扫描时,二维码总是很快得到数据,条码则有时有有时无,在坑里待了一段时间后终于找到原因,VCaptureMetadataOutput 有一个属性 rectOfInterest
就是设置元数据识别搜索的区域。
这个属性有点问题,不是普通的CGRect,四个值都需要在0~1之间。
AVCaptureVideoPreviewLayer 有个方法
- (CGRect)metadataOutputRectOfInterestForRect:(CGRect)rectInLayerCoordinates
可以看看这个方法的说明:
描述就是:把一个在previewlayer坐标系中的rect 转换成 一个在metadataoutputs坐标系中的rect。
这个方法需要的rect参数是我们系统坐标系中的rect.
SO 。这就得到了我们需要的rectOfInterest。
代码:
- (BOOL)startReading {
NSError *error;
//1.初始化捕捉设备(AVCaptureDevice),类型为AVMediaTypeVideo
AVCaptureDevice *captureDevice = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];
//2.用captureDevice创建输入流
AVCaptureDeviceInput *input = [AVCaptureDeviceInputdeviceInputWithDevice:captureDeviceerror:&error];
if (!input) {
NSLog(@"%@", [errorlocalizedDescription]);
returnNO;
}
//3.创建媒体数据输出流
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutputalloc] init];
//4.实例化捕捉会话
_captureSession = [[AVCaptureSessionalloc] init];
//4.1.将输入流添加到会话
[_captureSessionaddInput:input];
[_captureSessionsetSessionPreset:AVCaptureSessionPresetHigh];
//4.2.将媒体输出流添加到会话中
[_captureSessionaddOutput:captureMetadataOutput];
//5.创建串行队列,并加媒体输出流添加到队列当中
dispatch_queue_t dispatchQueue;
//dispatchQueue = dispatch_queue_create("myQueue", NULL);
dispatchQueue = dispatch_get_main_queue();
//5.1.设置代理
[captureMetadataOutput setMetadataObjectsDelegate:selfqueue:dispatchQueue];
//5.2.设置输出媒体数据类型为QRCode
[captureMetadataOutput setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode128Code]];
//6.实例化预览图层
_videoPreviewLayer = [[AVCaptureVideoPreviewLayeralloc] initWithSession:_captureSession];
//7.设置预览图层填充方式
[_videoPreviewLayersetVideoGravity:AVLayerVideoGravityResizeAspectFill];
//8.设置图层的frame
[_videoPreviewLayersetFrame:_vPreview.layer.bounds];
//9.将图层添加到预览view的图层上
[_vPreview.layeraddSublayer:_videoPreviewLayer];
//10.设置扫描范围
captureMetadataOutput.rectOfInterest =CGRectMake(0.2f,0.2f, 0.8f,0.8f);
//10.1.扫描框
_boxView = [[UIViewalloc] initWithFrame:CGRectMake(60, [[UIScreenmainScreen] bounds].size.height/2 -30 -([[UIScreenmainScreen] bounds].size.width - 60 * 2)/2, [[UIScreenmainScreen] bounds].size.width - 60 * 2, [[UIScreenmainScreen] bounds].size.width - 60 * 2)];
_boxView.layer.borderColor =mainColor.CGColor;
_boxView.layer.borderWidth =1.0f;
[_vPreviewaddSubview:_boxView];
//10.2.扫描线
_scanLayer = [[CALayeralloc] init];
_scanLayer.frame =CGRectMake(0,0, _boxView.bounds.size.width,1);
_scanLayer.backgroundColor = [UIColorcolorWithRed:190.0/255green:190.0/255blue:190.0/255alpha:1.0].CGColor;
[_boxView.layeraddSublayer:_scanLayer];
NSTimer *timer = [NSTimerscheduledTimerWithTimeInterval:0.2ftarget:selfselector:@selector(moveScanLayer:)userInfo:nilrepeats:YES];
[timer fire];
//放大焦距
[captureDevice lockForConfiguration:&error];
if (captureDevice.activeFormat.videoMaxZoomFactor > 2) {
captureDevice.videoZoomFactor =2;
}else{
captureDevice.videoZoomFactor = captureDevice.activeFormat.videoMaxZoomFactor;
}
[captureDevice unlockForConfiguration];
//10.开始扫描
[_captureSessionstartRunning];
//11.必须在startRunning之后才会生效(坑哦)
CGRect rect =CGRectMake(30,100, self.view.frame.size.width - 60, 300);
CGRect intertRect = [_videoPreviewLayermetadataOutputRectOfInterestForRect:rect];
CGRect layerRect = [_videoPreviewLayerrectForMetadataOutputRectOfInterest:intertRect];
NSLog(@"%@, %@",NSStringFromCGRect(intertRect),NSStringFromCGRect(layerRect));
captureMetadataOutput.rectOfInterest = intertRect;
// 这种方法实际不可行
// float width = self.view.frame.size.width;// AVCaptureVideoPreviewLayer的对象的宽度
// float height = self.view.frame.size.height;// AVCaptureVideoPreviewLayer的对象的高度
//
// captureMetadataOutput.rectOfInterest=CGRectMake(100/height, (width/2 -110)/width +50, 220/height, 220/width);
returnYES;
}