CIFilter_看了這個,你就可以打造自己的美圖秀秀

上篇文章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:它與CoreGraphicsOpenGL context類似,所有CoreImage的處理流程都通過它來進行;
CIImage:它用來存放圖片數據,可以通過UIImage,圖片文件或像素數據創建;
CIFilter:通過它來定義過濾器的詳細屬性。
CIContext有兩種初始化方法,分別對應GPUCPU

創建基于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.重繪+銳化


1.銳化;2.重繪;3.重繪+銳化.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內容