最近在項目中遇到了涉及二維碼相關(guān)的問題, 這里想記錄總結(jié)一下二維碼相關(guān)技術(shù)
一. 二維碼的介紹
- 二維條碼/二維碼是用某種特定的幾何圖形按一定規(guī)律在平面分布的黑白相間的圖形記錄數(shù)據(jù)符號信息的
- 總結(jié): 用圖形記錄標記一些信息,方便通過圖形識別來獲取信息
- 應(yīng)用場景
- 信息獲仁中(名片筐高、地圖云头、WIFI密碼、資料)
- 手機電商(用戶掃碼骡技、手機直接購物下單)
- 手機支付(掃描商品二維碼,通過銀行或第三方支付提供的手機端通道完成支付)
- 微信添加好友
二. 二維碼的生成
- 生成二維碼的方式
- 采用第三方框架(放棄)
- ZXing/ZBar
- 框架不支持64位(2015年2月1號起, - 不允許不支持64位處理器的APP 上架)
- 系統(tǒng)自帶API
- 采用第三方框架(放棄)
- 生成二維碼的步驟
- 創(chuàng)建二維碼濾鏡--CIFilter
- 恢復(fù)濾鏡的默認屬性
- 設(shè)置濾鏡的輸入數(shù)據(jù)
- 將傳入的字符串轉(zhuǎn)換成Data(OC為NSData)數(shù)據(jù)
- 通過KVC來設(shè)置輸入的內(nèi)容
inputMessage
1. 二維碼容錯率
filter?.setValue("H", forKey: "inputCorrectionLevel")
-
inputCorrectionLevel
是一個單字母(@"L", @"M", @"Q", @"H" 中的一個)羞反,表示不同級別的容錯率布朦,默認為 @"M". - QR碼有容錯能力,QR碼圖形如果有破損昼窗,仍然可以被機器讀取內(nèi)容是趴,最高可以到7%~30%面積破損仍可被讀取,相對而言,容錯率愈高澄惊,QR碼圖形面積愈大唆途。所以一般折衷使用15%容錯能力。
- L水平 7%的字碼可被修正.
- M水平 15%的字碼可被修正
- Q水平 25%的字碼可被修正
- H水平 30%的字碼可被修正
- 代碼:
/* * @param inputMsg 二維碼保存的信息
* @param fgImage 前景圖片 */
func generateCode(inputMsg: String, fgImage: UIImage?) -> UIImage {
//1. 將內(nèi)容生成二維碼
//1.1 創(chuàng)建濾鏡
let filter = CIFilter(name: "CIQRCodeGenerator")
//1.2 恢復(fù)默認設(shè)置
filter?.setDefaults()
//1.3 設(shè)置生成的二維碼的容錯率
//value = @"L/M/Q/H"
filter?.setValue("H", forKey: "inputCorrectionLevel")
// 2.設(shè)置輸入的內(nèi)容(KVC)
// 注意:key = inputMessage, value必須是NSData類型
let inputData = inputMsg.data(using: .utf8)
filter?.setValue(inputData, forKey: "inputMessage")
//3. 獲取輸出的圖片
guard let outImage = filter?.outputImage else { return UIImage() }
//4. 獲取高清圖片
let hdImage = getHDImage(outImage)
//5. 判斷是否有前景圖片
if fgImage == nil{
return hdImage
}
//6. 獲取有前景圖片的二維碼
return getResultImage(hdImage: hdImage, fgImage: fgImage!)
}
2. 獲取高清圖片
//4. 獲取高清圖片
fileprivate func getHDImage(_ outImage: CIImage) -> UIImage {
let transform = CGAffineTransform(scaleX: 10, y: 10)
//放大圖片
let ciImage = outImage.transformed(by: transform)
return UIImage(ciImage: ciImage)
}
3. 將圖片合成到二維碼中
- 需要用到圖形上下文
- 將二維碼畫到圖形上下文
- 將圖片合成到圖行上下文
//獲取前景圖片
fileprivate func getResultImage(hdImage: UIImage, fgImage: UIImage) -> UIImage {
let hdSize = hdImage.size
//1. 開啟圖形上下文
UIGraphicsBeginImageContext(hdSize)
//2. 將高清圖片畫到上下文
hdImage.draw(in: CGRect(x: 0, y: 0, width: hdSize.width, height: hdSize.height))
//3. 將前景圖片畫到上下文
let fgWidth: CGFloat = 80
fgImage.draw(in: CGRect(x: (hdSize.width - fgWidth) / 2, y: (hdSize.height - fgWidth) / 2, width: fgWidth, height: fgWidth))
//4. 獲取上下文
guard let resultImage = UIGraphicsGetImageFromCurrentImageContext() else { return UIImage() }
//5. 關(guān)閉上下文
UIGraphicsEndImageContext()
return resultImage
}
后續(xù)會研究彩色二維碼的黑科技, 敬請期待...
識別二維碼
識別圖片中二維碼步驟
- 創(chuàng)建探測器
- 屬于CoreImage框架(CIDetector)
- 獲取CIImage類型的圖片
- 獲取圖片中所有符合特征的內(nèi)容(CIQRCodeFeature)
- 遍歷所有的特性(CIQRCodeFeature)
- 獲取特征中代表的信息(messageString)
- 識別二維碼的代碼實現(xiàn)
/* * @param qrCodeImage 二維碼的圖片
* @return 結(jié)果的數(shù)組 */
func recognitionQRCode(qrCodeImage: UIImage) -> [String]? {
//1. 創(chuàng)建過濾器
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: nil)
//2. 獲取CIImage
guard let ciImage = CIImage(image: qrCodeImage) else { return nil }
//3. 識別二維碼
guard let features = detector?.features(in: ciImage) else { return nil }
//4. 遍歷數(shù)組, 獲取信息
var resultArr = [String]()
for feature in features {
resultArr.append(feature.type)
}
return resultArr
}
三. 二維碼的掃描
- 創(chuàng)建輸入設(shè)備(攝像頭)
- 獲取攝像頭設(shè)備
- 創(chuàng)建輸入對象
- 創(chuàng)建輸出設(shè)置(元數(shù)據(jù))
- 創(chuàng)建輸出對象
- 設(shè)置輸出對象的代理(在代理中獲取掃描到的數(shù)據(jù))
- 設(shè)置輸出數(shù)據(jù)的類型
- 創(chuàng)建捕捉會話
- 將輸入添加到會話中
- 將輸出添加到會話中
- 添加預(yù)覽圖片(方便用于查看)
- 創(chuàng)建圖層,將圖片添加到View圖層中
- 開始掃描
1. 懶加載輸入輸出中間會話
//輸入輸出中間橋梁(會話)
fileprivate lazy var session : AVCaptureSession = AVCaptureSession()
2. 初始化掃描設(shè)備
2.1. 注意: AVCaptureMetadataOutputObjectsDelegate
的代理設(shè)置, 該協(xié)議中的方法會將掃描的結(jié)果返回
fileprivate func addScaningVideo(){
//1.獲取輸入設(shè)備(攝像頭)
guard let device = AVCaptureDevice.default(for: .video) else { return }
//2.根據(jù)輸入設(shè)備創(chuàng)建輸入對象
guard let deviceInput = try? AVCaptureDeviceInput(device: device) else { return }
//3.創(chuàng)建原數(shù)據(jù)的輸出對象
let metadataOutput = AVCaptureMetadataOutput()
//4.設(shè)置代理監(jiān)聽輸出對象輸出的數(shù)據(jù)掸驱,在主線程中刷新
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
//5.創(chuàng)建會話(橋梁)
// let session = AVCaptureSession()
//6.添加輸入和輸出到會話
if session.canAddInput(deviceInput) {
session.addInput(deviceInput)
}
if session.canAddOutput(metadataOutput) {
session.addOutput(metadataOutput)
}
//7.告訴輸出對象要輸出什么樣的數(shù)據(jù)(二維碼還是條形碼),要先創(chuàng)建會話才能設(shè)置
metadataOutput.metadataObjectTypes = [.qr, .code128, .code39, .code93, .code39Mod43, .ean8, .ean13, .upce, .pdf417, .aztec]
//8.創(chuàng)建預(yù)覽圖層
let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = .resizeAspectFill
previewLayer.frame = view.bounds
view.layer.insertSublayer(previewLayer, at: 0)
//9.設(shè)置有效掃描區(qū)域(默認整個屏幕區(qū)域)(每個取值0~1, 以屏幕右上角為坐標原點)
let rect = CGRect(x: scanImageView.frame.minY / kScreenHeight, y: scanImageView.frame.minX / kScreenWidth, width: scanImageView.frame.height / kScreenHeight, height: scanImageView.frame.width / kScreenWidth)
metadataOutput.rectOfInterest = rect
//10. 開始掃描
session.startRunning()
}
2.2 代理方法的實現(xiàn)
- 需要將掃描的結(jié)果轉(zhuǎn)化成機器可讀的編碼數(shù)據(jù),才能獲取二維碼的相關(guān)信息
extension ScaningViewController: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
//1. 取出掃描到的數(shù)據(jù): metadataObjects
//2. 以震動的形式告知用戶掃描成功
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
//3. 關(guān)閉session
session.stopRunning()
//4. 遍歷結(jié)果
var resultArr = [String]()
for result in metadataObjects {
//轉(zhuǎn)換成機器可讀的編碼數(shù)據(jù)
if let code = result as? AVMetadataMachineReadableCodeObject {
resultArr.append(code.stringValue ?? "")
}else {
resultArr.append(result.type.rawValue)
}
}
//5. 將結(jié)果
let vc = ShowViewController()
vc.scanDataArr = resultArr
navigationController?.pushViewController(vc, animated: true)
}
}
項目地址: Github
- 感謝大家的支持
其他相關(guān)文章
- Swift之二維碼的生成肛搬、識別和掃描
- iOS黑科技之(CoreImage)靜態(tài)人臉識別(一)
- iOS黑科技之(AVFoundation)動態(tài)人臉識別(二)
- Swift之Vision 圖像識別框架