上篇文章iOS_最全的二維碼篇說要給大家簡紹一下強大而好玩工具CIFilter
,所以這今天晚上給大家分享一個demo夯尽。我保證你看了這篇文章之后瞧壮,肯定能做出自己的美圖工具,我發(fā)誓(雖然并沒卵用)匙握。
CIFilter
,其實就是一個濾鏡咆槽。喜歡攝影的小伙伴,可能接觸過PS圈纺,而接觸過PS的小伙伴秦忿,對濾鏡肯定不陌生。而且有了解相關知識的小伙伴蛾娶,對于顏色和圖片處理的認知也一定信手捏來灯谣。什么RGB,什么CMYK蛔琅,什么灰度圖片胎许,什么高斯模糊,什么銳化罗售,什么對比度辜窑,什么飽和度,什么顏色通道寨躁,為什么值在255之間等等穆碎。我為什么知道這些,其實小Jorn我大一的時候朽缎,剛上大學惨远,課不是很多谜悟,時間充足话肖,那時候,都還不知道LOL(呵呵葡幸,現(xiàn)在最筒,此處省略1W字),還帶著高中的稚氣和志氣蔚叨。想想要學點啥一技之長床蜘。記得高中時候,有次去拍一寸照蔑水,看那sb老板邢锯,不懂PS,硬是給我照片亂修搀别。結(jié)果照片老丑丹擎,還硬坑我20塊錢。所以大學就想到自己學學PS,在處理照片的時候可以自己修蒂培。而且再愈,PS還可以做很多平面設計。說不定以后可以去做設計的工作护戳。一個好的設計師翎冲,薪資還是很高的(_)。所以自己學了一年多的PS(堪稱大神了媳荒,然并卵)抗悍,后來學的差不多了。海報設計钳枕,網(wǎng)頁設計檐春,UI設計,還有其他各種設計么伯,圖文排版疟暖,圖片處理,婚紗處理田柔,P圖等什么滴都自己做過(厲害吧)俐巴。大二的時候又學了一年的AI,后來還想學AE來著(因為大學嘛硬爆,越到后來欣舵,你懂得。游戲也開始玩起來了)缀磕。學了PS和AI缘圈,其實我還是覺得很不錯的,不只在一個地方看到袜蚕,PS和AI就像左右手糟把,這也是做平面設計的工作者必備的兩技能。一個負責位圖牲剃,一個負責矢量圖遣疯,功能都超強大。現(xiàn)在iOS上用的icon基本都是用這兩工具設計的凿傅。雖然現(xiàn)在不慎混到了程序猿的大流缠犀。不過想想懂這也不是無可用武之地,至少在圖片處理聪舒,顏色的認知上還有挺有幫助的(呵呵辨液,安慰一下自己)。(扯遠了箱残。滔迈。。)
言歸正傳,你學會使用CIFilter
亡鼠,你就可以隨意處理你想要的效果赏殃。系統(tǒng)給我們提供的濾鏡種類是非常的多,不是十幾個间涵,是幾十個仁热。沒錯!
CoreImage
是個非常強大框架勾哩,集圖片的幾乎所有操作編輯于一身抗蠢,CIFilter
只是其中的一個工具,主要作用是給圖片渲染不同的效果
CIFilter
的種類很多思劳,所以蘋果的官方文檔也只能給出部分常用的種類的說明迅矛。
官方文檔給出的部分說明:點擊這里
雖然官方文檔很簡潔,但國外的大神們已經(jīng)證明這是個相當強悍的框架潜叛,
不僅功能強大秽褒,而且可以直接使用GPU
,效率奇高威兜,甚至可以實時的對視頻進行渲染销斟。下面讓我們來看看,如何具體使用它:
首先你需要導入CoreImage.framework
框架椒舵;進行Mac(不是iOS)開發(fā)的同學請導入QuartzCore.framework
框架蚂踊,包含在其中了。
然后我們先來看看3個主要的類:
CIContext
:它與CoreGraphics
和OpenGL context
類似笔宿,所有CoreImage
的處理流程都通過它來進行犁钟;
CIImage
:它用來存放圖片數(shù)據(jù),可以通過UIImage
泼橘,圖片文件或像素數(shù)據(jù)創(chuàng)建涝动;
CIFilter
:通過它來定義過濾器的詳細屬性。
CIContext
有兩種初始化方法侥加,分別對應GPU
和CPU
創(chuàng)建基于GPU的CIContext
對象
context = [CIContext contextWithOptions: nil];
創(chuàng)建基于CPU的CIContext
對象
context = [CIContext contextWithOptions: [NSDictionarydictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:kCIContextUseSoftwareRenderer]];
一般采用第一種基于GPU的捧存,因為效率要比CPU高很多,但是要注意的是基于GPU的CIContext
對象無法跨應用訪問担败。 比如你打開UIImagePickerController
要選張照片進行美化,如果你直接在UIImagePickerControllerDelegate
的委托方法里調(diào)用CIContext
對象進行處理镰官,那么系統(tǒng)會自動將其降為基于CPU的提前,速度會變慢,所以正確的方法應該是在委托方法里先把照片保存下來泳唠,回到主類里再來處理狈网。
CIFilter
的強大之處在于,可以疊加來得到多種效果⊥夭福看過iOS_最全的二維碼篇這篇文章的小伙伴肯定知道了什么叫疊加勇垛,其實如果你按那篇文章我說的練習一下,你就會發(fā)現(xiàn)士鸥,得到的圖片也還是不過清晰闲孤。因為,二維碼生成的原圖太小烤礁,放大就很模糊讼积。其實我在用PS處理手機拍的圖片時,一開始少不了這三步脚仔,補點光勤众,太暗;增加的對比度鲤脏,不夠鮮明们颜;銳化一下,細節(jié)不過清晰猎醇。對掌桩,就是銳化一下。等下會讓你獲得一副清晰的二維碼圖姑食。
首先讓你知道波岛,怎么查看到底有哪些濾鏡:
/* Categories */
// public let kCICategoryDistortionEffect: String ///失真效果
// public let kCICategoryGeometryAdjustment: String ///幾何調(diào)整
// public let kCICategoryCompositeOperation: String ///復合操作
// public let kCICategoryHalftoneEffect: String ///半色調(diào)效果
// public let kCICategoryColorAdjustment: String ///顏色調(diào)整
// public let kCICategoryColorEffect: String ///顏色效果
// public let kCICategoryTransition: String ///翻轉(zhuǎn)
// 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 ///靜態(tài)圖片
// public let kCICategoryInterlaced: String ///交叉
// public let kCICategoryNonSquarePixels: String ///非方形像素
// public let kCICategoryHighDynamicRange: String ///高動態(tài)范圍
// public let kCICategoryBuiltIn: String ///內(nèi)建
// @available(iOS 9.0, *)
// public let kCICategoryFilterGenerator: String ///濾鏡生成器
這是系統(tǒng)含有的所有大類。
想知道有哪些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"]
然后就可以創(chuàng)建濾鏡對象了,有兩方法彻桃,含參數(shù)的僅iOS8之后可用坛善,iOS上不設輸入?yún)?shù),系統(tǒng)會使用默認值邻眷,但是mac是會報錯眠屎,輸入?yún)?shù)不明確:
/** 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開發(fā),創(chuàng)建filter對象必須提供輸入?yún)?shù)肆饶,iOS可以忽略改衩,系統(tǒng)會使用默認值。
//init?(name: String)
//@available(iOS 8.0, *) ///iOS 8.0 之后
//init?(name: String, withInputParameters params: [String : Any]?)
看看該濾鏡需要設置那些輸入?yún)?shù)驯镊,如此:
let filter = CIFilter(name: "CIQRCodeGenerator")
let inpoutkeys = filter?.inputKeys ///查看這個filter的所有輸入?yún)?shù)
let outputKeys = filter?.outputKeys ///查看這個filter的所有輸出參數(shù)
print("inpoutkeys:",inpoutkeys)
print("outputKeys:",outputKeys)
設置參數(shù)用KVC來設置葫督,常用的key竭鞍,系統(tǒng)已經(jīng)作為常量給出,可以cmd加鼠標左鍵點擊CIFilter
類名進去查看橄镜。
如上偎快,二維碼生成器濾鏡需要量輸入?yún)?shù):
///eg.1 ///示例代碼KVO
/// 1. 實例化二維碼濾鏡
let filter = CIFilter(name: "CIQRCodeGenerator")///二維碼
/// 2. 恢復濾鏡的默認屬性 ///值得注意
filter?.setDefaults()
/// 3. 將字符串轉(zhuǎn)換成二進制數(shù)據(jù),(生成二維碼所需的數(shù)據(jù))
let string = "hello word"
let data = string.data(using: String.Encoding.utf8)///Swift 3.0
/// 4. 通過KVO把二進制數(shù)據(jù)添加到濾鏡inputMessage中
filter?.setValue(data, forKey: "inputMessage")
filter?.setValue("H", forKey: "inputCorrectionLevel")
/// 5. 獲得濾鏡輸出的圖像
let outputImage = filter?.outputImage ///CIImage
/// 6. 將CIImage轉(zhuǎn)換成UIImage洽胶,并放大顯示
//let originQRCodeImage = UIImage(ciImage: outputImage!, scale: 0.07, orientation: UIImageOrientation.up) ///原生二維碼圖片 ///這樣將圖片放大會變得模糊
這樣得到的originQRCodeImage
是模糊的晒夹,把scale
設為一時得到實際大小,但太小妖异。在上篇文章我提過惋戏,需要進行重繪(效果80分)。這里我們可以使用縮放濾鏡來縮放他膳。生產(chǎn)高質(zhì)量的响逢、按比例縮放的源圖像的版本(這是文檔說明,然我并沒發(fā)現(xiàn)有啥牛掰棕孙,還是模糊)舔亭。
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") ///細節(jié)銳化濾鏡
///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)
通過參數(shù)的設置矛洞,得到的圖片效果70分;
而在進行重繪后烫映,再進行銳化處理的話沼本,你就會發(fā)現(xiàn)效果是真的不錯(95分)。
因為升為了Switft3.0代碼锭沟,所以代碼需要少量修改抽兆。主要就是Swift3.0把CoreGraphics
的全局方法改為了實例方法,
func createUIimageWithCGImage(ciImage image: CIImage, widthAndHeightValue wh: CGFloat) -> CIImage {
let ciRect = image.extent.integral///根據(jù)容器得到適合的尺寸
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) /// 創(chuàng)建基于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///寫入質(zhì)量高族淮,時間長
bitmapRef!.scaleBy(x: scale, y: scale) ///調(diào)整“畫布”的縮放
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
}
附錄:
///附:你要是細心,或者有點好奇心祝辣,你可能會問贴妻,為什么我們看到的二維碼中間都有一個小圖片,
///確實現(xiàn)在的大多二維碼生成工具都喜歡中間貼上一個小圖较幌,但是上述生成的二維碼并沒有揍瑟,
///其實這很簡單,這也是我沒有在這個小問題給出示例的原因乍炉。其實二維碼在缺少小部分的情況下绢片,并不影響存儲信息的完整性
///所以小圖片是另外加上去的,只是遮掉了一小塊二維碼內(nèi)容岛琼,這并不影響什么底循。
///然而在一張圖上添加另一張圖,相信你也覺得這并不是什么問題槐瑞。自己試試吧熙涤。
///如:用quartz2D 、drawImga的方法即可困檩。
下圖:1.銳化祠挫;2.重繪;3.重繪+銳化