IOS 原生二維碼掃描

前文:

?今天來詳細(xì)寫一下掃一掃實(shí)現(xiàn),基本上實(shí)現(xiàn)掃一掃有三個(gè)庫泳叠,分別是ZBar,ZXing,AVFoundation迂卢,在IOS7以前是沒有AVFoundation的。

?1.ZBar在掃描靈敏度和內(nèi)存上比ZXing較好途凫,缺點(diǎn)卻很多垢夹,比如有圓角的二維碼很難掃。目前已經(jīng)停止更新

?2.ZXing是GoogleCode上的一個(gè)開源的條形碼掃碼庫维费,是用java設(shè)計(jì)的果元,連Google Glass都在使用。但有人為了追求更高效率以及可移植性犀盟,出現(xiàn)了c++ port. Github上的Objectivc-C port而晒,其實(shí)就是用OC代碼封裝了一下而已,而且已經(jīng)停止維護(hù)且蓬。

?3.AVFoundation提供原生api掃描二維碼欣硼,無論在掃描靈敏度和性能上來說都是最優(yōu)的,所以毫無疑問我們應(yīng)該切換到AVFoundation,但是只兼容IOS7及以上诈胜,如果是IOS7之前的版本就要使用ZBar或ZXing代替豹障。

我寫的比較全面,二維碼焦匈,條形碼血公,掃描區(qū)域設(shè)置,光感傳感器應(yīng)用缓熟,閃光燈顯示與隱藏累魔,閃光燈打開與關(guān)閉,相冊獲取二維碼掃描




頭文件:

?AVFoundation?是掃描需要用到的庫

?ImageIO?是閃光燈需要用到的庫

#import?<AVFoundation/AVFoundation.h>

#import?<ImageIO/ImageIO.h>



代理協(xié)議:

?AVCaptureMetadataOutputObjectsDelegate 掃描二維碼結(jié)果代理

?AVCaptureVideoDataOutputSampleBufferDelegate 周圍環(huán)境光感傳感器代理

?UINavigationControllerDelegate够滑、UIImagePickerControllerDelegate 選擇相冊圖片代理

<AVCaptureMetadataOutputObjectsDelegate,AVCaptureVideoDataOutputSampleBufferDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate>



屬性:

//顯示圖層

@property(nonatomic,strong)AVCaptureVideoPreviewLayer *layer;

//捕捉會(huì)話

@property(nonatomic,strong)AVCaptureSession *session;

//輔助區(qū)域框

@property(nonatomic,strong)UIView * cyanView;

//打開燈光btn,默認(rèn)為hidden

@property(nonatomic,strong)UIButton * lightBtn;

//獲取相冊圖片進(jìn)行掃描

@property(nonatomic,strong)UIButton * photoBtn;



//建議先判斷一下垦写,是否開啟相機(jī)權(quán)限

//創(chuàng)建狀態(tài)對象

AVAuthorizationStatus authStatus =[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

//判斷攝像頭狀態(tài)是否可用

? ? if(authStatus==AVAuthorizationStatusAuthorized){

? ? ? ? //開始掃描二維碼

? ? ? ? [self startScan];

? ? }else{

? ? ? ? NSLog(@"未開啟相機(jī)權(quán)限,請前往設(shè)置中開啟");

? ? }



//開始掃描二維碼

-(void)startScan{


//1.創(chuàng)建捕捉會(huì)話,AVCaptureSession是第一個(gè)要被創(chuàng)建的對象彰触,所有的操作都要基于這一個(gè)session

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


? ? //2.添加輸入源(數(shù)據(jù)從攝像頭輸入)

? ? /*輸入源對應(yīng)的類是AVCaptureInput梯投,該類是一個(gè)抽象類,不能被直接實(shí)例化

? ? 在實(shí)際使用中况毅,都是使用他的子類分蓖,比如

? ? AVCaptureDeviceInput,

? ? AVCaptureScreenInput(只能用于Mac)尔许,

? ? AVCaptureMetadataInput么鹤,

? ? 一般情況下,我們是使用AVCaptureDeviceInput味廊,比如從設(shè)備的攝像頭或者麥克風(fēng)輸入蒸甜。

?? ? AVCaptureDeviceInput的實(shí)例化方法如下

? ? */

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

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

? ? [self.session addInput:input];


? ? //3.添加輸出數(shù)據(jù)(示例對象-->類對象-->元類對象-->根元類對象)

? ? /*輸入的類是AVCaptureInput,那么輸出的類相應(yīng)的就應(yīng)該是AVCaptureOutput毡们。

?? ? 輸出不需要和設(shè)備掛鉤,因?yàn)橐话闱闆r下迅皇,我們的輸出要么是音頻或視頻文件,要么是一些其他的數(shù)據(jù)衙熔,像二維碼掃描一般是字符串類型登颓。

?? ? 所以創(chuàng)建AVCaptureOutput實(shí)例就不需要AVCaptureDevice對象。

?? ? AVCaptureOutput也同樣是一個(gè)抽象類红氯,同樣要使用其子類框咙,在這里我們掃描二維碼,

?? ? 使用的是AVCaptureMetadataOutput痢甘,設(shè)置代碼如下所示*/

? ? AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];

? ? [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

? ? //設(shè)置能掃描的區(qū)域喇嘱,這里注意,CGRectMake的x,y和width,height的值是互換位置

? ? output.rectOfInterest=CGRectMake(150/self.view.frame.size.height, 100/self.view.frame.size.width, (self.view.frame.size.width-200)/self.view.frame.size.width, (self.view.frame.size.width-200)/self.view.frame.size.width);

? ? [self.session addOutput:output];

? ? //設(shè)置輸入元數(shù)據(jù)的類型(類型是二維碼,條形碼數(shù)據(jù),注意塞栅,這個(gè)一定要寫在添加到session后面者铜,不然要崩潰,如果只需要掃描二維碼只需要AVMetadataObjectTypeQRCode,如果還需要掃描條形碼作烟,那么全部添加上)

? ? [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeEAN8Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeEAN13Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeCode39Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeCode39Mod43Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeCode93Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeCode128Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypePDF417Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeAztecCode,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeUPCECode,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeInterleaved2of5Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeITF14Code,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AVMetadataObjectTypeDataMatrixCode,

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ]];


? ? //4.添加掃描圖層

? ? self.layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];

? ? self.layer.videoGravity=AVLayerVideoGravityResizeAspectFill;

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

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


? ? //5.創(chuàng)建view,通過layer層進(jìn)行設(shè)置邊框?qū)挾群皖伾?用來輔助展示掃描的區(qū)域

? ? UIView * cyanView=[[UIView alloc] initWithFrame:CGRectMake(100, 150, self.view.frame.size.width-200, self.view.frame.size.width-200)];

? ? cyanView.layer.borderWidth=2;

? ? cyanView.layer.borderColor =[UIColor cyanColor].CGColor;

? ? [self.view addSubview:cyanView];


? ? //6.創(chuàng)建檢測光感源

? ? AVCaptureVideoDataOutput *guangOutPut = [[AVCaptureVideoDataOutput alloc] init];

? ? [guangOutPut setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

? ? //設(shè)置為高質(zhì)量采集率

? ? [self.session setSessionPreset:AVCaptureSessionPresetHigh];

? ? //把光感源添加到會(huì)話

? ? [self.session addOutput:guangOutPut];


? ? //7.閃光燈開關(guān)btn

? ? self.lightBtn=[[UIButton alloc]initWithFrame:CGRectMake(150, cyanView.frame.origin.y+cyanView.frame.size.height+100, self.view.frame.size.width-300, self.view.frame.size.width-300)];

? ? self.lightBtn.backgroundColor=[UIColor grayColor];

? ? [self.lightBtn addTarget:self action:@selector(lightBtnClick:) forControlEvents:UIControlEventTouchUpInside];

? ? [self.view addSubview:self.lightBtn];


? ? //8.獲取相冊圖片進(jìn)行掃描btn

? ? self.photoBtn=[[UIButton alloc]initWithFrame:CGRectMake(100, self.lightBtn.frame.origin.y+self.lightBtn.frame.size.height+50, self.view.frame.size.width-200, 50)];

? ? [self.photoBtn setTitle:@"相冊" forState:UIControlStateNormal];

? ? [self.photoBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

? ? self.photoBtn.backgroundColor=[UIColor orangeColor];

? ? [self.photoBtn addTarget:self action:@selector(photoBtnClick:) forControlEvents:UIControlEventTouchUpInside];

? ? [self.view addSubview:self.photoBtn];


? ? //9.開始掃描

? ? [self.session startRunning];

}



//實(shí)現(xiàn)掃描的回調(diào)代理方法

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

//如果數(shù)組metadataObjects中有數(shù)據(jù)愉粤,metadataObjects是個(gè)數(shù)組類型

? ? if(metadataObjects.count>0) {

? ? ? ? // 獲取最終的讀取結(jié)果,獲取數(shù)組中最后一個(gè)元素拿撩,數(shù)組中是AVMetadataMachineReadableCodeObject類型對象

? ? ? ? AVMetadataMachineReadableCodeObject*object = [metadataObjects lastObject];

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

? ? ? ? //停止掃描

? ? ? ? [self.session stopRunning];

? ? ? ? //移除掃描層layer

? ? ? ? [self.layer removeFromSuperlayer];

? ? }else{

? ? ? ? NSLog(@"沒有掃描到數(shù)據(jù)");

? ? }

}



//光感傳感器代理

-(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];

? ? floatbrightnessValue = [[exifMetadata objectForKey:(NSString*)kCGImagePropertyExifBrightnessValue]floatValue];

? ? NSLog(@"%f",brightnessValue);


? ? // 根據(jù)brightnessValue的值來打開和關(guān)閉閃光燈衣厘,一般值小于0就需要打開,大于0就關(guān)閉

? ? if((brightnessValue <0)) {//顯示閃光燈

? ? ? ? self.lightBtn.hidden=NO;

? ? }elseif((brightnessValue >0)) {//隱藏閃光燈

? ? ? ? self.lightBtn.hidden=YES;

? ? }

}



//閃光燈按鈕點(diǎn)擊方法

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

? ? //判斷當(dāng)前設(shè)備是否有閃光燈

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

? ? BOOL result=[device hasTorch];

? ? if(result==YES){

? ? ? ? if(self.lightBtn.isSelected==NO){

? ? ? ? ? ? self.lightBtn.selected=YES;

? ? ? ? ? ? self.lightBtn.backgroundColor=[UIColor greenColor];


? ? ? ? ? ? [device lockForConfiguration:nil];

? ? ? ? ? ? [device setTorchMode: AVCaptureTorchModeOn];//開

? ? ? ? ? ? [device unlockForConfiguration];


? ? ? ? }else if(self.lightBtn.isSelected==YES){

? ? ? ? ? ? self.lightBtn.selected=NO;

? ? ? ? ? ? self.lightBtn.backgroundColor=[UIColor grayColor];;


? ? ? ? ? ? [device lockForConfiguration:nil];

? ? ? ? ? ? [device setTorchMode: AVCaptureTorchModeOff];//關(guān)

? ? ? ? ? ? [device unlockForConfiguration];

? ? ? ? }

? ? }else{

? ? ? ? NSLog(@"當(dāng)前設(shè)備閃光燈不可用");

? ? }

}



//獲取相冊圖片btn點(diǎn)擊方法

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

? ? UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];

? ? imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

? ? // imagePicker.allowsEditing = YES;

? ? imagePicker.delegate=self;

? ? [self.navigationController presentViewController:imagePicker animated:YES completion:nil];

}



//UIImagePickerControllerDelegate選擇圖片的回調(diào)

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {

?//把UIimage類型轉(zhuǎn)換成CIimage類型

? ? UIImage *pickedImage = info[UIImagePickerControllerEditedImage] ?: info[UIImagePickerControllerOriginalImage];

? ? CIImage*detectImage = [CIImage imageWithData:UIImagePNGRepresentation(pickedImage)];


? ? //解析掃描二維碼結(jié)果字符串

? ? CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];

? ? CIQRCodeFeature*feature = (CIQRCodeFeature*)[detector featuresInImage:detectImage options:nil].firstObject;


? ? [picker dismissViewControllerAnimated:YES completion:^{

? ? ? ? if(feature.messageString) {

? ? ? ? ? ? NSLog(@"=================二維碼結(jié)果為%@",feature.messageString);

? ? ? ? }else{

? ? ? ? ? ? NSLog(@"未掃描到相應(yīng)二維碼");

? ? ? ? }

? ? ? ? //停止會(huì)話對象掃描

? ? ? ? [self.session stopRunning];

? ? ? ? //移除掃描層layer

? ? ? ? [self.layer removeFromSuperlayer];

? ? }];

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末压恒,一起剝皮案震驚了整個(gè)濱河市影暴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌探赫,老刑警劉巖型宙,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異期吓,居然都是意外死亡早歇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門讨勤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晨另,你說我怎么就攤上這事潭千。” “怎么了借尿?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵刨晴,是天一觀的道長。 經(jīng)常有香客問我路翻,道長狈癞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任茂契,我火速辦了婚禮蝶桶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掉冶。我一直安慰自己真竖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布厌小。 她就那樣靜靜地躺著恢共,像睡著了一般。 火紅的嫁衣襯著肌膚如雪璧亚。 梳的紋絲不亂的頭發(fā)上讨韭,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼透硝。 笑死吉嚣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蹬铺。 我是一名探鬼主播尝哆,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼甜攀!你這毒婦竟也來了秋泄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤规阀,失蹤者是張志新(化名)和其女友劉穎恒序,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谁撼,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡歧胁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厉碟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喊巍。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖箍鼓,靈堂內(nèi)的尸體忽然破棺而出崭参,到底是詐尸還是另有隱情,我是刑警寧澤款咖,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布何暮,位于F島的核電站,受9級(jí)特大地震影響铐殃,放射性物質(zhì)發(fā)生泄漏海洼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一富腊、第九天 我趴在偏房一處隱蔽的房頂上張望坏逢。 院中可真熱鬧,春花似錦蟹肘、人聲如沸词疼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贰盗。三九已至,卻和暖如春阳欲,著一層夾襖步出監(jiān)牢的瞬間舵盈,已是汗流浹背陋率。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秽晚,地道東北人瓦糟。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像赴蝇,于是被迫代替她去往敵國和親菩浙。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容