上篇文章iOS_最全的二維碼篇說要給大家簡紹一下強大而好玩工具CIFilter
,所以這今天晚上給大家分享一個demo。我保證你看了這篇文章之后,肯定能做出自己的美圖工具,我發誓(雖然并沒卵用)。
CIFilter
,其實就是一個濾鏡。喜歡攝影的小伙伴,可能接觸過PS,而接觸過PS的小伙伴,對濾鏡肯定不陌生。而且有了解相關知識的小伙伴,對于顏色和圖片處理的認知也一定信手捏來。什么RGB,什么CMYK,什么灰度圖片,什么高斯模糊,什么銳化,什么對比度,什么飽和度,什么顏色通道,為什么值在255之間等等。我為什么知道這些,其實小Jorn我大一的時候,剛上大學,課不是很多,時間充足,那時候,都還不知道LOL(呵呵,現在,此處省略1W字),還帶著高中的稚氣和志氣。想想要學點啥一技之長。記得高中時候,有次去拍一寸照,看那sb老板,不懂PS,硬是給我照片亂修。結果照片老丑,還硬坑我20塊錢。所以大學就想到自己學學PS,在處理照片的時候可以自己修。而且,PS還可以做很多平面設計。說不定以后可以去做設計的工作。一個好的設計師,薪資還是很高的(_)。所以自己學了一年多的PS(堪稱大神了,然并卵),后來學的差不多了。海報設計,網頁設計,UI設計,還有其他各種設計,圖文排版,圖片處理,婚紗處理,P圖等什么滴都自己做過(厲害吧)。大二的時候又學了一年的AI,后來還想學AE來著(因為大學嘛,越到后來,你懂得。游戲也開始玩起來了)。學了PS和AI,其實我還是覺得很不錯的,不只在一個地方看到,PS和AI就像左右手,這也是做平面設計的工作者必備的兩技能。一個負責位圖,一個負責矢量圖,功能都超強大。現在iOS上用的icon基本都是用這兩工具設計的。雖然現在不慎混到了程序猿的大流。不過想想懂這也不是無可用武之地,至少在圖片處理,顏色的認知上還有挺有幫助的(呵呵,安慰一下自己)。(扯遠了。。。)
言歸正傳,你學會使用CIFilter
,你就可以隨意處理你想要的效果。系統給我們提供的濾鏡種類是非常的多,不是十幾個,是幾十個。沒錯!
CoreImage
是個非常強大框架,集圖片的幾乎所有操作編輯于一身,CIFilter
只是其中的一個工具,主要作用是給圖片渲染不同的效果
CIFilter
的種類很多,所以蘋果的官方文檔也只能給出部分常用的種類的說明。
官方文檔給出的部分說明:點擊這里
雖然官方文檔很簡潔,但國外的大神們已經證明這是個相當強悍的框架,
不僅功能強大,而且可以直接使用GPU
,效率奇高,甚至可以實時的對視頻進行渲染。下面讓我們來看看,如何具體使用它:
首先你需要導入CoreImage.framework
框架;進行Mac(不是iOS)開發的同學請導入QuartzCore.framework
框架,包含在其中了。
然后我們先來看看3個主要的類:
CIContext
:它與CoreGraphics
和OpenGL context
類似,所有CoreImage
的處理流程都通過它來進行;
CIImage
:它用來存放圖片數據,可以通過UIImage
,圖片文件或像素數據創建;
CIFilter
:通過它來定義過濾器的詳細屬性。
CIContext
有兩種初始化方法,分別對應GPU
和CPU
創建基于GPU的CIContext
對象
context = [CIContext contextWithOptions: nil];
創建基于CPU的CIContext
對象
context = [CIContext contextWithOptions: [NSDictionarydictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:kCIContextUseSoftwareRenderer]];
一般采用第一種基于GPU的,因為效率要比CPU高很多,但是要注意的是基于GPU的CIContext
對象無法跨應用訪問。 比如你打開UIImagePickerController
要選張照片進行美化,如果你直接在UIImagePickerControllerDelegate
的委托方法里調用CIContext
對象進行處理,那么系統會自動將其降為基于CPU的,速度會變慢,所以正確的方法應該是在委托方法里先把照片保存下來,回到主類里再來處理。
CIFilter
的強大之處在于,可以疊加來得到多種效果。看過iOS_最全的二維碼篇這篇文章的小伙伴肯定知道了什么叫疊加,其實如果你按那篇文章我說的練習一下,你就會發現,得到的圖片也還是不過清晰。因為,二維碼生成的原圖太小,放大就很模糊。其實我在用PS處理手機拍的圖片時,一開始少不了這三步,補點光,太暗;增加的對比度,不夠鮮明;銳化一下,細節不過清晰。對,就是銳化一下。等下會讓你獲得一副清晰的二維碼圖。
首先讓你知道,怎么查看到底有哪些濾鏡:
/* Categories */
// public let kCICategoryDistortionEffect: String ///失真效果
// public let kCICategoryGeometryAdjustment: String ///幾何調整
// public let kCICategoryCompositeOperation: String ///復合操作
// public let kCICategoryHalftoneEffect: String ///半色調效果
// public let kCICategoryColorAdjustment: String ///顏色調整
// public let kCICategoryColorEffect: String ///顏色效果
// public let kCICategoryTransition: String ///翻轉
// public let kCICategoryTileEffect: String ///瓦片效果
// public let kCICategoryGenerator: String ///生成器
// @available(iOS 5.0, *)
// public let kCICategoryReduction: String ///削減
// public let kCICategoryGradient: String ///梯度
// public let kCICategoryStylize: String ///風格
// public let kCICategorySharpen: String ///銳化
// public let kCICategoryBlur: String ///模糊
// public let kCICategoryVideo: String ///視頻
// public let kCICategoryStillImage: String ///靜態圖片
// public let kCICategoryInterlaced: String ///交叉
// public let kCICategoryNonSquarePixels: String ///非方形像素
// public let kCICategoryHighDynamicRange: String ///高動態范圍
// public let kCICategoryBuiltIn: String ///內建
// @available(iOS 9.0, *)
// public let kCICategoryFilterGenerator: String ///濾鏡生成器
這是系統含有的所有大類。
想知道有哪些filter類型或想查找想要的filter類型,可以通過先查找大的分類(如上),然后在查找子項。
let names = CIFilter.filterNames(inCategory: kCICategoryGenerator) ///kCICategoryGenerator大類
print(names)
這樣就會輸出該大類包含的所有濾鏡。如上會輸出所有的生成器類型CIFilter
種類:
///生成器大類所包含的所有生成器子類,如:"`CICode128BarcodeGenerator`"(條形碼生成器),"CIQRCodeGenerator"(二維碼生成器)
// ["CIAztecCodeGenerator",
// "CICheckerboardGenerator",
// "CICode128BarcodeGenerator", ///條形碼生成器
// "CIConstantColorGenerator",
// "CILenticularHaloGenerator",
// "CIPDF417BarcodeGenerator",
// "CIQRCodeGenerator", ///二維碼生成器
// "CIRandomGenerator",
// "CIStarShineGenerator",
// "CIStripesGenerator",
// "CISunbeamsGenerator"]
然后就可以創建濾鏡對象了,有兩方法,含參數的僅iOS8之后可用,iOS上不設輸入參數,系統會使用默認值,但是mac是會報錯,輸入參數不明確:
/** Creates a new filter of type 'name'.
On OSX, all input values will be undefined.
On iOS, all input values will be set to default values. */
/// 要是是mac開發,創建filter對象必須提供輸入參數,iOS可以忽略,系統會使用默認值。
//init?(name: String)
//@available(iOS 8.0, *) ///iOS 8.0 之后
//init?(name: String, withInputParameters params: [String : Any]?)
看看該濾鏡需要設置那些輸入參數,如此:
let filter = CIFilter(name: "CIQRCodeGenerator")
let inpoutkeys = filter?.inputKeys ///查看這個filter的所有輸入參數
let outputKeys = filter?.outputKeys ///查看這個filter的所有輸出參數
print("inpoutkeys:",inpoutkeys)
print("outputKeys:",outputKeys)
設置參數用KVC來設置,常用的key,系統已經作為常量給出,可以cmd加鼠標左鍵點擊CIFilter
類名進去查看。
如上,二維碼生成器濾鏡需要量輸入參數:
///eg.1 ///示例代碼KVO
/// 1. 實例化二維碼濾鏡
let filter = CIFilter(name: "CIQRCodeGenerator")///二維碼
/// 2. 恢復濾鏡的默認屬性 ///值得注意
filter?.setDefaults()
/// 3. 將字符串轉換成二進制數據,(生成二維碼所需的數據)
let string = "hello word"
let data = string.data(using: String.Encoding.utf8)///Swift 3.0
/// 4. 通過KVO把二進制數據添加到濾鏡inputMessage中
filter?.setValue(data, forKey: "inputMessage")
filter?.setValue("H", forKey: "inputCorrectionLevel")
/// 5. 獲得濾鏡輸出的圖像
let outputImage = filter?.outputImage ///CIImage
/// 6. 將CIImage轉換成UIImage,并放大顯示
//let originQRCodeImage = UIImage(ciImage: outputImage!, scale: 0.07, orientation: UIImageOrientation.up) ///原生二維碼圖片 ///這樣將圖片放大會變得模糊
這樣得到的originQRCodeImage
是模糊的,把scale
設為一時得到實際大小,但太小。在上篇文章我提過,需要進行重繪(效果80分)。這里我們可以使用縮放濾鏡來縮放。生產高質量的、按比例縮放的源圖像的版本(這是文檔說明,然我并沒發現有啥牛掰,還是模糊)。
CIFilter
為"CILanczosScaleTransform
"(蘭索斯縮放變化濾鏡),但為了達到彩色的效果我們先把顏色濾鏡加上,CIFliter
為"CIFalseColor
"(偽色濾鏡):
let colorFilter = CIFilter(name: "CIFalseColor")///顏色濾鏡
colorFilter!.setDefaults()
colorFilter!.setValue(outputImage
, forKey:kCIInputImageKey)
colorFilter!.setValue(CIColor(red: 33.0 / 225.0, green: 192.0 / 225.0, blue: 174.0 / 225.0, alpha: 1.0), forKey:"inputColor0")///二維碼元素(像素)
colorFilter!.setValue(CIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1), forKey:"inputColor1")///背景
let colorImgae = colorFilter!.outputImage
let scaleFilter = CIFilter(name: "CILanczosScaleTransform") ///蘭索斯縮放變化濾鏡
scaleFilter?.setDefaults()
scaleFilter?.setValue(colorImgae, forKey: kCIInputImageKey)
scaleFilter?.setValue(1.0, forKey: kCIInputScaleKey)
scaleFilter?.setValue(1.0, forKey: kCIInputAspectRatioKey)
let scaleImage = scaleFilter?.outputImage
所以通過添加銳化濾鏡來銳化一下,CIFilter
為"CISharpenLuminance
"(亮度銳化,對光度有作用,度色度沒影響):
let sharpenFilter = CIFilter(name: "CISharpenLuminance") ///細節銳化濾鏡
///It operates on the luminance of the image; the chrominance of the pixels remains unaffected.
sharpenFilter?.setDefaults()
sharpenFilter?.setValue(scaleImage, forKey: kCIInputImageKey)
sharpenFilter?.setValue(10.0, forKey: kCIInputSharpnessKey)
let sharpenImage = sharpenFilter?.outputImage
最后得到圖片:
let newQRCodeImage = UIImage(ciImage: sharpenImage!)
let imgBtn = UIButton(type: .custom)
imgBtn.frame = self.view.frame
imgBtn.setImage(newQRCodeImage, for: .normal)
self.view.addSubview(imgBtn)
通過參數的設置,得到的圖片效果70分;
而在進行重繪后,再進行銳化處理的話,你就會發現效果是真的不錯(95分)。
因為升為了Switft3.0代碼,所以代碼需要少量修改。主要就是Swift3.0把CoreGraphics
的全局方法改為了實例方法,
func createUIimageWithCGImage(ciImage image: CIImage, widthAndHeightValue wh: CGFloat) -> CIImage {
let ciRect = image.extent.integral///根據容器得到適合的尺寸
let scale = min(wh / ciRect.width, wh / ciRect.height)
///獲取bitmap
let width = size_t(ciRect.width * scale)
let height = size_t(ciRect.height * scale)
let cs = CGColorSpaceCreateDeviceGray()///灰度顏色通道 ///CGColorSpaceRef
let info_UInt32 = CGImageAlphaInfo.none.rawValue
let bitmapRef = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: info_UInt32)
let contex = CIContext(options: nil) /// 創建基于GPU的CIContext對象,性能和效果更好
let bitmapImageRef = contex.createCGImage(image, from: CGRect(x: ciRect.origin.x, y: ciRect.origin.y, width: ciRect.size.width, height: ciRect.size.height)) ///CGImageRef
///swift 3.0, 把全局方法改為了實例方法
bitmapRef!.interpolationQuality = CGInterpolationQuality.high///寫入質量高,時間長
bitmapRef!.scaleBy(x: scale, y: scale) ///調整“畫布”的縮放
bitmapRef?.draw(bitmapImageRef!, in: ciRect, byTiling: true)///繪制圖片
///保存
let scaledImage = bitmapRef!.makeImage() ///cgimage
///bitmapRef和bitmapImageRef不用主動釋放,Core Foundation自動管理
//let originImage = UIImage(CGImage: scaledImage!) ///原生灰度圖片(灰色)
let ciImage = CIImage(cgImage: scaledImage!) ///ciimage
//let newQRCodeImage = UIImage(cgImage: scaledImage!) ///uiimage
return ciImage
}
附錄:
///附:你要是細心,或者有點好奇心,你可能會問,為什么我們看到的二維碼中間都有一個小圖片,
///確實現在的大多二維碼生成工具都喜歡中間貼上一個小圖,但是上述生成的二維碼并沒有,
///其實這很簡單,這也是我沒有在這個小問題給出示例的原因。其實二維碼在缺少小部分的情況下,并不影響存儲信息的完整性
///所以小圖片是另外加上去的,只是遮掉了一小塊二維碼內容,這并不影響什么。
///然而在一張圖上添加另一張圖,相信你也覺得這并不是什么問題。自己試試吧。
///如:用quartz2D 、drawImga的方法即可。
下圖:1.銳化;2.重繪;3.重繪+銳化