iOS 二維碼和條形碼掃描,獲取焦點及焦距拉近縮放

? ? ? 對于現(xiàn)在的App應用來說,掃描二維碼和條形碼這個功能是再正常不過的一個功能了,在早期開發(fā)這些功能的時候,大家或多或少的都接觸過ZXing和ZBar這類的第三方庫,但從iOS7以后,蘋果就給我們提供了系統(tǒng)原生的API來支持我們掃描獲取二維碼,ZXing和ZBar在使用中或多或少有不盡如人意的地方,再之停止更新很久了,所以今天我們就來聊聊如何用系統(tǒng)原生的方法掃描獲取二維碼,強大的AVFoundation框架給我們提供了掃描私有方法和代理方法。

? ? ?首先獲取流媒體信息我們需要AVCaptureSession對象來管理輸入流和輸出流,AVCaptureVideoPreviewLayer對象來顯示信息,基本流程如下圖所示

??

AVCaptureSession管理輸入(AVCaptureInput)和輸出(AVCaptureOutput)流,包含開啟和停止會話方法。

AVCaptureDeviceInput是AVCaptureInput的子類,可以作為輸入捕獲會話,用AVCaptureDevice實例初始化。

AVCaptureDevice代表了物理捕獲設備如:攝像機。用于配置等底層硬件設置相機的自動對焦模式。

AVCaptureMetadataOutput是AVCaptureOutput的子類,處理輸出捕獲會話。捕獲的對象傳遞給一個委托實現(xiàn)AVCaptureMetadataOutputObjectsDelegate協(xié)議。協(xié)議方法在指定的派發(fā)隊列(dispatch queue)上執(zhí)行。

AVCaptureVideoPreviewLayerCALayer的一個子類,顯示捕獲到的相機輸出流。

好了看下實現(xiàn)過程:

添加代理 <AVCaptureMetadataOutputObjectsDelegate>

/** 設備 */

@property (nonatomic, strong) AVCaptureDevice * device;

/** 輸入輸出的中間橋梁 */

@property (nonatomic, strong) AVCaptureSession * session;

/** 相機圖層 */

@property (nonatomic, strong) AVCaptureVideoPreviewLayer * previewLayer;

/** 掃描支持的編碼格式的數(shù)組 */

@property (nonatomic, strong) NSMutableArray * metadataObjectTypes;

/** 遮罩層 */

@property (nonatomic, strong) ZFMaskView * maskView;

@property(nonatomic,strong) AVCaptureMetadataOutput * metadataOutput ;//輸出流

@property(nonatomic,strong)AVCaptureDeviceInput * input;//創(chuàng)建輸入流

這里介紹下掃描支持的編碼格式

/*

//設置支持的掃描類型

由于本項目只支持條形碼掃描,故先屏蔽掉二維碼掃描功能

AVMetadataObjectTypeQRCode,AVMetadataObjectTypeAztecCode,

*/

- (NSMutableArray *)metadataObjectTypes{

if (!_metadataObjectTypes) {

_metadataObjectTypes = [NSMutableArray arrayWithObjects:AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, ?/ ?/我國商品碼主要就是這和 EAN8

AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeUPCECode, nil];

// >= iOS 8

if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) {

[_metadataObjectTypes addObjectsFromArray:@[AVMetadataObjectTypeInterleaved2of5Code, AVMetadataObjectTypeITF14Code, AVMetadataObjectTypeDataMatrixCode]];

}

}

? ? return _metadataObjectTypes;

}

/**

*? 掃描初始化

*/

- (void)capture{

//獲取攝像設備

self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

//創(chuàng)建輸入流

AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];

//創(chuàng)建輸出流

_metadataOutput = [[AVCaptureMetadataOutput alloc] init];

//設置代理 在主線程里刷新

[_metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

//初始化鏈接對象

self.session = [[AVCaptureSession alloc] init];

//高質量采集率

self.session.sessionPreset = AVCaptureSessionPresetHigh;

[self.session addInput:input];

[self.session addOutput:_metadataOutput];

self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];

self.previewLayer.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

self.previewLayer.backgroundColor = [UIColor yellowColor].CGColor;

[self.view.layer addSublayer:self.previewLayer];

//設置掃描支持的編碼格式(如下設置條形碼和二維碼兼容)

_metadataOutput.metadataObjectTypes = self.metadataObjectTypes;

//開始捕獲

[self.session startRunning];

}

下一步,獲取掃描結果

#pragma mark - AVCaptureMetadataOutputObjectsDelegate-(void)captureOutput:(AVCaptureOutput*)captureOutput didOutputMetadataObjects:(NSArray*)metadataObjects fromConnection:(AVCaptureConnection*)connection

{if(metadataObjects.count>0) {? ? ?

? ?[self.session stopRunning];

?AVMetadataMachineReadableCodeObject*metadataObject = ?metadataObjects[0];

?NSLog(@"%@",metadataObject.stringValue);?

? }}

小結一下:

如果你的項目只需要掃描二維碼,不考慮條形碼,metadataObjectTypes只需要AVMetadataObjectTypeQRCode就夠了,反之把這個去掉


? 下面我主要講講怎么把鏡頭拉近,提高掃描效果,你之前在界面中添加一個按鈕,添加事件。

#pragma mark - ?焦距

- (void)CameraScaleAction:(UIButton *)sender{

kCameraScale+=0.5; ? //去定義一個float類型,默認值為1.0

if(kCameraScale>2.5)

kCameraScale=1.0;

//改變焦距 ? 記住這里的輸出鏈接類型要選中這個類型,否則屏幕會花的

AVCaptureConnection *connect=[_metadataOutput connectionWithMediaType:AVMediaTypeVideo];

[CATransaction begin];

[CATransaction setAnimationDuration:0.2];

[sender setTitle:[NSString stringWithFormat:@"%.1fX",(float)kCameraScale] forState:UIControlStateNormal];

//主要是改變相機圖層的大小

[_previewLayer setAffineTransform:CGAffineTransformMakeScale(kCameraScale, kCameraScale)];

connect.videoScaleAndCropFactor= kCameraScale;

[CATransaction commit];

//超出的部分切掉,否則影響掃描效果

self.view.clipsToBounds=YES;

self.view.layer.masksToBounds=YES;

}



這是對比圖,

如果想獲取焦點需要給view添加一個手勢

////對焦

-(void)foucus:(UITapGestureRecognizer *)sender

{

if(_input.device.position==AVCaptureDevicePositionFront)

return;

if(sender.state==UIGestureRecognizerStateRecognized)

{

CGPoint location=[sender locationInView:self.view];

//對焦

__weak typeof(self) weakSelf=self;

[self focusOnPoint:location completionHandler:^{

weakSelf.focalReticule.center=location;

weakSelf.focalReticule.alpha=0.0;

weakSelf.focalReticule.hidden=NO;

[UIView animateWithDuration:0.3 animations:^{

weakSelf.focalReticule.alpha=1.0;

}completion:^(BOOL finished) {

[UIView animateWithDuration:0.3 animations:^{

weakSelf.focalReticule.alpha=0.0;

}];

}];

}];

}

}

////對某一點對焦

-(void)focusOnPoint:(CGPoint)point completionHandler:(void(^)())completionHandler{

AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];;

CGPoint pointOfInterest = CGPointZero;

CGSize frameSize = self.view.bounds.size;

pointOfInterest = CGPointMake(point.y / frameSize.height, 1.f - (point.x / frameSize.width));

if ([device isFocusPointOfInterestSupported] && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus])

{

NSError *error;

if ([device lockForConfiguration:&error])

{

if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance])

{

[device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];

}

if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus])

{

[device setFocusMode:AVCaptureFocusModeAutoFocus];

[device setFocusPointOfInterest:pointOfInterest];

}

if([device isExposurePointOfInterestSupported] && [device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure])

{

[device setExposurePointOfInterest:pointOfInterest];

[device setExposureMode:AVCaptureExposureModeContinuousAutoExposure];

}

[device unlockForConfiguration];

if(completionHandler)

completionHandler();

}

}

else{

if(completionHandler)

completionHandler();

}

} ? ? ? ? ? ? ? ??

好了,歡迎大家指正

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容