掃描二維碼- 功能實現(xiàn)
1. 是指像微信眼俊、支付寶等通過二維碼掃描工具動態(tài)識別攝像頭見到的區(qū)域中的二維碼
2. 讀取二維碼需要導(dǎo)入AVFoundation框架
3. 利用攝像頭識別二維碼中的內(nèi)容(模擬器無法實現(xiàn)該功能)
掃描二維碼- 功能實現(xiàn)(讀取二維碼) <- OC
-
導(dǎo)入框架
#import <AVFoundation/AVFoundation.h>
-
實現(xiàn)步驟及代碼
// 1. 實例化拍攝設(shè)備 AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; // 2. 把攝像頭當(dāng)做一個輸入設(shè)備 AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil]; // 3. 設(shè)置元數(shù)據(jù)輸出 // 3.1 實例化拍攝元數(shù)據(jù)輸出 AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init]; // 3.2 設(shè)置輸出數(shù)據(jù)代理 [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; // 3.3 設(shè)置掃描取景范圍(rectOfInterest 都是按照橫屏來計算的 所以當(dāng)豎屏的情況下 x軸和y軸要交換一下) CGFloat screenW = [UIScreen mainScreen].bounds.size.width; CGFloat screenH = [UIScreen mainScreen].bounds.size.height; CGFloat scanW = screenW * 0.6; CGRect scanRect = CGRectMake((screenW - scanW) * 0.5, (screenH - scanW) * 0.5, scanW, scanW); output.rectOfInterest = CGRectMake(scanRect.origin.y / screenH, scanRect.origin.x / screenW, scanRect.size.height / screenH, scanRect.size.width / screenW); // 3.4 設(shè)置掃描區(qū)域的邊框 UIView *scanV = [[UIView alloc] initWithFrame:scanRect]; [self.view addSubview:scanV]; scanV.layer.borderWidth = 2; scanV.layer.borderColor = [UIColor redColor].CGColor; // 4. 添加拍攝會話 // 4.1 實例化拍攝會話 AVCaptureSession *session = [[AVCaptureSession alloc] init]; // 4.2 添加會話輸入 [session addInput:input]; // 4.3 添加會話輸出 [session addOutput:output]; // 4.4 設(shè)置輸出數(shù)據(jù)類型,需要將元數(shù)據(jù)輸出添加到會話后庐橙,才能指定元數(shù)據(jù)類型琳水,否則會報錯 [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; // 5. 視頻預(yù)覽圖層 // 5.1 實例化預(yù)覽圖層 AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:_session]; preview.videoGravity = AVLayerVideoGravityResizeAspectFill; preview.frame = self.view.bounds; // 5.2 將圖層插入當(dāng)前視圖 [self.view.layer addSublayer:preview]; self.previewLayer = preview; // 6. 啟動會話 [_session startRunning]; // 當(dāng)掃描到數(shù)據(jù)時就會執(zhí)行該方法 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { if (metadataObjects.count > 0) { AVMetadataMachineReadableCodeObject *object = [metadataObjects lastObject]; NSLog(@"%@", object.stringValue); // 停止掃描 [self.session stopRunning]; // 將預(yù)覽圖層移除 [self.lview.ayer removeFromSuperlayer]; } else { NSLog(@"沒有掃描到數(shù)據(jù)"); } }
掃描二維碼- 功能實現(xiàn)(讀取二維碼) <- swift
-
導(dǎo)入框架
import AVFoundation
-
實現(xiàn)步驟及代碼
// 創(chuàng)建一個會話, 鏈接輸入和輸出 let session = AVCaptureSession() // 引用當(dāng)前的視頻預(yù)覽圖層 var layer: AVCaptureVideoPreviewLayer? override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { scan() } func scan() { // 1. 獲取攝像頭設(shè)備 // 1.1 把攝像頭當(dāng)做一個輸入設(shè)備 let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) var input: AVCaptureDeviceInput? do { input = try AVCaptureDeviceInput(device: device) }catch { print(error) return } // 2. 創(chuàng)建一個(元數(shù)據(jù))輸出處理對象 let output = AVCaptureMetadataOutput() // 2.1 設(shè)置代理, 拿到處理的結(jié)果 output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) // 3. 會話對象添加輸入輸出設(shè)備 // 容錯處理: 如果已經(jīng)添加過了, 就不會再次添加 if session.canAddInput(input) && session.canAddOutput(output) { session.addInput(input) session.addOutput(output) } // 3.1 設(shè)置元數(shù)據(jù)輸出處理對象, 處理數(shù)據(jù)的類型 // 必須在將輸出設(shè)備添加到會話設(shè)備后、啟動會話前設(shè)置 output.metadataObjectTypes = [AVMetadataObjectTypeQRCode] // 4. 啟動會話(讓輸入開始采集數(shù)據(jù), 讓輸出, 開始處理數(shù)據(jù)) session.startRunning() // 4.1 添加視頻預(yù)覽圖層(可選) // 可以讓用戶看到掃描的二維碼 let layer = AVCaptureVideoPreviewLayer(session: session) layer.frame = view.layer.bounds view.layer.insertSublayer(layer, atIndex: 0) } extension ScanVC: AVCaptureMetadataOutputObjectsDelegate { // 輸出數(shù)據(jù)時調(diào)用 // 最后如果沒有掃描到二維碼內(nèi)容的時候, 也會調(diào)用一次 func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { // 沒有數(shù)據(jù)直接return if (metadataObjects.count <= 0) {return} // 移除二維碼邊框代碼(可選)吊档,詳見“8. 掃描二維碼- 描繪邊框” // 遍歷元數(shù)據(jù)數(shù)組 for metaObj in metadataObjects { // 判斷元數(shù)據(jù)類型 if metaObj.isKindOfClass(AVMetadataMachineReadableCodeObject) { // 1. 獲取元數(shù)據(jù) // 如果需要繪制邊框篙议,需要把坐標(biāo)轉(zhuǎn)換成為在layer層上面的真實坐標(biāo) // 如果不需要,直接有l(wèi)et qrCodeObj = metaObj as! AVMetadataMachineReadableCodeObject let transformObj = layer?.transformedMetadataObjectForMetadataObject(metaObj as! AVMetadataObject) let qrCodeObj = transformObj as! AVMetadataMachineReadableCodeObject // 2. 繪制邊框代碼怠硼,詳見“8. 掃描二維碼- 描繪邊框” // qrCodeObj.corners: 二維碼的四個角 // 得到的結(jié)果,是點對應(yīng)的字典組成的數(shù)組,如[x:123.7997282646955,y:100.3352825435441]鬼贱,沒法直接使用 // 需要借助layer, 進行轉(zhuǎn)換成為我們可以直接處理的坐標(biāo) print(qrCodeObj.corners) // 3. 輸出二維碼具體內(nèi)容 // stringValue: 二維碼的具體內(nèi)容 print(qrCodeObj.stringValue) // 4. 停止掃描 // self.session.stopRunning // 5.將預(yù)覽圖層移除 // self.lview.ayer.removeFromSuperlayer } } }