在iOS中有個類CIFilter,通過這個類可以創建各種特定的過濾器,今天我們主要介紹一種二維碼發生器(CIQRCodeGenerator)濾鏡,通過這個濾鏡可以自動生成我們需要的二維碼。
首先我們要創建一個二維碼濾鏡:
//創建二維碼濾鏡 let qrCIFilter = CIFilter(name: "CIQRCodeGenerator")
注意,這個初始化方法中的傳入參數是只有固定的幾種字符串的,使用不同的字符串可以創建不同用處的濾鏡的。所以在官方的參考文檔中特別說明在創建以後要檢查qrCIFilter是否為空,以防拼寫錯誤無法創建濾鏡。如果我們想知道到底有哪幾種固定的字符串可以在Xcode中command+右鍵點擊CIQRCodeGenerator字符串,跳到的參考文獻上下文中有其他固定值的介紹的。
濾鏡創建出來了,我們還要給這濾鏡添加各種屬性,濾鏡的屬性是一對一對的鍵值對的,同樣的這個屬性字典的key值也是固定的,二維碼濾鏡有兩種屬性inputMessage和inputCorrectionLevel,在iOS中,濾鏡的屬性如果你不特別設置那麼系統會給一個默認值,所以你無需再統一設置默認值。inputMessage指輸入信息,具體來說就是你要加密的的字符串,但是value值是NSData類型的,inputCorrectionLevel指輸入的糾錯級別,有四種不同的級別:A single letter specifying the error correction format. An NSString object whose display name is CorrectionLevel不多說了,看代碼:
//二維碼包含的信息 qrCIFilter!.setValue(messageData, forKey: "inputMessage") //L7% M15% Q25% H%30% 糾錯級別. 默認值是M qrCIFilter!.setValue("H", forKey: "inputCorrectionLevel")
到這一步其實你已經創建了一個最簡單的二維碼了,你可以輸出過濾後的圖片了:
let qrImage = qrCIFilter?.outputImage
這裡qrImage是CIImage類型的,你可以通過這個qrImage創建一個UIImage類型的圖片,然後放到UIImageView視圖顯示出來,但是你會發現這個二維碼會非常模糊,我們要對它進一步處理。
在這裡先感謝一下航哥的無私奉獻,下面的處理我也是看到他的分享後才知道可以這麼做的。我們在上面的基礎上再創建一個濾鏡CIFalseColor,我查了下官方文檔度這種濾鏡的說明簡單:False color is often used to process astronomical and other scientific data, such as ultraviolet and x-ray images,其實它的用處是用來偽造顏色的。CIFalseColor只有三個固定的屬性inputImage,inputColor0,inputColor1。這三屬性很好理解,直接看代碼:
let colorFilter = CIFilter(name: "CIFalseColor") //輸入圖片 colorFilter!.setValue(qrImage, forKey: "inputImage") //輸入顏色 colorFilter!.setValue(CIColor(red: 0,green: 0,blue: 0), forKey: "inputColor0") colorFilter!.setValue(CIColor(red: 1,green: 1,blue: 1), forKey: "inputColor1")
然後我們再對圖片進行縮放(縮放後圖片會很清晰),並且轉換成UIImage類型:
var image = UIImage(CIImage: colorFilter!.outputImage! .imageByApplyingTransform(CGAffineTransformMakeScale(5, 5)))
到這裡我們的二維碼圖片已經生成完畢了,但是我們常常會在二維碼中間放置圖片來做個性化處理。這個就相當於在圖片中再添加一個圖片,處理起來就比較簡單了,其實就四個步驟:第一開啟上下文;第二圖片重繪這裡我們要重繪兩張圖片一張是二維碼圖片一張是個性化圖片;第三是通過上下文獲取圖片;第三是關閉上下文。
//開啟上下文 UIGraphicsBeginImageContext(frame.size) //二維碼圖片重繪(二維碼圖片如果不繪制,獲取的圖片無法反過來創建CIImage) image.drawInRect(frame) if let myImage = UIImage(named:andImageName) { //個性圖片尺寸 let mySize = CGSizeMake(frame.size.width/4, frame.size.height/4) //重繪自定義圖片 myImage.drawInRect(CGRectMake(frame.size.width/2-mySize.width/2, frame.size.height/2-mySize.height/2, mySize.width, mySize.height)) } //從上下文獲取圖片 image = UIGraphicsGetImageFromCurrentImageContext() //關閉上下文 UIGraphicsEndImageContext()
下面我們再看看二維碼的識別,先創建一個長按手勢:
let longTap = UILongPressGestureRecognizer(target: self, action: #selector(longPress)) self.view .addGestureRecognizer(longTap)
然後當長按時我們解析我們的二維碼。解析二維碼要創建探測器,探測器有不同的類型,這裡創建一個簡單的二維碼探測器。
創建探測器有幾個傳入參數:探測器類型、上下文、屬性選項:
/*創建探測器 options 是字典key: CIDetectorAccuracy 精度 CIDetectorTracking 軌跡 CIDetectorMinFeatureSize 最小特征尺寸 CIDetectorNumberOfAngles 角度**/ let dector = CIDetector(ofType: CIDetectorTypeQRCode, context: CIContext(), options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
然後我們再創建一個CIImage類型的圖片,探測器會探測出這張圖片裡面的所有二維碼:
let qrFeatures = dector.featuresInImage(decodeImage!) as! [CIQRCodeFeature]
上面的代碼中qrFeatures值是一個數組,元素類型是CIQRCodeFeature(二維碼特征),CIQRCodeFeature有個屬性messageString表示二維碼所代表的信息。
怎麼樣長按識別二維碼是不是很簡單。下面的是整個demo的源碼,有興趣的可以參考下:
// // ViewController.swift // 通過濾鏡CIFilter生成二維碼 // // Created by 句芒 on 16/8/17. // Copyright ? 2016年 fanwei. All rights reserved. // import UIKit class ViewController: UIViewController { let imageView = UIImageView(frame: CGRect(x: 30, y: 50, width: 200, height: 200)) let pictureView = UIImageView(frame: CGRect(x: 50, y: 270, width: 200, height: 200)) override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. imageView.image = createQRCodeByCIFilterWithString("句芒二維碼發生器", andImageName:"") self.view .addSubview(imageView) pictureView.image = createQRCodeByCIFilterWithString("http://www.jubaobar.com", andImageName: "jubaobar.jpg") self.view.addSubview(pictureView) let longTap = UILongPressGestureRecognizer(target: self, action: #selector(longPress)) self.view .addGestureRecognizer(longTap) let data = UIImagePNGRepresentation(pictureView.image!) let path = NSHomeDirectory().stringByAppendingString("/Documents/s.png") data!.writeToFile(path, atomically: true) print(path) } func longPress(recoginzer:UILongPressGestureRecognizer) { let point = recoginzer.locationInView(self.view) if imageView.frame.contains(point) { return show(decodeQRCode(imageView.image!)) } if pictureView.frame.contains(point) { return show(decodeQRCode(pictureView.image!)) } } func decodeQRCode(image:UIImage) -> String { let decodeImage = CIImage(image: image) /*創建探測器 options 是字典key: CIDetectorAccuracy 精度 CIDetectorTracking 軌跡 CIDetectorMinFeatureSize 最小特征尺寸 CIDetectorNumberOfAngles 角度**/ let dector = CIDetector(ofType: CIDetectorTypeQRCode, context: CIContext(), options: [CIDetectorAccuracy:CIDetectorAccuracyHigh]) let qrFeatures = dector.featuresInImage(decodeImage!) as! [CIQRCodeFeature] return qrFeatures.last!.messageString } func show(message:String) { let alert = UIAlertController(title: "二維碼", message: message, preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "知道了", style:.Cancel, handler: nil)) self .presentViewController(alert, animated: true, completion: nil) } func createQRCodeByCIFilterWithString(message:String,andImageName:String) -> UIImage? { if let messageData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) { //創建二維碼濾鏡 let qrCIFilter = CIFilter(name: "CIQRCodeGenerator") //二維碼包含的信息 qrCIFilter!.setValue(messageData, forKey: "inputMessage") //L7% M15% Q25% H%30% 糾錯級別. 默認值是M qrCIFilter!.setValue("H", forKey: "inputCorrectionLevel") let qrImage = qrCIFilter?.outputImage //創建顏色濾鏡主要是了解決二維碼不清晰 False color is often used to process astronomical and other scientific data, such as ultraviolet and x-ray images.通常用於處理紫外線,x射線等天文或科學的數據 let colorFilter = CIFilter(name: "CIFalseColor") //輸入圖片 colorFilter!.setValue(qrImage, forKey: "inputImage") //輸入顏色 colorFilter!.setValue(CIColor(red: 0,green: 0,blue: 0), forKey: "inputColor0") colorFilter!.setValue(CIColor(red: 1,green: 1,blue: 1), forKey: "inputColor1") var image = UIImage(CIImage: colorFilter!.outputImage! .imageByApplyingTransform(CGAffineTransformMakeScale(5, 5))) let frame = CGRectMake(0, 0, image.size.width, image.size.height) //開啟上下文 UIGraphicsBeginImageContext(frame.size) //二維碼圖片重繪(二維碼圖片如果不繪制,獲取的圖片無法反過來創建CIImage) image.drawInRect(frame) if let myImage = UIImage(named:andImageName) { //個性圖片尺寸 let mySize = CGSizeMake(frame.size.width/4, frame.size.height/4) //重繪自定義圖片 myImage.drawInRect(CGRectMake(frame.size.width/2-mySize.width/2, frame.size.height/2-mySize.height/2, mySize.width, mySize.height)) } //從上下文獲取圖片 image = UIGraphicsGetImageFromCurrentImageContext() //關閉上下文 UIGraphicsEndImageContext() return image } return nil } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }