GPUImage作為iOS相當(dāng)老牌的圖片處理三方庫(kù)已經(jīng)有些日子了(2013年發(fā)布第一個(gè)版本),至今甚至感覺要離我們慢慢遠(yuǎn)去(2015年更新了最后一個(gè)release)??赡墁F(xiàn)在分享這個(gè)稍微有點(diǎn)晚,再加上落影大神早已發(fā)布過此類文章,但是還是想從自己的角度來分享一下對(duì)其的理解和想法。
本文集所有內(nèi)容皆為原創(chuàng),嚴(yán)禁轉(zhuǎn)載。
? ? ? ? 我在2015年底因?yàn)槭诸^項(xiàng)目需求原因接觸到GPUImage,在此之前在上海一家十分傳統(tǒng)的金融互聯(lián)網(wǎng)公司做著我的第一份iOS開發(fā)工作,面對(duì)著每天的TableView、CollectionView顯示著異步獲取下來的各式數(shù)據(jù)做著各種屏幕自適應(yīng),至今我還特別討厭iPad翻轉(zhuǎn)自適應(yīng),不過現(xiàn)在有諸如Masonry、SnapKit等相當(dāng)好用的框架后好像容易解決一些。
? ? ? ? 機(jī)緣巧合下來到杭州,完全一個(gè)人的開發(fā)工作,邊上就一個(gè)天天遲到的產(chǎn)品在一直畫著他想做的原型圖。拿到之前版本的源碼后花了幾天看了濾鏡、貼紙的實(shí)現(xiàn),濾鏡是通過CoreImage框架實(shí)現(xiàn),貼紙則只是用視圖假裝的,之后面試的應(yīng)聘者說到自己所掌握的圖像處理也基本上有這些內(nèi)容,相信這些的實(shí)現(xiàn)只要花點(diǎn)時(shí)間就能掌握。突然有一天他提了一個(gè)需求:能不能做一個(gè)類似PS的遮罩的功能?這個(gè)問題對(duì)于當(dāng)時(shí)只會(huì)數(shù)據(jù)處理展示的我真是一大阻礙。有花了一些時(shí)間,最后發(fā)現(xiàn)CoreAnimation框架中的CALayer就能完美實(shí)現(xiàn),并且它的子類的功能十分令人驚訝,包括之后的界面效果等使用其都能很好的滿足需求,我的簡(jiǎn)書中也有自己對(duì)CALayer的一些理解。接下來才是真正讓我遇到大困難的時(shí)候,當(dāng)決定要做一款圖像處理軟件時(shí)我已經(jīng)知道官方的CoreImage、CoreGraphics這些框架已經(jīng)遠(yuǎn)遠(yuǎn)不能滿足功能需求,并且在那時(shí)候也沒特別多的時(shí)間允許我去學(xué)習(xí)諸如OpenGLES、OpenCV或者M(jìn)etal等圖像處理框架,最后抱著一絲希望,從GitHub上發(fā)現(xiàn)了GPUImage。
? ? ? ? GPUImage的wiki并不像是一個(gè)完整的說明文檔。它只是告訴你:1.GPUImage是基于OpenGLES2.0實(shí)現(xiàn);2.比CoreImage快;3.如何使用GPUImage來對(duì)一張靜態(tài)圖片、一段視頻或者攝像頭實(shí)時(shí)捕捉到的影響加一個(gè)濾鏡效果并顯示在GPUImageView上或者導(dǎo)出成相應(yīng)格式的文件。可能只有我只看懂了以上三點(diǎn),至于其他說到的例如:為什么加完濾鏡要有效果必須調(diào)用processImage方法;導(dǎo)出圖片前不調(diào)用useNextFrameForImageCapture方法就會(huì)crash;glsl語(yǔ)言有什么作用?這些問題對(duì)于當(dāng)時(shí)的我完全毫無概念。并且,當(dāng)時(shí)通過各搜索引擎獲取到相關(guān)的資料無論中英文都是少之又少。因此,剛試手用GPUImage去實(shí)現(xiàn)那些復(fù)雜的圖像處理需求時(shí)我差點(diǎn)選擇了放棄。這么一說,我突然好想去翻譯一下GPUImage的wiki。
? ? ? ?接下來正式說一下我對(duì)GPUImage的大體理解,如有錯(cuò)誤,勞煩指正:
1.OpenGLES可以通過片段著色器(fragment)、頂點(diǎn)著色器(Vertex)兩方面對(duì)圖像進(jìn)行做處理。GPUImage在iOS官方提供的基于OpenGLES的GLKit的再次封裝或者說封裝加拓展的庫(kù)。GLKit是可以指定使用的OpenGLES版本,而GPUImage使用的是OpenGLES2.0。個(gè)人理解,GPUImage庫(kù)中提供的大部分濾鏡是通過片段著色器的一系列操作來實(shí)現(xiàn)相應(yīng)的效果,原因是大部分濾鏡效果并不需要改變圖片本身的大小和外形,只是對(duì)圖片中各像素進(jìn)行計(jì)算生成新的像素,就可達(dá)到濾鏡或者其他調(diào)整效果,這也體現(xiàn)了著色器語(yǔ)言(glsl),尤其是片段著色器語(yǔ)言在GPUImage框架中的份量之重。
2.GPUImage給使用者提供了一個(gè)鏈的概念,這個(gè)鏈并不像Masonry體現(xiàn)在使用上,而是將每一個(gè)輸入源、濾鏡、輸出源假設(shè)為一段段獨(dú)立管道,只有將其完整串起來后,才能把輸入源的圖像信息經(jīng)過每一個(gè)獨(dú)立管道進(jìn)行處理最終流出得到具有所有處理效果的內(nèi)容,以上同樣是個(gè)人在使用GPUImage時(shí)對(duì)其工作流程的抽象理解。
3.在2的基礎(chǔ)上,若想實(shí)現(xiàn)每個(gè)獨(dú)立管道都能串聯(lián),GPUImage使用了一種在iOS不常用到的設(shè)計(jì)模式后:MVP。必然使用到的那些類,也就是可以加入到串聯(lián)中的那些類,1.他們都繼承于GPUImageOutput,除了GPUImageView;2.他們都遵循GPUImageInput協(xié)議,除了輸入源類(GPUImage提供了五種輸入源類:GPUImagePicture、GPUImageRawDataInput、GPUImageMovie、GPUImageUIElement、GPUImageVideoCamera,通過名字即可知道應(yīng)根據(jù)輸入源類型應(yīng)選擇相應(yīng)類進(jìn)行輸入源對(duì)象創(chuàng)建)。GPUImageOutput類在使用過程中并不會(huì)去直接創(chuàng)建該類的對(duì)象,使用者所使用到的都是它的子類。從名字可以看出,GPUImageOutput的大致作用是可以作為一個(gè)輸出源來使用,而遵循了GPUImageInput協(xié)議的類則可以理解成可以作為輸出源來使用。所以在一段段獨(dú)立管道的串聯(lián)過程中,1.最源頭的地方只要作為輸入源,即五種輸入源類不遵循GPUImageInput協(xié)議;2.在過程中需要串聯(lián)的類,比如所有filter的父類GPUImageFilter則又是GPUImageOutput的子類又要遵循GPUImageInput協(xié)議,因?yàn)樗獙⑺弦粋€(gè)管道中處理好的數(shù)據(jù)接收,處理完了之后要將相應(yīng)數(shù)據(jù)作為下一個(gè)的輸入源傳遞給下一個(gè)管道;3.在最后節(jié)點(diǎn)部分,GPUImageView就不需要繼承GPUImageOutput,原因是在它之后并不存在下一個(gè)管道。
? ? ? ? 以上是我認(rèn)為GPUImage最重要的三個(gè)點(diǎn),如果之后還有想起其他就再來補(bǔ)充。這篇是我對(duì)GPUImage理解的開卷,之后想從多方面說明對(duì)其的深入理解。想寫這些的原因其實(shí)也簡(jiǎn)單,現(xiàn)在手頭的項(xiàng)目里依然用著GPUImage實(shí)現(xiàn)主要功能,但是沒想到它竟然可以強(qiáng)大到只要有想法就能實(shí)現(xiàn)各式各樣需求的地步,然后在開發(fā)過程中也希望自己能夠?qū)λ懈钊氲睦斫?,從而能幫助?xiàng)目更好的優(yōu)化和進(jìn)步。再有嘛,可能對(duì)今后的發(fā)展也有一些幫助吧。那第一篇就到這里,以上。