AVFoundation二維碼

有關(guān)二維碼的介紹渔期,我這里不做過多說明, 可以直接去基維百科查看尘颓,附上鏈接QR code.

IOS7之前,開發(fā)者進(jìn)行掃碼編程時晦譬,一般會借助第三方庫疤苹。常用的是ZBarSDKaZXingObjC,IOS7之后敛腌,系統(tǒng)的AVMetadataObject類中卧土,為我們提供了解析二維碼的接口惫皱。經(jīng)過測試,使用原生API掃描和處理的效率非常高尤莺,遠(yuǎn)遠(yuǎn)高于第三方庫旅敷。


官方提供的接口非常簡單,直接看代碼颤霎,主要使用的是AVFoundation媳谁。

@interfaceViewController()//用于處理采集信息的代理


{

AVCaptureSession* session;//輸入輸出的中間橋梁

}

@end

@implementationViewController

- (void)viewDidLoad {

[superviewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

//獲取攝像設(shè)備

AVCaptureDevice* device = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];

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

AVCaptureDeviceInput* input = [AVCaptureDeviceInputdeviceInputWithDevice:device error:nil];

if(!input)return;

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

AVCaptureMetadataOutput* output = [[AVCaptureMetadataOutputalloc]init];

//設(shè)置代理 在主線程里刷新

[output setMetadataObjectsDelegate:selfqueue:dispatch_get_main_queue()];

//設(shè)置有效掃描區(qū)域

CGRectscanCrop=[selfgetScanCrop:_scanWindow.bounds readerViewBounds:self.view.frame];

output.rectOfInterest = scanCrop;

//初始化鏈接對象

_session = [[AVCaptureSessionalloc]init];

//高質(zhì)量采集率

[_session setSessionPreset:AVCaptureSessionPresetHigh];

[_session addInput:input];

[_session addOutput:output];

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

output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode128Code];

AVCaptureVideoPreviewLayer* layer = [AVCaptureVideoPreviewLayerlayerWithSession:_session];

layer.videoGravity=AVLayerVideoGravityResizeAspectFill;

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

[self.view.layer insertSublayer:layer atIndex:0];

//開始捕獲

[_session startRunning];

}

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

if(metadataObjects.count>0) {

//[session stopRunning];

AVMetadataMachineReadableCodeObject* metadataObject = [metadataObjects objectAtIndex :0];

//輸出掃描字符串

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

}

}




一些初始化的代碼加上實現(xiàn)代理方法便完成了二維碼掃描的工作,這里我們需要注意的是友酱, 在二維碼掃描的時候晴音, 我們一般都會在屏幕中間放一個方框,用來顯示二維碼掃描的大小區(qū)間缔杉,這里我們在個AVCaptureMetadataOutput類中有一個rectOfInterest屬性锤躁,它的作用就是設(shè)置掃描范圍。

這個CGRect參數(shù)和普通的Rect范圍不太一樣壮吩,它的四個值的范圍都是0-1进苍,表示比例。

rectOfInterest都是按照橫屏來計算的 所以當(dāng)豎屏的情況下 x軸和y軸要交換一下鸭叙。

寬度和高度設(shè)置的情況也是類似觉啊。

我們在上面設(shè)置有效掃描區(qū)域的方法如下


#pragma mark-> 獲取掃描區(qū)域的比例關(guān)系

-(CGRect)getScanCrop:(CGRect)rect readerViewBounds:(CGRect)readerViewBounds

{

CGFloatx,y,width,height;

x = (CGRectGetHeight(readerViewBounds)-CGRectGetHeight(rect))/2/CGRectGetHeight(readerViewBounds);

y = (CGRectGetWidth(readerViewBounds)-CGRectGetWidth(rect))/2/CGRectGetWidth(readerViewBounds);

width =CGRectGetHeight(rect)/CGRectGetHeight(readerViewBounds);

height =CGRectGetWidth(rect)/CGRectGetWidth(readerViewBounds);

returnCGRectMake(x, y, width, height);

}



讀取主要用到CoreImage 不過要強調(diào)的是讀取二維碼的功能只有在iOS8之后才支持,我們需要在相冊中調(diào)用一個二維碼沈贝,將其讀取杠人,代碼如下

#pragma mark-> 我的相冊

-(void)myAlbum{

NSLog(@"我的相冊");

if([UIImagePickerControllerisSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){

//1.初始化相冊拾取器

UIImagePickerController*controller = [[UIImagePickerControlleralloc] init];

//2.設(shè)置代理

controller.delegate =self;

//3.設(shè)置資源:

/**

UIImagePickerControllerSourceTypePhotoLibrary,相冊

UIImagePickerControllerSourceTypeCamera,相機

UIImagePickerControllerSourceTypeSavedPhotosAlbum,照片庫

*/

controller.sourceType =UIImagePickerControllerSourceTypeSavedPhotosAlbum;

//4.隨便給他一個轉(zhuǎn)場動畫

controller.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal;

[selfpresentViewController:controller animated:YEScompletion:NULL];

}else{

UIAlertView* alert = [[UIAlertViewalloc]initWithTitle:@"提示"message:@"設(shè)備不支持訪問相冊,請在設(shè)置->隱私->照片中進(jìn)行設(shè)置宋下!"delegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil,nil];

[alert show];

}

}

完成相冊代理嗡善, 我們在代理中添加讀取二維碼方法

#pragma mark-> imagePickerController delegate

- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info

{

//1.獲取選擇的圖片

UIImage*image = info[UIImagePickerControllerOriginalImage];

//2.初始化一個監(jiān)測器

CIDetector*detector = [CIDetectordetectorOfType:CIDetectorTypeQRCodecontext:niloptions:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];

[picker dismissViewControllerAnimated:YEScompletion:^{

//監(jiān)測到的結(jié)果數(shù)組

NSArray*features = [detector featuresInImage:[CIImageimageWithCGImage:image.CGImage]];

if(features.count >=1) {

/**結(jié)果對象 */

CIQRCodeFeature*feature = [features objectAtIndex:0];

NSString*scannedResult = feature.messageString;

UIAlertView* alertView = [[UIAlertViewalloc]initWithTitle:@"掃描結(jié)果"message:scannedResult delegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil,nil];

[alertView show];

}

else{

UIAlertView* alertView = [[UIAlertViewalloc]initWithTitle:@"提示"message:@"該圖片沒有包含一個二維碼!"delegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil,nil];

[alertView show];

}

}];

}

因為沒用真機学歧,所以這里沒有給出太多的截圖罩引, 用模擬器讀取自帶圖片,結(jié)果如下


生成

生成二維碼枝笨,其實也是用到CoreImage袁铐,但是步驟繁瑣一些,代碼如下


#pragma mark-> 二維碼生成

-(void)create{

UIImage*image=[UIImageimageNamed:@"6824500_006_thumb.jpg"];

NSString*tempStr;

if(self.textField.text.length==0){

tempStr=@"ddddddddd";

}else{

tempStr=self.textField.text;

}

UIImage*tempImage=[QRCodeGenerator qrImageForString:tempStr imageSize:360Topimg:image withColor:RandomColor];

_outImageView.image=tempImage;

}

+(UIImage*)qrImageForString:(NSString*)string imageSize:(CGFloat)size Topimg:(UIImage*)topimg withColor:(UIColor*)color{

if(![string length]) {

returnnil;

}

QRcode *code = QRcode_encodeString([string UTF8String],0, QR_ECLEVEL_L, QR_MODE_8,1);

if(!code) {

returnnil;

}

// create context

CGColorSpaceRefcolorSpace =CGColorSpaceCreateDeviceRGB();

CGContextRefctx =CGBitmapContextCreate(0, size, size,8, size *4, colorSpace, kCGImageAlphaPremultipliedLast);

CGAffineTransformtranslateTransform =CGAffineTransformMakeTranslation(0, -size);

CGAffineTransformscaleTransform =CGAffineTransformMakeScale(1,-1);

CGContextConcatCTM(ctx,CGAffineTransformConcat(translateTransform, scaleTransform));

// draw QR on this context

[QRCodeGenerator drawQRCode:code context:ctx size:size withPointType:0withPositionType:0withColor:color];

// get image

CGImageRefqrCGImage =CGBitmapContextCreateImage(ctx);

UIImage* qrImage = [UIImageimageWithCGImage:qrCGImage];

if(topimg)

{

UIGraphicsBeginImageContext(qrImage.size);

//Draw image2

[qrImage drawInRect:CGRectMake(0,0, qrImage.size.width, qrImage.size.height)];

//Draw image1

floatr=qrImage.size.width*35/240;

[topimg drawInRect:CGRectMake((qrImage.size.width-r)/2, (qrImage.size.height-r)/2,r, r)];

qrImage=UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

}

// some releases

CGContextRelease(ctx);

CGImageRelease(qrCGImage);

CGColorSpaceRelease(colorSpace);

QRcode_free(code);

returnqrImage;

}

+ (void)drawQRCode:(QRcode *)code context:(CGContextRef)ctx size:(CGFloat)size withPointType:(QRPointType)pointType withPositionType:(QRPositionType)positionType withColor:(UIColor*)color {

unsignedchar*data =0;

intwidth;

data = code->data;

width = code->width;

floatzoom = (double)size / (code->width +2.0* qr_margin);

CGRectrectDraw =CGRectMake(0,0, zoom, zoom);

// draw

constCGFloat*components;

if(color) {

components =CGColorGetComponents(color.CGColor);

}else{

components =CGColorGetComponents([UIColorblackColor].CGColor);

}

CGContextSetRGBFillColor(ctx, components[0], components[1], components[2],1.0);

NSLog(@"aad :%f? bbd :%f? ccd:%f",components[0],components[1],components[2]);

for(inti =0; i < width; ++i) {

for(intj =0; j < width; ++j) {

if(*data &1) {

rectDraw.origin =CGPointMake((j + qr_margin) * zoom,(i + qr_margin) * zoom);

if(positionType == QRPositionNormal) {

switch(pointType) {

caseQRPointRect:

CGContextAddRect(ctx, rectDraw);

break;

caseQRPointRound:

CGContextAddEllipseInRect(ctx, rectDraw);

break;

default:

break;

}

}elseif(positionType == QRPositionRound) {

switch(pointType) {

caseQRPointRect:

CGContextAddRect(ctx, rectDraw);

break;

caseQRPointRound:

if((i>=0&& i<=6&& j>=0&& j<=6) || (i>=0&& i<=6&& j>=width-7-1&& j<=width-1) || (i>=width-7-1&& i<=width-1&& j>=0&& j<=6)) {

CGContextAddRect(ctx, rectDraw);

}else{

CGContextAddEllipseInRect(ctx, rectDraw);

}

break;

default:

break;

}

}

}

++data;

}

}

CGContextFillPath(ctx);

}


在textField輸入横浑,生成下圖

長按二維碼識別

這個功能有很多的地方在用剔桨, 最讓人熟知的我想便是微信了,其實實現(xiàn)方法還是很簡單的徙融。

#pragma mark-> 長按識別二維碼

-(void)dealLongPress:(UIGestureRecognizer*)gesture{

if(gesture.state==UIGestureRecognizerStateBegan){

_timer.fireDate=[NSDatedistantFuture];

UIImageView*tempImageView=(UIImageView*)gesture.view;

if(tempImageView.image){

//1. 初始化掃描儀洒缀,設(shè)置設(shè)別類型和識別質(zhì)量

CIDetector*detector = [CIDetectordetectorOfType:CIDetectorTypeQRCodecontext:niloptions:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];

//2. 掃描獲取的特征組

NSArray*features = [detector featuresInImage:[CIImageimageWithCGImage:tempImageView.image.CGImage]];

//3. 獲取掃描結(jié)果

CIQRCodeFeature*feature = [features objectAtIndex:0];

NSString*scannedResult = feature.messageString;

UIAlertView* alertView = [[UIAlertViewalloc]initWithTitle:@"掃描結(jié)果"message:scannedResult delegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil,nil];

[alertView show];

}else{

UIAlertView* alertView = [[UIAlertViewalloc]initWithTitle:@"掃描結(jié)果"message:@"您還沒有生成二維碼"delegate:nilcancelButtonTitle:@"確定"otherButtonTitles:nil,nil];

[alertView show];

}

}elseif(gesture.state==UIGestureRecognizerStateEnded){

_timer.fireDate=[NSDatedistantPast];

}

}

我們用剛才生成的二維碼進(jìn)行長按識別,效果如下

結(jié)語

本文demo下載地址請點這里Demo,

轉(zhuǎn)自mokey1422所寫的仿支付寶二維碼。

系統(tǒng)原生的二維碼掃描掃描識別速度树绩,要比第三方好用得多萨脑,在沒有特殊原因的情況下,比如7.0系統(tǒng)以下葱峡,我希望大家都能用系統(tǒng)原生的方法砚哗。

文章若有問題請給予指正龙助,感謝砰奕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市提鸟,隨后出現(xiàn)的幾起案子军援,更是在濱河造成了極大的恐慌,老刑警劉巖称勋,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胸哥,死亡現(xiàn)場離奇詭異,居然都是意外死亡赡鲜,警方通過查閱死者的電腦和手機空厌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來银酬,“玉大人嘲更,你說我怎么就攤上這事】桑” “怎么了赋朦?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長李破。 經(jīng)常有香客問我宠哄,道長,這世上最難降的妖魔是什么嗤攻? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任毛嫉,我火速辦了婚禮,結(jié)果婚禮上妇菱,老公的妹妹穿的比我還像新娘承粤。我一直安慰自己,他們只是感情好恶耽,可當(dāng)我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布密任。 她就那樣靜靜地躺著,像睡著了一般偷俭。 火紅的嫁衣襯著肌膚如雪浪讳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天涌萤,我揣著相機與錄音淹遵,去河邊找鬼口猜。 笑死,一個胖子當(dāng)著我的面吹牛透揣,可吹牛的內(nèi)容都是我干的济炎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼辐真,長吁一口氣:“原來是場噩夢啊……” “哼须尚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侍咱,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤耐床,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后楔脯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撩轰,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年昧廷,在試婚紗的時候發(fā)現(xiàn)自己被綠了堪嫂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡木柬,死狀恐怖皆串,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弄诲,我是刑警寧澤愚战,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站齐遵,受9級特大地震影響寂玲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梗摇,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一拓哟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧伶授,春花似錦断序、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疮蹦,卻和暖如春诸迟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工阵苇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留壁公,地道東北人。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓绅项,卻偏偏與公主長得像紊册,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子快耿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,554評論 2 349

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

  • 在以前二維碼比較知名的框架是ZXing和Zbar囊陡,現(xiàn)在,iOS系統(tǒng)提供了原生的實現(xiàn)二維碼的功能 內(nèi)容: 二維碼的掃...
    零點知晨閱讀 843評論 0 3
  • 之前使用過AVFoundation實現(xiàn)二維碼掃描的功能润努,當(dāng)初第一次接觸這個框架关斜,只是搜索資料示括,實現(xiàn)功能就草草了事了...
    月詠蝴蝶閱讀 1,228評論 1 6
  • 空閑學(xué)習(xí)下AVFoundation中的AVCaptureSession铺浇,為了加深理解,寫了一個識別二維碼的demo...
    YxxxHao閱讀 1,250評論 0 3
  • CIDetector 這個api是蘋果在ios8之后提供的垛膝。所以用蘋果自帶的AVFundation掃描鳍侣,如果從相冊...
    然亦傘閱讀 551評論 1 0
  • 原文:子曰:為政以德,譬如北辰吼拥,居其所倚聚,而眾星共之。 孔子說:“以德行來治理國家凿可,就像北極星一樣安坐在自己的位置上...
    愛你and回憶閱讀 167評論 0 0