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

上篇文章iOS_最全的二維碼篇說要給大家簡(jiǎn)紹一下強(qiáng)大而好玩工具CIFilter,所以這今天晚上給大家分享一個(gè)demo。我保證你看了這篇文章之后,肯定能做出自己的美圖工具,我發(fā)誓(雖然并沒卵用)。

CIFilter,其實(shí)就是一個(gè)濾鏡。喜歡攝影的小伙伴,可能接觸過PS,而接觸過PS的小伙伴,對(duì)濾鏡肯定不陌生。而且有了解相關(guān)知識(shí)的小伙伴,對(duì)于顏色和圖片處理的認(rèn)知也一定信手捏來。什么RGB,什么CMYK,什么灰度圖片,什么高斯模糊,什么銳化,什么對(duì)比度,什么飽和度,什么顏色通道,為什么值在255之間等等。我為什么知道這些,其實(shí)小Jorn我大一的時(shí)候,剛上大學(xué),課不是很多,時(shí)間充足,那時(shí)候,都還不知道LOL(呵呵,現(xiàn)在,此處省略1W字),還帶著高中的稚氣和志氣。想想要學(xué)點(diǎn)啥一技之長(zhǎng)。記得高中時(shí)候,有次去拍一寸照,看那sb老板,不懂PS,硬是給我照片亂修。結(jié)果照片老丑,還硬坑我20塊錢。所以大學(xué)就想到自己學(xué)學(xué)PS,在處理照片的時(shí)候可以自己修。而且,PS還可以做很多平面設(shè)計(jì)。說不定以后可以去做設(shè)計(jì)的工作。一個(gè)好的設(shè)計(jì)師,薪資還是很高的(_)。所以自己學(xué)了一年多的PS(堪稱大神了,然并卵),后來學(xué)的差不多了。海報(bào)設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),UI設(shè)計(jì),還有其他各種設(shè)計(jì),圖文排版,圖片處理,婚紗處理,P圖等什么滴都自己做過(厲害吧)。大二的時(shí)候又學(xué)了一年的AI,后來還想學(xué)AE來著(因?yàn)榇髮W(xué)嘛,越到后來,你懂得。游戲也開始玩起來了)。學(xué)了PS和AI,其實(shí)我還是覺得很不錯(cuò)的,不只在一個(gè)地方看到,PS和AI就像左右手,這也是做平面設(shè)計(jì)的工作者必備的兩技能。一個(gè)負(fù)責(zé)位圖,一個(gè)負(fù)責(zé)矢量圖,功能都超強(qiáng)大?,F(xiàn)在iOS上用的icon基本都是用這兩工具設(shè)計(jì)的。雖然現(xiàn)在不慎混到了程序猿的大流。不過想想懂這也不是無可用武之地,至少在圖片處理,顏色的認(rèn)知上還有挺有幫助的(呵呵,安慰一下自己)。(扯遠(yuǎn)了。。。)

言歸正傳,你學(xué)會(huì)使用CIFilter,你就可以隨意處理你想要的效果。系統(tǒng)給我們提供的濾鏡種類是非常的多,不是十幾個(gè),是幾十個(gè)。沒錯(cuò)!

CoreImage是個(gè)非常強(qiáng)大框架,集圖片的幾乎所有操作編輯于一身,CIFilter只是其中的一個(gè)工具,主要作用是給圖片渲染不同的效果
CIFilter的種類很多,所以蘋果的官方文檔也只能給出部分常用的種類的說明。
官方文檔給出的部分說明:點(diǎn)擊這里
雖然官方文檔很簡(jiǎn)潔,但國(guó)外的大神們已經(jīng)證明這是個(gè)相當(dāng)強(qiáng)悍的框架,
不僅功能強(qiáng)大,而且可以直接使用GPU,效率奇高,甚至可以實(shí)時(shí)的對(duì)視頻進(jìn)行渲染。

下面讓我們來看看,如何具體使用它:
首先你需要導(dǎo)入CoreImage.framework框架;進(jìn)行Mac(不是iOS)開發(fā)的同學(xué)請(qǐng)導(dǎo)入QuartzCore.framework框架,包含在其中了。
然后我們先來看看3個(gè)主要的類:
CIContext:它與CoreGraphicsOpenGL context類似,所有CoreImage的處理流程都通過它來進(jìn)行;
CIImage:它用來存放圖片數(shù)據(jù),可以通過UIImage,圖片文件或像素?cái)?shù)據(jù)創(chuàng)建;
CIFilter:通過它來定義過濾器的詳細(xì)屬性。
CIContext有兩種初始化方法,分別對(duì)應(yīng)GPUCPU

創(chuàng)建基于GPU的CIContext對(duì)象
context = [CIContext contextWithOptions: nil];
創(chuàng)建基于CPU的CIContext對(duì)象

context = [CIContext contextWithOptions: [NSDictionarydictionaryWithObject:[NSNumber numberWithBool:YES]
    forKey:kCIContextUseSoftwareRenderer]];

一般采用第一種基于GPU的,因?yàn)樾室菴PU高很多,但是要注意的是基于GPU的CIContext對(duì)象無法跨應(yīng)用訪問。 比如你打開UIImagePickerController要選張照片進(jìn)行美化,如果你直接在UIImagePickerControllerDelegate的委托方法里調(diào)用CIContext對(duì)象進(jìn)行處理,那么系統(tǒng)會(huì)自動(dòng)將其降為基于CPU的,速度會(huì)變慢,所以正確的方法應(yīng)該是在委托方法里先把照片保存下來,回到主類里再來處理。

CIFilter的強(qiáng)大之處在于,可以疊加來得到多種效果。看過iOS_最全的二維碼篇這篇文章的小伙伴肯定知道了什么叫疊加,其實(shí)如果你按那篇文章我說的練習(xí)一下,你就會(huì)發(fā)現(xiàn),得到的圖片也還是不過清晰。因?yàn)?,二維碼生成的原圖太小,放大就很模糊。其實(shí)我在用PS處理手機(jī)拍的圖片時(shí),一開始少不了這三步,補(bǔ)點(diǎn)光,太暗;增加的對(duì)比度,不夠鮮明;銳化一下,細(xì)節(jié)不過清晰。對(duì),就是銳化一下。等下會(huì)讓你獲得一副清晰的二維碼圖。

首先讓你知道,怎么查看到底有哪些濾鏡:

        /* Categories */
//        public let kCICategoryDistortionEffect: String ///失真效果
//        public let kCICategoryGeometryAdjustment: String ///幾何調(diào)整
//        public let kCICategoryCompositeOperation: String ///復(fù)合操作
//        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 ///風(fēng)格
//        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 ///高動(dòng)態(tài)范圍
//        public let kCICategoryBuiltIn: String ///內(nèi)建
//        @available(iOS 9.0, *)
//        public let kCICategoryFilterGenerator: String ///濾鏡生成器

這是系統(tǒng)含有的所有大類。
想知道有哪些filter類型或想查找想要的filter類型,可以通過先查找大的分類(如上),然后在查找子項(xiàng)。

        let names = CIFilter.filterNames(inCategory: kCICategoryGenerator) ///kCICategoryGenerator大類
        print(names)

這樣就會(huì)輸出該大類包含的所有濾鏡。如上會(huì)輸出所有的生成器類型CIFilter種類:

 ///生成器大類所包含的所有生成器子類,如:"`CICode128BarcodeGenerator`"(條形碼生成器),"CIQRCodeGenerator"(二維碼生成器)
//        ["CIAztecCodeGenerator",
//         "CICheckerboardGenerator",
//         "CICode128BarcodeGenerator", ///條形碼生成器
//         "CIConstantColorGenerator",
//         "CILenticularHaloGenerator",
//         "CIPDF417BarcodeGenerator",
//         "CIQRCodeGenerator", ///二維碼生成器
//         "CIRandomGenerator",
//         "CIStarShineGenerator",
//         "CIStripesGenerator",
//         "CISunbeamsGenerator"]

然后就可以創(chuàng)建濾鏡對(duì)象了,有兩方法,含參數(shù)的僅iOS8之后可用,iOS上不設(shè)輸入?yún)?shù),系統(tǒng)會(huì)使用默認(rèn)值,但是mac是會(huì)報(bào)錯(cuò),輸入?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對(duì)象必須提供輸入?yún)?shù),iOS可以忽略,系統(tǒng)會(huì)使用默認(rèn)值。
        //init?(name: String)
        //@available(iOS 8.0, *) ///iOS 8.0 之后
        //init?(name: String, withInputParameters params: [String : Any]?)

看看該濾鏡需要設(shè)置那些輸入?yún)?shù),如此:

        let filter = CIFilter(name: "CIQRCodeGenerator")
        let inpoutkeys = filter?.inputKeys ///查看這個(gè)filter的所有輸入?yún)?shù)
        let outputKeys = filter?.outputKeys ///查看這個(gè)filter的所有輸出參數(shù)
        
        print("inpoutkeys:",inpoutkeys)
        print("outputKeys:",outputKeys)

設(shè)置參數(shù)用KVC來設(shè)置,常用的key,系統(tǒng)已經(jīng)作為常量給出,可以cmd加鼠標(biāo)左鍵點(diǎn)擊CIFilter類名進(jìn)去查看。
如上,二維碼生成器濾鏡需要量輸入?yún)?shù):

///eg.1 ///示例代碼KVO
        /// 1. 實(shí)例化二維碼濾鏡
        let filter = CIFilter(name: "CIQRCodeGenerator")///二維碼
        
        /// 2. 恢復(fù)濾鏡的默認(rèn)屬性 ///值得注意
        filter?.setDefaults()
        
        /// 3. 將字符串轉(zhuǎn)換成二進(jìn)制數(shù)據(jù),(生成二維碼所需的數(shù)據(jù))
        let string = "hello word"
        let data = string.data(using: String.Encoding.utf8)///Swift 3.0
        
        /// 4. 通過KVO把二進(jìn)制數(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) ///原生二維碼圖片 ///這樣將圖片放大會(huì)變得模糊

這樣得到的originQRCodeImage是模糊的,把scale設(shè)為一時(shí)得到實(shí)際大小,但太小。在上篇文章我提過,需要進(jìn)行重繪(效果80分)。這里我們可以使用縮放濾鏡來縮放。生產(chǎn)高質(zhì)量的、按比例縮放的源圖像的版本(這是文檔說明,然我并沒發(fā)現(xiàn)有啥牛掰,還是模糊)。
CIFilter為"CILanczosScaleTransform"(蘭索斯縮放變化濾鏡),但為了達(dá)到彩色的效果我們先把顏色濾鏡加上,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"(亮度銳化,對(duì)光度有作用,度色度沒影響):

 let sharpenFilter = CIFilter(name: "CISharpenLuminance") ///細(xì)節(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ù)的設(shè)置,得到的圖片效果70分;

而在進(jìn)行重繪后,再進(jìn)行銳化處理的話,你就會(huì)發(fā)現(xiàn)效果是真的不錯(cuò)(95分)。

因?yàn)樯秊榱薙witft3.0代碼,所以代碼需要少量修改。主要就是Swift3.0把CoreGraphics的全局方法改為了實(shí)例方法,


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對(duì)象,性能和效果更好
        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, 把全局方法改為了實(shí)例方法
        bitmapRef!.interpolationQuality = CGInterpolationQuality.high///寫入質(zhì)量高,時(shí)間長(zhǎng)
        bitmapRef!.scaleBy(x: scale, y: scale) ///調(diào)整“畫布”的縮放
        bitmapRef?.draw(bitmapImageRef!, in: ciRect, byTiling: true)///繪制圖片
        
        ///保存
        let scaledImage = bitmapRef!.makeImage() ///cgimage
        
        ///bitmapRef和bitmapImageRef不用主動(dòng)釋放,Core Foundation自動(dòng)管理
        //let originImage = UIImage(CGImage: scaledImage!) ///原生灰度圖片(灰色)
        
        let ciImage = CIImage(cgImage: scaledImage!) ///ciimage
        //let newQRCodeImage = UIImage(cgImage: scaledImage!) ///uiimage
        
        return ciImage
    }

附錄:

///附:你要是細(xì)心,或者有點(diǎn)好奇心,你可能會(huì)問,為什么我們看到的二維碼中間都有一個(gè)小圖片,
///確實(shí)現(xiàn)在的大多二維碼生成工具都喜歡中間貼上一個(gè)小圖,但是上述生成的二維碼并沒有,
///其實(shí)這很簡(jiǎn)單,這也是我沒有在這個(gè)小問題給出示例的原因。其實(shí)二維碼在缺少小部分的情況下,并不影響存儲(chǔ)信息的完整性
///所以小圖片是另外加上去的,只是遮掉了一小塊二維碼內(nèi)容,這并不影響什么。
///然而在一張圖上添加另一張圖,相信你也覺得這并不是什么問題。自己試試吧。
///如:用quartz2D 、drawImga的方法即可。

下圖:1.銳化;2.重繪;3.重繪+銳化


1.銳化;2.重繪;3.重繪+銳化.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容