關(guān)于掃一掃歧寺,是時候放棄第三方了

原文地址:張飛的技術(shù)博客

掃一掃這個功能我們并不陌生,微信QQ加好友掃一掃棘脐,路邊搞推廣的掃一掃斜筐,吃飯付錢掃一掃【2校看來這個掃一掃應用的地方還真不少芭!打開手機看了看安裝的APP,社交類APP有掃一掃内斯,支付類的APP有掃一掃,連瀏覽器都有掃一掃像啼》常看來這個掃一掃不可小視!說不定哪天在你的項目中你的boss就要你給他加個掃一掃的功能呢忽冻!對于iOS開發(fā)要想做掃一掃這個功能真朗,并不是很難,我們需要做的就是處理二維碼(QRCode)而已僧诚。在iOS7之前需要借助第三方庫ZBar和ZXing遮婶。在iOS7以后用自帶API就能輕松搞定蝗碎。不用在項目中導入臃腫的第三方庫和擔心編譯出問題了。

二維碼是個什么鬼旗扑?

二維條碼是指在一維條碼的基礎上擴展出另一維具有可讀性的條碼蹦骑,使用黑白矩形圖案表示二進制數(shù)據(jù),被設備掃描后可獲取其中所包含的信息臀防。----維基百科

詳細的生成細節(jié)和原理可以看看二維碼的生成細節(jié)和原理這篇文章眠菇。

掃描二維碼

首先我們來想一想具體的步驟,大概流程應該是:1.打開設備的攝像頭-->2.進行二維碼圖像捕獲-->3.獲取捕獲的圖像進行解析-->4.取得解析結(jié)果進行后續(xù)處理袱衷。這些流程需要用到AVFoundation這個庫捎废,注意導入。

//獲取一個AVCaptureDevice對象致燥,可以理解為打開攝像頭這樣的動作
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//獲取一個AVCaptureDeviceInput對象登疗,將上面的'攝像頭'作為輸入設備
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:nil];
//拍完照片以后,需要一個AVCaptureMetadataOutput對象將獲取的'圖像'輸出嫌蚤,以便進行對其解析
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init];
//獲取輸出需要設置代理辐益,在代理方法中獲取
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//設置輸出類型,如AVMetadataObjectTypeQRCode是二維碼類型搬葬,下面還增加了條形碼荷腊。如果掃描的是條形碼也能識別
output.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code,
                                    AVMetadataObjectTypeEAN8Code,
                                    AVMetadataObjectTypeCode128Code,
                                    AVMetadataObjectTypeQRCode];

上面完成了捕獲的設置,但是并未正在開始'掃描'急凰,要完成一次掃描的過程女仰,需要用到AVCaptureSession這個類,這個session類把一次掃描看做一次會話抡锈,會話開始后才是正在的'掃描'開始,具體代碼如下疾忍。

AVCaptureSession *session = [[AVCaptureSession alloc]init];
[session setSessionPreset:AVCaptureSessionPresetHigh];//掃描的質(zhì)量
if ([session canAddInput:input]){
   [session addInput:input];//將輸入添加到會話中
}  
if ([session canAddOutput:output]){
   [session addOutput:output];//將輸出添加到會話中
}

接下來我們要做的不是立即開始會話(開始掃描),如果你現(xiàn)在調(diào)用會話的startRunning方法的話床三,你會發(fā)現(xiàn)屏幕是一片黑一罩,這時由于我們還沒有設置相機的取景器的大小。設置取景器需要用到AVCaptureVideoPreviewLayer這個類撇簿。具體代碼如下:

AVCaptureVideoPreviewLayer *preview =[AVCaptureVideoPreviewLayer layerWithSession:session];
preview.videoGravity = AVLayerVideoGravityResize;
[preview setFrame:self.view.bounds];//設置取景器的frame
[self.view.layer insertSublayer:preview atIndex:0];

接下來我們就可以調(diào)用session的startRunning方法了聂渊,這時我們的掃描就真正開始了。想要獲得掃描的結(jié)果四瘫,需要實現(xiàn)session的代理方法- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection,代碼如下:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    [self.session stopRunning];//停止會話
    [self.preview removeFromSuperlayer];//移除取景器
    
    if (metadataObjects.count > 0) {
        AVMetadataMachineReadableCodeObject *obj = metadataObjects[0];
        NSString *result = obj.stringValue;//這就是掃描的結(jié)果啦
        //對結(jié)果進行處理...
    }
}

如果要做到為用戶考慮的話汉嗽,還得加入照明的功能或者設置興趣區(qū)域。

  • 設設置興趣區(qū)域

使用過微信中的掃一掃的話找蜜,你應該發(fā)現(xiàn)在掃描界面中間有一個矩形限定框饼暑,這個框就是興趣區(qū)域了。這個興趣區(qū)域是AVCaptureMetadataOutputrectOfInterest屬性。rectOfInterest的值的范圍都是0-1,是按比例取值而不是實際尺寸,所以設置的時候要注意的一點弓叛。還要注意rectOfInterest都是按照橫屏來計算的彰居,所以當豎屏的情況下x軸和y軸要交換一下。代碼如下:

CGSize size = self.view.bounds.size;
CGSize transparentAreaSize = CGSizeMake(200,200);
CGRect cropRect = CGRectMake((size.width - transparentAreaSize.width)/2, (size.height - transparentAreaSize.height)/2, transparentAreaSize.width, transparentAreaSize.height);
output.rectOfInterest = CGRectMake(cropRect.origin.y/size.width,
                                              cropRect.origin.x/size.height,
                                              cropRect.size.height/size.height,
                                              cropRect.size.width/size.width);
  • 加入照明功能

加入照明功能能讓用戶在光照條件不好的情況下順利的進行進行掃描操作,代碼如下:

AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
if (device.hasTorch) {  // 判斷設備是否有閃光燈
    BOOL b = [device lockForConfiguration:&error];
    if (!b) {
       if (error) {
          NSLog(@"lock torch configuration error:%@", error.localizedDescription);
       }
       return;
    }
    device.torchMode = (device.torchMode == AVCaptureTorchModeOff ? AVCaptureTorchModeOn : AVCaptureTorchModeOff);
    [device unlockForConfiguration];
    }

從圖片中讀取二維碼

從圖片中直接讀取二維碼的功能在iOS7上面蘋果沒有實現(xiàn)撰筷,不過在iOS上已經(jīng)填補了這一功能陈惰。主要用到的是讀取主要用到CoreImage。

廢話不多說闭专,直接上代碼奴潘。

+ (NSString *)scQRReaderForImage:(UIImage *)qrimage{
    CIContext *context = [CIContext contextWithOptions:nil];
    CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy:CIDetectorAccuracyHigh}];
    CIImage *image = [CIImage imageWithCGImage:qrimage.CGImage];
    NSArray *features = [detector featuresInImage:image];
    CIQRCodeFeature *feature = [features firstObject];
    NSString *result = feature.messageString;
    return result;
}

既然講到要從相冊獲取照片,那么順便把從相冊獲取照片也講一下吧影钉。

從相冊獲取照片主要用到的是UIImagePickerController画髓,這是蘋果給我們分裝好的一個相冊選取的控制器。實現(xiàn)起來也是很簡單的平委。

- (void)readerImage{
    UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
    photoPicker.delegate = self;
    photoPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    photoPicker.view.backgroundColor = [UIColor whiteColor];
    [self presentViewController:photoPicker animated:YES completion:NULL];
}

當我們從照片庫選擇取了照片后要帶調(diào)用UIImagePickerController的代理方法獲取選擇的照片奈虾。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
    [self dismissViewControllerAnimated:YES completion:^{
      //code is here ...  
    }];
    
    UIImage *srcImage = [info objectForKey:UIImagePickerControllerOriginalImage];
    NSString *result = [QRCScanner scQRReaderForImage:srcImage];//調(diào)用上面講過的方法對圖片中的二維碼進行處理
    [self.navigationController popViewControllerAnimated:YES];
}

生成二維碼

生成二維碼和從圖片中讀取二維碼一樣要用到CoreImage,具體步驟如下:

- (UIImage *)makeQRCodeForString(NSString *)string{
    NSString *text = string;
    NSData *stringData = [text dataUsingEncoding: NSUTF8StringEncoding];
    //生成
    CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    [qrFilter setValue:stringData forKey:@"inputMessage"];
    [qrFilter setValue:@"M" forKey:@"inputCorrectionLevel"];
    //二維碼顏色
    UIColor *onColor = [UIColor redColor];
    UIColor *offColor = [UIColor blueColor];
    //上色,如果只要白底黑塊的QRCode可以跳過這一步
    CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor"
                                          keysAndValues:
                             @"inputImage",qrFilter.outputImage,
                             @"inputColor0",[CIColor colorWithCGColor:onColor.CGColor],
                             @"inputColor1",[CIColor colorWithCGColor:offColor.CGColor],
                             nil];
    //繪制
    CIImage *qrImage = colorFilter.outputImage;
    CGSize size = CGSizeMake(300, 300);
    CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage  fromRect:qrImage.extent];
    UIGraphicsBeginImageContext(size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetInterpolationQuality(context, kCGInterpolationNone);
    CGContextScaleCTM(context, 1.0, -1.0);//生成的QRCode就是上下顛倒的,需要翻轉(zhuǎn)一下
    CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage);
    UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CGImageRelease(cgImage);
    
    return [UIImage imageWithCIImage:qrImage];
}

當然如果你不想寫這個代碼的話廉赔,你也可以使用一個輕量級的開源代碼libqrencode來幫你實現(xiàn)肉微。它的使用非常簡單,導入UIImage+MDQRCode這個擴展后,使用UIImage的類方法就可以調(diào)用了蜡塌。

+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size;
+ (UIImage *)mdQRCodeForString:(NSString *)qrString size:(CGFloat)size fillColor:(UIColor *)fillColor;

QRCScanner

如果你連上面的代碼一點兒都不想寫碉纳,想一句話就集成掃描功能,你可以使用我封裝的QRCScanner,地址點這里馏艾。

總結(jié)

用第三方ZBar劳曹,ZXing是導入有問題?或者是編譯有問題琅摩?使用自帶的就不用擔心這些問題铁孵,而且是秒掃哦!如果你覺得我的文章對你有幫助房资,請隨意打賞蜕劝!


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘹狞,一起剝皮案震驚了整個濱河市缝呕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌廓握,老刑警劉巖搭独,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烫止,死亡現(xiàn)場離奇詭異,居然都是意外死亡戳稽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惊奇,“玉大人互躬,你說我怎么就攤上這事∷汤桑” “怎么了吼渡?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乓序。 經(jīng)常有香客問我寺酪,道長,這世上最難降的妖魔是什么替劈? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任寄雀,我火速辦了婚禮,結(jié)果婚禮上陨献,老公的妹妹穿的比我還像新娘盒犹。我一直安慰自己,他們只是感情好眨业,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布急膀。 她就那樣靜靜地躺著,像睡著了一般龄捡。 火紅的嫁衣襯著肌膚如雪卓嫂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天聘殖,我揣著相機與錄音晨雳,去河邊找鬼。 笑死就斤,一個胖子當著我的面吹牛悍募,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洋机,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼坠宴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了绷旗?” 一聲冷哼從身側(cè)響起喜鼓,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衔肢,沒想到半個月后庄岖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡角骤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年隅忿,在試婚紗的時候發(fā)現(xiàn)自己被綠了心剥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡背桐,死狀恐怖优烧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情链峭,我是刑警寧澤畦娄,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站弊仪,受9級特大地震影響熙卡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜励饵,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一驳癌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧曲横,春花似錦喂柒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至熙参,卻和暖如春艳吠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背孽椰。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工昭娩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人黍匾。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓栏渺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锐涯。 傳聞我的和親對象是個殘疾皇子磕诊,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

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

  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議。它實...
    香橙柚子閱讀 23,881評論 8 183
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫纹腌、插件霎终、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,109評論 4 62
  • 我的表弟在6月19日出生了!我期待著他的到來升薯,最為好奇的就是他的那張臉莱褒。 媽媽抱著表弟,他被一個棉被裹起來...
    少女故事閱讀 223評論 0 0
  • 昨天我參加了一場婚禮阅茶,婚禮的主人公是媽媽朋友的兒子。正當我興致勃勃的看新郎和新娘喝交杯酒的時候炮障,坐在我旁邊的王阿姨...
    韓雅潔閱讀 1,336評論 4 5
  • 1.新貴的目標是把“迷你退休”分配到整個一生目派,而不是愚蠢地把休息和享樂一再延遲統(tǒng)統(tǒng)放到退休以后。只在身體機能處于最...
    瑩瑩happygo閱讀 438評論 5 4