掃碼過程中的光線監(jiān)測(cè)的實(shí)現(xiàn)效果一般是,在掃碼的過程中,監(jiān)測(cè)光線環(huán)境,比如摩拜單車app,支付寶、微信的掃碼同樣也可以在掃碼的過程中針對(duì)環(huán)境進(jìn)行提醒。
(本文基于iOS原生的API實(shí)現(xiàn)的二維碼掃描)
網(wǎng)上關(guān)于iOS原生API實(shí)現(xiàn)掃描、閃光燈控制方面的文章有很多,這里就不再贅述了。
首先介紹兩個(gè)錯(cuò)誤的實(shí)現(xiàn)思路
1.AVCaptureTorchModeAuto不起作用
只有使用AVCaptureVideoDataOutput作為輸出時(shí),AVCaptureTorchModeAuto才會(huì)起作用,而且亮度的監(jiān)測(cè)只在捕獲最初起作用,并不是連續(xù)監(jiān)測(cè)的,而且我們需要的是實(shí)時(shí)監(jiān)測(cè),所以,AVCaptureTorchModeAuto不能滿足我們的需求。
ZBar應(yīng)該采用的就是設(shè)置AVCaptureTorchModeAuto的方法。
2.[UIScreen mainScreen].brightness跟二維碼沒關(guān)系
網(wǎng)上有的文章說通過NSTimer實(shí)時(shí)獲取這個(gè)值來判斷當(dāng)前光線環(huán)境。brightness這個(gè)值指的是手機(jī)屏幕的亮度級(jí)別,和掃描用的相機(jī)設(shè)備并沒有關(guān)系,而且它的自動(dòng)變化是需要開啟手機(jī)的自動(dòng)亮度調(diào)節(jié)功能的。
綜上,需要找到一個(gè)可以實(shí)時(shí)監(jiān)測(cè)相機(jī)光線環(huán)境的方法。在光線環(huán)境較差的情況下,操作閃光燈的開關(guān)狀態(tài)。
正確的實(shí)現(xiàn)思路
二維碼掃碼我們用到的輸出流是AVCaptureMetadataOutput,對(duì)應(yīng)的代理是AVCaptureMetadataOutputObjectsDelegate。實(shí)現(xiàn)的代理方法是
#pragma mark - 掃描結(jié)果 AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
if (metadataObjects && metadataObjects.count > 0) {
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
NSLog(@"掃描字符串:%@", metadataObject.stringValue)
}
}
這個(gè)方法里并沒有提供光線環(huán)境監(jiān)測(cè)方面的信息,而且這個(gè)方法只是在掃描結(jié)束才調(diào)用。
我們可以通過音視頻錄制輸出流AVCaptureVideoDataOutput來實(shí)時(shí)監(jiān)測(cè)相機(jī)的光線環(huán)境。
#define brightnessThresholdValue (-0.2) //亮度閾值
#pragma AVCaptureVideoDataOutputSampleBufferDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL, sampleBuffer, kCMAttachmentMode_ShouldPropagate);
NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
CFRelease(metadataDict);
NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];
NSLog(@"當(dāng)前亮度值 : %f",brightnessValue);
if (brightnessValue < brightnessThresholdValue) {
dispatch_async(dispatch_get_main_queue(), ^{
//打開手電筒
[self turnTorchOn:YES];
});
}
}
同一個(gè)AVCaptureSession是可以添加多個(gè)input設(shè)備和多個(gè)output的,所以,我們可以通過同時(shí)使用這兩個(gè)輸出流,來實(shí)現(xiàn)掃碼和光線環(huán)境監(jiān)測(cè)。不過添加前一定要通過- (BOOL)canAddOutput:(AVCaptureOutput *)output;
判斷一下,同一個(gè)input/output添加兩次是會(huì)崩潰的。
總結(jié):添加一個(gè)相機(jī)輸入設(shè)備的output,添加AVCaptureMetadataOutput解析二維碼,添加AVCaptureVideoDataOutput監(jiān)測(cè)光線環(huán)境。