ios-深度解析二維碼的產生與使用,ios-深度
利用一個小demo來對二維碼進行學習,總共四個介面(主介面,產生二維碼介面,識別二維碼介面,掃描二維碼介面) 一.二維碼的介紹 1.什麼是二維碼? 二維條碼/二維碼是用某種特定的幾何圖形按一定規律在平面分布的黑白相間的圖形記錄資料符號資訊的 總結: 用圖形記錄標記一些資訊,方便通過圖形識別來擷取資訊 2 應用情境 資訊擷取(名片、地圖、WIFI密碼、資料) 手機電商(使用者掃碼、手機直接購物下單) 手機支付(掃描商品二維碼,通過銀行或第三方支付提供的手機端通道完成支付) 添加好友 二.二維碼介面的搭建 1.總共四個介面,可以採用storyBoard來搭建 2.四個storyBoard放在一個介面,看起來不美觀,還很容易搞混,有沒有最佳化方案? 可以把四個storyBoard分別開來,單獨放到一個介面裡面 3.怎麼把storyBoard單獨放在一個介面,而且還讓這些介面有聯絡(連線)? 可以用storyBoard reference 來解決 就是用一個引用來代替storyBoard,保持storyBoard間的聯絡(連線) 4.最終效果
三.二維碼的產生 1.產生二維碼的步驟 1.1 建立濾鏡 CIFilter 濾鏡屬於CoreImage架構,要匯入該架構 該架構將常用來處理圖片(產生毛半透明效果/二維碼) 1.2 給濾鏡設定內容(用kvc方式賦值) 內容必須為NSData類型 1.3 擷取產生的二維碼圖片 擷取的圖片是CIImage類型的,使用的話要進行轉換 2.運行程式發現產生的二維碼圖片很模糊,為什麼? 產生為二維碼圖片大小為 27 * 27 被展開的太大,所以不清晰 3.怎麼顯示清晰的二維碼? 蘋果提供一個api(CIImage的方法)對圖片放大,還不影響清晰度
1 // 1.建立Transform orginalImage的資料類型為CIImage2 let scale = imageView.bounds.width / orginalImage.extent.width3 let transform = CGAffineTransformMakeScale(scale, scale)4 // 2.放大圖片5 let hdImage = orginalImage.imageByApplyingTransform(transform)
4.設定前景圖片 4.1 為什麼要設定前景圖片? 一般二維碼中心都有一張小的圖片,就是前景圖片 產生二維碼沒有前景圖片,需要手動添加前景圖片 4.2 怎麼添加前景圖片? 就是把兩張圖片合成為一張圖片,用繪圖就可以輕鬆搞定 4.3 繪圖的步驟 4.31 開啟圖形上下文 4.32 將二維碼圖片畫到圖形上下文(二維碼的size = 圖形內容相關的size) 4.33 將前景圖片畫到圖形上下文(前景圖片的center = 圖形內容相關的center) 4.34 從圖形上下文擷取新的圖片 4.35 關閉圖形上下文 四.二維碼的識別 1.擷取相簿中的二維碼 1.1 怎麼擷取相簿? 1.11 建立照片選擇控制器 1.12 設定照片的來源類型 1.13 設定代理 1.14 彈出控制器
// 1.建立照片選擇控制器 let ipc = UIImagePickerController() // 2.設定來源的類型 ipc.sourceType = .PhotoLibrary // 3.設定代理 ipc.delegate = self // 4.彈出控制器 presentViewController(ipc, animated: true, completion: nil) 在代理方法中實現 選中圖片dismiss掉控制器 func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { //選中照片 imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage picker.dismissViewControllerAnimated(true, completion: nil) }
2.識別二維碼的步驟 2.1 建立 CIDetector對象(辨識器) 2.2 擷取圖片,並將圖片轉成 CIIImage 2.3 識別圖片中的二維碼(得到一個數組,圖片中可能有多個二維碼) 2.4 遍曆數組
// 1.建立辨識器 let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: nil) // 2.擷取圖片,並且將圖片轉成CIIImage let image = imageView.image! guard let ciImage = CIImage(image: image) else { return } // 3.識別圖片中二維碼 let features = detector.featuresInImage(ciImage) // 4.遍曆數組中所有的元素 for f in features { // feature類型是CIFeature 要轉換成二維碼類型 CIQRCodeFeature guard let qrCodeF = f as? CIQRCodeFeature else { continue } //列印二維碼的資訊 print(qrCodeF.messageString) }
五.掃描二維碼(需要真機操作) 1.掃描二維碼介面搭建 1.1 主要就是掃描框的搭建 掃描框中再加上一個ImageView,給ImageView一個動畫 類比正在掃描(衝擊波) 1.2 掃描框是一張圖片,衝擊波也是一張圖片,他們的位置和尺寸是一樣的 為了方便以後更改控制項的位置,可以用一個view把掃描框和衝擊波封裝在裡面 1.3 掃描動畫(衝擊波)動畫怎麼做? 1.31 設定衝擊波的底部約束相對於父控制項(view)有一個間距 1.32 更改約束的間距,來達到動畫的效果
// 1.改變約束(原來約束為-240) scanViewBottomCons.constant = 240 // 2.執行動畫 UIView.animateWithDuration(1.0) { UIView.setAnimationRepeatCount(MAXFLOAT) self.qrCodeView.layoutIfNeeded() }
2.掃描二維碼 2.1 掃描步驟 2.11 建立捕捉會話(需要匯入AVFoundation架構) 2.12 設定輸入(網路攝影機) 2.13 設定輸出 Metadata 2.14 添加預覽圖層(可以沒有) 預覽圖層是為了讓使用者知道掃描到哪裡了,一般為了使用者體驗,都會添加 2.15 開始掃描 原始碼:建議不要死記,用的時候直接拷貝
// 1.建立捕捉會話 let session = AVCaptureSession() // 2.設定輸入(網路攝影機) let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) guard let input = try? AVCaptureDeviceInput(device: device) else { return } session.addInput(input) // 3.設定輸出(Metadata) let output = AVCaptureMetadataOutput() // 設定代理 output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) session.addOutput(output) // 設定output的輸出的類型(該類型的設定必須在添加到session之後) output.metadataObjectTypes = [AVMetadataObjectTypeQRCode] // 4.添加預覽圖層(可以沒有) let previewLayer = AVCaptureVideoPreviewLayer(session: session) previewLayer.frame = view.bounds view.layer.insertSublayer(previewLayer, atIndex: 0) // 5.開始掃描 session.startRunning()
3.擷取掃描結果 3.1設定代理,在代理方法中拿到結果 代理方法
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) { guard let objc = metadataObjects.last as? AVMetadataMachineReadableCodeObject else { return } print(objc.stringValue) }
5.設定掃描地區. 5.1 為什麼要設定掃描地區? 掃描二維碼,發現只要二維碼進入網路攝影機地區,就能直接掃描 要求是進入掃描框,才進行掃描 5.2 怎麼設定掃描地區? 通過設定 output.rectOfInterest屬性來設定掃描地區
// 設定掃描的地區 let screenW = UIScreen.mainScreen().bounds.width let screenH = UIScreen.mainScreen().bounds.height let x : CGFloat = qrCodeView.frame.origin.x / screenW let y : CGFloat = qrCodeView.frame.origin.y / screenH let w : CGFloat = qrCodeView.frame.width / screenW let h : CGFloat = qrCodeView.frame.height / screenH output.rectOfInterest = CGRect(x: y, y: x, width: h, height: w)
注意:掃描地區的座標系與螢幕的座標系正好相反 ( 掃描地區x = 螢幕座標系 y)
5.3 設定掃描地區代碼寫到哪裡? 掃描地區屬於 輸出的一個屬性,應該寫到建立輸出代碼的後邊