iOS 原生二维码扫描

写这篇文章的主要缘由不是展现如何使用 AVFoundation   来进行二维码扫描,更主要的是限制扫描二维码的范围。(由于默认的是全屏扫描)session

项目遇到扫描二维码的功能需求,这里我放弃了使用三方库,而采用了苹果原生的扫描。ide

原生的好处就是扫描特别快效率特别高,可是遇到一个问题就是不知道怎么去限制扫描范围。优化

仍是先简单说一下怎么使用来进行二维码扫描吧。this

 

首先是要用到的几个类atom

 

@property (strong,nonatomic)AVCaptureDevice * device;spa

@property (strong,nonatomic)AVCaptureDeviceInput * input;.net

@property (strong,nonatomic)AVCaptureMetadataOutput * output;rest

@property (strong,nonatomic)AVCaptureSession * session;orm

@property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview;blog

他们之间的关系能够看下面的篇文章  

传送门

 

下面分别建立他们

 

    // Device

    _device = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];

    

    // Input

    _input = [AVCaptureDeviceInputdeviceInputWithDevice:self.deviceerror:nil];

    

    // Output

    _output = [[AVCaptureMetadataOutputalloc]init];

    [_outputsetMetadataObjectsDelegate:selfqueue:dispatch_get_main_queue()];

 

 

    // Session

    _session = [[AVCaptureSessionalloc]init];

    [_sessionsetSessionPreset:AVCaptureSessionPresetHigh];

    if ([_sessioncanAddInput:self.input])

    {

        [_sessionaddInput:self.input];

    }

    

    if ([_sessioncanAddOutput:self.output])

    {

        [_sessionaddOutput:self.output];

    }

    

    // 条码类型 AVMetadataObjectTypeQRCode

    _output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];

 

    // Preview

    _preview =[AVCaptureVideoPreviewLayerlayerWithSession:_session];

    _preview.videoGravity =AVLayerVideoGravityResizeAspectFill;

    _preview.frame =self.view.layer.bounds;

    [self.view.layerinsertSublayer:_previewatIndex:0];

 

    // Start

    [_sessionstartRunning];

 

而后实现 AVCaptureMetadataOutputObjectsDelegate

 

#pragma mark AVCaptureMetadataOutputObjectsDelegate

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection

{

   NSString *stringValue;

    if ([metadataObjectscount] >0)

       {

           //中止扫描

           [_sessionstopRunning];        

           AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjectsobjectAtIndex:0];

           stringValue = metadataObject.stringValue;        

    }

 

}

 

到此为止就能够成功扫描二维码了,可是有个尴尬的问题,这时的扫描是全屏扫描的。即

通常状况下项目中的扫描页面是这样的,可是当你扫描的时候会发如今二维码还没进入中心的那个小方块时,就已经成功扫描完成了,这对于体验来讲很很差。可是因为那时候赶项目就没有时间优化。终于今天抽出来时间了。

我从早上上班开始一直搞到下午,把全部想到的方法都试了一遍,可是都不行(都是泪),最后将要放弃的时候发现了一个比较可疑的点。

 

 

@property(nonatomic)CGRect rectOfInterest NS_AVAILABLE_IOS(7_0);

这是的 AVCaptureMetadataOutput 一个属性,它的解释是

@discussion

The value of this property is a CGRect that determines the receiver's rectangle of interest for each frame of video.  

The rectangle's origin is top left and is relative to the coordinate space of the device providing the metadata.  Specifying 

a rectOfInterest may improve detection performance for certain types of metadata. The default value of this property is the 

value CGRectMake(0, 0, 1, 1).  Metadata objects whose bounds do not intersect with the rectOfInterest will not be returned.

 

大概意思就是设置每一帧画面感兴趣的区域(字面意思),那岂不是就是设置扫描范围喽,大喜
因而赶忙把rectOfInterest设置成中间框的frame,

[_outputsetRectOfInterest:CGRectMake((ScreenWidth-220)/2,60+64,220, 220)];

//中间区域的宽和高都是220  ScreenWidth为设备屏幕宽度

可是却发现怎么扫描都不能成功了。因而又看了看上面的一段话。
 
第二句:区域的原点在左上方(后面才知道坑苦我了!),而后区域是相对于设备的大小的,默认值是CGRectMake(0, 0, 1, 1),这时候我才知道是有比例关系的,最大值才是1,也就是说只要除以相应的设备宽和高的大小不就好了?而后就改为

[_outputsetRectOfInterest:CGRectMake(((ScreenWidth-220)/2)/ScreenWidth,(60+64)/ScreenHigh,220/ScreenWidth,220/ScreenHigh)];

 

按说这样应该就完美了,可是才知道我仍是高兴得太早了,一扫描才发现彻底不是那么回事,差不少。

因而我就一点一点调,可是最后也没调成功,最后一狠心有设置了一个很肯定的值。

[_output setRectOfInterest:CGRectMake(0.5,0.5,0.5, 0.5)];

 

此次应该很肯定是在右下方的四分之一区域吧,嘿嘿。

可是事实又一次打击了我,扫描后发现是左下的四分之一区域,也就是说rectOfInterest的原点是右上角!!!

回头又一想,即便右上角是原点那也应该没有影响啊,可是为何不行呢,不会是原点的 X 和 Y 互换了吧?算了无论怎么着,试一试吧。

 

[_outputsetRectOfInterest:CGRectMake((60+64)/ScreenHigh,((ScreenWidth-220)/2)/ScreenWidth,220/ScreenWidth,220/ScreenHigh)];

 

又扫描了一下发现成功了!果真原点正确了,我只想说TMD!

可是宽和高又怎么对不上了?不会也互换了吧!赶忙试试

 

[_outputsetRectOfInterest:CGRectMake((124)/ScreenHigh,((ScreenWidth-220)/2)/ScreenWidth,220/ScreenHigh,220/ScreenWidth)];

 

因而用系统原生的扫描二维码就完美了!

原文连接:http://blog.csdn.net/lc_obj/article/details/41549469

相关文章
相关标签/搜索