http://blog.ibireme.com/2015/11/02/mobile_image_benchmark/php
圖片一般是移動端流量耗費最多的部分,而且佔據着重要的視覺空間。合理的圖片格式選用和優化能夠爲你節省帶寬、提高視覺效果。在這篇文章裏我會分析一下目前主流和新興的幾種圖片格式的特色、性能分析、參數調優,以及相關開源庫的選擇。html
Index
幾種圖片格式簡介
移動端圖片類型的支持狀況
靜態圖片的編碼與解碼
JPEG
PNG
WebP
BPG
動態圖片的編碼與解碼
GIF
APNG
WebP
BPG
動圖性能對比git
首先談一下你們耳熟能詳的幾種老牌的圖片格式吧:程序員
JPEG 是目前最多見的圖片格式,它誕生於 1992 年,是一個很古老的格式。它只支持有損壓縮,其壓縮算法能夠精確控制壓縮比,以圖像質量換得存儲空間。因爲它太過常見,以致於許多移動設備的 CPU 都支持針對它的硬編碼與硬解碼。github
PNG 誕生在 1995 年,比 JPEG 晚幾年。它自己的設計目的是替代 GIF 格式,因此它與 GIF 有更多類似的地方。PNG 只支持無損壓縮,因此它的壓縮比是有上限的。相對於 JPEG 和 GIF 來講,它最大的優點在於支持完整的透明通道。web
GIF 誕生於 1987 年,隨着初代互聯網流行開來。它有不少缺點,好比一般狀況下只支持 256 種顏色、透明通道只有 1 bit、文件壓縮比不高。它惟一的優點就是支持多幀動畫,憑藉這個特性,它得以從 Windows 1.0 時代流行至今,並且仍然大受歡迎。算法
在上面這些圖片格式誕生後,也有很多公司或團體嘗試對他們進行改進,或者創造其餘更加優秀的圖片格式,好比 JPEG 小組的 JPEG 2000、微軟的 JPEG-XR、Google 的 WebP、我的開發者發佈的 BPG、FLIF 等。它們相對於老牌的那幾個圖片格式來講有了很大的進步,但出於各類各樣的緣由,只有少數幾個格式可以流行開來。下面三種就是目前實力比較強的新興格式了:canvas
APNG 是 Mozilla 在 2008 年發佈的一種圖片格式,旨在替換掉畫質低劣的 GIF 動畫。它實際上只是至關於 PNG 格式的一個擴展,因此 Mozilla 一直想把它合併到 PNG 標準裏面去。然而 PNG 開發組並無接受 APNG 這個擴展,而是一直在推動它本身的 MNG 動圖格式。MNG 格式過於複雜以致於並無什麼系統或瀏覽器支持,而 APNG 格式因爲簡單容易實現,目前已經漸漸流行開來。Mozilla 本身的 Firefox 首先支持了 APNG,隨後蘋果的 Safari 也開始有了支持, Chrome 目前也已經嘗試開始支持 ,能夠說將來前景很好。瀏覽器
WebP 是 Google 在 2010 年發佈的圖片格式,但願以更高的壓縮比替代 JPEG。它用 VP8 視頻幀內編碼做爲其算法基礎,取得了不錯的壓縮效果。它支持有損和無損壓縮、支持完整的透明通道、也支持多幀動畫,而且沒有版權問題,是一種很是理想的圖片格式。藉由 Google 在網絡世界的影響力,WebP 在幾年的時間內已經獲得了普遍的應用。看看你手機裏的 App:微博、微信、QQ、淘寶、網易新聞等等,每一個 App 裏都有 WebP 的身影。Facebook 則更進一步,用 WebP 來顯示聊天界面的貼紙動畫。性能優化
BPG 是著名程序員 Fabrice Bellard 在去年 (2014年) 發佈的一款超高壓縮比的圖片格式。這個程序員有些人可能感受面生,但提及他的做品 FFmpeg、QEMU 你們想必是都知道的。BPG 使用 HEVC (即 H.265) 幀內編碼做爲其算法基礎,就這點而言,它毋庸置疑是當下最爲先進的圖片壓縮格式。相對於 JP二、JPEG-XR、WebP 來講,同等體積下 BPG 能提供更高的圖像質量。另外,得益於它自己基於視頻編碼算法的特性,它能以很是小的文件體積保存多幀動畫。 Fabrice Bellard 聰明的地方在於,他知道本身一我的沒法獲得各大瀏覽器廠商的支持,因此他還特意開發了 Javascript 版的解碼器,任何瀏覽器只要加載了這個 76KB 大小的 JS 文件,就能夠直接顯示 BPG 格式的圖片了。目前阻礙它流行的緣由就是 HEVC 的版權問題和它較長的編碼解碼時間。儘管這個圖片格式纔剛剛發佈一年,但已經有很多廠子開始試用了,好比阿里和騰訊。
目前主流的移動端對圖片格式的支持狀況如何呢?咱們分別來看一下 Android 和 iOS 目前的圖片編解碼架構吧:
Android 的圖片編碼解碼是由 Skia 圖形庫負責的,Skia 經過掛接第三方開源庫實現了常見的圖片格式的編解碼支持。目前來講,Android 原生支持的格式只有 JPEG、PNG、GIF、BMP 和 WebP (Android 4.0 加入),在上層能直接調用的編碼方式也只有 JPEG、PNG、WebP 這三種。目前來講 Android 還不支持直接的動圖編解碼。
iOS 底層是用 ImageIO.framework 實現的圖片編解碼。目前 iOS 原生支持的格式有:JPEG、JPEG2000、PNG、GIF、BMP、ICO、TIFF、PICT,自 iOS 8.0 起,ImageIO 又加入了 APNG、SVG、RAW 格式的支持。在上層,開發者能夠直接調用 ImageIO 對上面這些圖片格式進行編碼和解碼。對於動圖來講,開發者能夠解碼動畫 GIF 和 APNG、能夠編碼動畫 GIF。
兩個平臺在導入第三方編解碼庫時,都多少對他們進行了一些修改,好比 Android 對 libjpeg 等進行的調整以更好的控制內存,iOS 對 libpng 進行了修改以支持 APNG,並增長了多線程編解碼的特性。除此以外,iOS 專門針對 JPEG 的編解碼開發了 AppleJPEG.framework,實現了性能更高的硬編碼和硬解碼,只有當硬編碼解碼失敗時,libjpeg 纔會被用到。
因爲我目前主要是作 iOS 開發,因此下面的性能評測都是基於 iPhone 的,主要測試代碼能夠在這裏看到。測試素材不多,只有兩個:
第一張是Dribbble 的 Logo,包含 Alpha 通道,用於測試簡單的、圖形類的圖像。
第二張經典的 Lena 圖,用於測試照片類的、具備豐富細節的圖像。
每一個圖像都有 64x6四、128x12八、256x25六、512x512 四種分辨率。
測試素材過少可能致使某些測試不夠準確,但做爲參考大體是沒問題的。
目前比較知名的 JPEG 庫有如下三個:
libjpeg:開發時間最先,使用最普遍的 JPEG 庫。因爲 JPEG 標準過於複雜和模糊,並無其餘人去實現,因此這個庫是 JPEG 的事實標準。
libjpeg-turbo:一個致力於提高編解碼速度的 JPEG 庫。它基於 libjpeg 進行了改造,用 SIMD 指令集 (MMX、SSE二、NEON) 重寫了部分代碼,官網稱相對於 libjpeg 有 2 到 4 倍的性能提高。
MozJPEG: 一個致力於提高壓縮比的 JPEG 庫。它是 Mozilla 在 2014 年發佈的基於 libjpeg-turbo 進行改造的庫,相對於 libjpeg 有 5% ~ 15% 的壓縮比提高,但相應的其編碼速度也慢了不少。
除了上面這三個庫,蘋果本身也開發了一個 AppleJPEG,但並無開源。其調用了芯片提供的 DSP 硬編碼和硬解碼的功能。雖然它不如上面這三個庫功能完善,但其性能很是高。在個人測試中,其編解碼速度一般是 libjpeg-turbo 的 1~2 倍。惋惜的是,目前開發者並不能直接訪問這個庫。
下面是 ImageIO (AppleJPEG/libpng) 在 iPhone 6 上的編解碼性能:
能夠看到,JPEG 編碼中 quality 越小,圖片體積就越小,質量越也差,編碼時間也越短。解碼時間並無很大的差距,多是其大部分時間消耗在了函數調用、硬件調用上。蘋果在本身的相冊 Demo 中提供的 quality 的默認值是 0.9,在這個值附近,圖像質量和體積、編碼解碼時間之間都能取得不錯的平衡。
相對於 JPEG 來講,PNG 標準更爲清晰和簡單,所以有不少公司或我的都有本身的 PNG 編碼解碼實現。但目前使用最廣的仍是 PNG 官方發佈的 libpng 庫。iOS 和 Android 底層都是調用這個庫實現的 PNG 編解碼。
下面是 PNG 在 iPhone 6 上的編解碼性能:
能夠看到,在編解碼圖形類型(顏色少、細節少)的圖片時,PNG 和 JPEG 差距並不大;可是對於照片類型(顏色和細節豐富)的圖片來講,PNG 在文件體積、編解碼速度上都差 JPEG 很多了。
和 JPEG 不一樣,PNG 是無損壓縮,其並不能提供壓縮比的選項,其壓縮比是有上限的。目前網上有不少針對 PNG 進行優化的工具和服務,旨在提高 PNG 的壓縮比。下面是常見的幾個 PNG 壓縮工具的性能對比:
pngcrush 是 Xcode 自帶的 PNG 壓縮工具,相對於設計師用 Photoshop 生成的圖片來講,它能取得不錯的壓縮效果。ImageOptim 則更進一步,對每張圖用多種縮算法進行比對,選擇壓縮比更高的結果,進一步縮小了文件體積。TinyPNG.com 相對於其餘工具來講,壓縮比高得不像話。它啓用了相似 GIF 那樣的顏色索引表對 PNG 進行壓縮,因此會致使顏色豐富的圖片丟失掉一部分細節。若是使用 TinyPNG 的話,最好在壓縮完成後讓設計師看一下顏色效果是否能夠接受。
WebP 標準是 Google 定製的,迄今爲止也只有 Google 發佈的 libwebp 實現了該的編解碼 。 因此這個庫也是該格式的事實標準。
WebP 編碼主要有幾個參數:
lossless: YES:有損編碼 NO:無損編碼。WebP 主要優點在於有損編碼,其無損編碼的性能和壓縮比表現通常。
quality: [0~100] 圖像質量,0表示最差質量,文件體積最小,細節損失嚴重,100表示最高圖像質量,文件體積較大。該參數只針對有損壓縮有明顯效果。Google 官方的建議是 75,騰訊在對 WebP 評測時給出的建議也是 75。在這個值附近,WebP 能在壓縮比、圖像質量上取得較好的平衡。
method: [0~6] 壓縮比,0表示快速壓縮,耗時短,壓縮質量通常,6表示極限壓縮,耗時長,壓縮質量好。該參數也只針對有損壓縮有明顯效果。調節該參數最高能帶來 20% ~ 40% 的更高壓縮比,但相應的編碼時間會增長 5~20 倍。Google 推薦的值是 4。
對於編碼無損圖片來講,quality=0, method=0~3 是相對來講比較合適的參數,可以節省編碼時間,同時也有不錯的壓縮比。無損編碼圖片,quality=75, method=2~4 是比較合適的參數,能在編碼時間、圖片質量、文件體積之間有着不錯的平衡。
WebP 解碼有三個參數:
use_threads: 是否啓用 pthread 多線程解碼。該參數只對寬度大於 512 的有損圖片起做用。開啓後內部會用多線程解碼,CPU 佔用會更高,解碼時間平均能縮短 10%~20%。
bypass_filtering: 是否禁用濾波。該參數只對有損圖片起做用,開啓後大約能縮短 5%~10% 的解碼時間,但會形成一些顏色過渡平滑的區域產生色帶(banding)。
no_fancy_upsampling: 是否禁用上採樣。該參數只對有損圖片起做用。在個人測試中,開啓該參數後,解碼時間反而會增長 5~25%,同時會形成一些圖像細節的丟失,線條邊緣會增長雜色,顯得不天然。
一般狀況下,這三個參數都設爲 NO 便可,若是要追求更高的解碼速度,則能夠嘗試開啓 use_threads 和 bypass_filtering 這兩個參數。而 no_fancy_upsampling 在任何狀況下都不必開啓。
因爲 WebP 測試數據較多,這裏只貼一下 512x512 大小的一部分測試結果,感興趣的能夠看文章結尾處的 Excel 附件。
對於簡單的圖形類型的圖像(好比 App 內的各類 UI 素材),WebP 無損壓縮的文件體積和解碼速度某些狀況下已經比 PNG 還要理想了,若是你想要對 App 安裝包體積進行優化,能夠嘗試一下 WebP。
對於複雜的圖像(好比照片)來講,WebP 無損編碼表現並很差,但有損編碼表現卻很是棒。相近質量的圖片解碼速度 WebP 相距 JPEG 也已經相差不大了,而文件壓縮比卻能提高很多。
BPG 是目前已知最優秀的有損壓縮格式了,它能在相同質量下比 JPEG 減小 50% 的體積。下面是經典的 Lena 圖的對比,你也能夠在這裏看到大量其餘圖片的 BPG、JPEG、JPEG2000、JPEG-XR、WebP 壓縮效果的在線對比,效果很是明顯。
BPG 目前只有做者發佈的 libbpg 可用。但做者基於 libbpg 編譯出了一個 Javascript 解碼器,很大的擴展了可用範圍。bpg 能夠以無損和有損壓縮兩種方式進行編碼,有損壓縮時能夠用 quality 參數控制壓縮比,可選範圍爲 0~51,數值越大壓縮比越高。一般來講,25 附近是一個不錯的選擇,BPG 官方工具默認值是 28。
libbpg 目前並無針對 ARM NEON 作優化,因此其在移動端的性能表現通常。下面是 iPhone 6 上的性能測試:
因爲 bpg 編碼時間太長,我並無將數據放到表格裏。能夠看到相同質量下,BPG 的解碼速度仍是差 JPEG 太多,大約慢了 3~5 倍。目前來講,BPG 適用於那些對流量很是敏感,但對解碼時間不敏感的地方。從網上的新聞來看,手機淘寶和手機QQ都已經有所嘗試,但不清楚他們是否對 BPG 解碼進行了優化。
動圖在網絡上很是受歡迎,它近似視頻,但一般實現簡單、文件體積小,應用範圍很是普遍。動圖的始祖是 GIF,它自 Windows 1.0 時代就在互聯網上流行開來,直到今天仍然難以被其餘格式取代。儘管它很是古老,但其所用的原理和今天幾種新興格式幾乎同樣。
下面是一張 GIF 格式的 QQ 大表情:
這張表情由 6 幅靜態圖構成,每幅圖片有必定的存活時間,連貫播放就造成了動畫:
這幾張圖中,大部份內容是相近的,爲了壓縮文件體積,一般動圖格式都支持一些特殊的方式對類似圖片進行裁剪,只保留先後幀不一樣的部分:
在解碼動圖時,解碼器一般採用所謂"畫布模式"進行渲染。想象一下:播放的區域是一張畫布,第一幀播放前先把畫布清空,而後完整的繪製上第一幀圖;播放第二幀時,再也不清空畫布,而是隻把和第一幀不一樣的區域覆蓋到畫布上,就像油畫的創做那樣。
像這樣的第一幀就被稱爲關鍵幀(即 I 幀,幀內編碼幀),然後續的那些經過補償計算獲得的幀被稱爲預測編碼幀(P幀)。一個壓縮的比較好的動圖內,一般只有少許的關鍵幀,而其他都是預測編碼幀;一個較差的壓縮工具製做的動圖內,則基本都是關鍵幀。不一樣的動圖壓縮工具一般能獲得不一樣的結果。
除此以外,動圖格式一般有更爲詳細的參數控制每一幀的繪製過程,下面是 GIF/APNG/WebP 通用的幾個參數:
Disposal Method (清除方式)
Do Not Dispose:把當前幀增量繪製到畫布上,不清空畫布。
Restore to Background:繪製當前幀以前,先把畫布清空爲默認背景色。
Restore to Previous:繪製下一幀前,把先把畫布恢復爲當前幀的前一幀
Blend Mode (混合模式)
Blend None: 繪製時,所有通道(包含Alpha通道)都會覆蓋到畫布,至關於繪製前先清空畫布的指定區域。
Blend over:繪製時,Alpha 通道會被合成到畫布,即一般狀況下兩張圖片重疊的效果。
上面這些技術,就是常見動圖格式的基礎了,下面分別介紹一下不一樣動圖格式的特色。
GIF 缺陷很是明顯:它一般只支持 256 色索引顏色,這致使它只能經過抖動、差值等方式模擬較多豐富的顏色;它的 Alpha 通道只有 1 bit,這意味着一個像素只能是徹底透明或者徹底不透明。
上面這是騰訊博客裏的一張演示圖,能夠看到 GIF 因爲 Alpha 通道的問題,產生了嚴重的"毛邊"現象。目前一般的解決方案是在圖片的邊緣加一圈白邊,以減輕這種視覺效果:
能夠仔細觀察一下 QQ、微信等 App 裏面的動畫表情,幾乎每一個表情都被一圈白邊所環繞,不得不說是一種很無奈的解決方案。
GIF 的製做工具備不少,但效果好、壓縮比高的工具很是少。對於已經制做好的 GIF 來講,用imagemagick 處理一下能夠把文件體積壓縮很多。若是須要將視頻轉爲 GIF,Cinemagraph Pro 是個不錯的傻瓜化工具。這裏有一篇文章介紹如何用 ffmpeg 壓縮 GIF,雖然參數調節有點麻煩,但效果很是理想。
下面是沒有通過優化的 GIF 和通過 ffmpeg 優化編碼的 GIF,能夠看到差距很是大。
APNG 目前並無被 PNG 官方所接受,因此 libpng 並不能直接解碼 APNG。但因爲 APNG 只是基於 PNG 的一個簡單擴展,因此在已經支持 PNG 的平臺上,能夠很輕鬆的用少許代碼實現 APNG 的編解碼。Chromium 爲了支持 APNG 播放,只增長了不到 600 行代碼 ,我本身也用大概 500 行 C 代碼實現了一個簡單的 APNG 編解碼工具。另外,在支持 canvas 的瀏覽器上,能夠用 apng-canvas 直接顯示 APNG 動畫。APNG 壓縮最好的工具目前是 apngasm,大部分圖形化工具好比騰訊的 iSparta 都是基於這個工具開發的。
就目前而言, APNG 是 GIF 最好的替代了:實現簡單,可用範圍廣,壓縮比不錯,顯示效果好。
WebP 在 2010 年 發佈時並無支持動圖。2012 年 libwebp v0.2 的時候,Google 纔開始嘗試支持動畫,但其實現有不少問題,性能也很是差,以致於 Chrome 團隊一直都沒有接受。直到 2013 年,libwebp v0.4 時,動畫格式才穩定下來才被 Chrome 所接受。
WebP 動圖其實是把多個單幀 WebP 數據簡單打包到一個文件內,而並非由單幀 WebP 擴展而來,以致於動圖格式並不能向上兼容靜態圖。若是要支持動圖,首先在編譯 libwebp 時須要加上 demux 模塊,解碼 WebP 時須要先用 WebPDemuxer 嘗試拆包,以後再把拆出來的單幀用 WebPDecode 解碼。爲了方便編譯,我寫了個腳本用於打包 iOS 的靜態庫,加入了 mux 和 demux 模塊。
Google 提供了兩個簡單的命令行工具用於製做動圖:gif2webp 能把 GIF 轉換爲 WebP, webpmux 能把多個 WebP 圖片打包爲動態圖,而且有着不少參數能夠調節。這兩個工具對相近幀的壓縮並不太理想,以致於有的狀況下壓縮比還不如 APNG,但除此之外也沒有其餘什麼更好的工具能夠用了。
BPG 自己是基於 HEVC (H.265) 視頻編碼的,其最開始設計時就考慮到了動圖的實現。因爲它充分利用了 HEVC 的高壓縮比和視頻編碼的特性,其動圖壓縮比遠超其餘格式。這裏和這裏有幾張 BPG 動圖示例,能夠看到相同質量下 BPG 動圖只有 APNG/WebP/GIF 幾十分之一的大小。
我在這裏寫了個簡單的利用 libbpg 解碼動圖的方法,若有須要能夠參考下。
我把下面這張 GIF 分別轉爲 WebP、APNG、BPG 動圖,並在 iPhone 6 上對其全部幀進行解碼。
評測結果以下:
APNG 在文件體積上比 GIF 略有優點,解碼時間相差很少。WebP 在體積和解碼時間上都具備較大的優點。BPG 在體積上優點最大,但解碼時間也最長。這麼看來,APNG 和 WebP 都是不錯的選擇,而 BPG 還有待性能優化。
最後作一個小廣告:若是你是 iOS 平臺的開發者,能夠試試我開發的 YYWebImage,它支持 APNG、WebP、GIF 動圖的異步加載與播放、編碼與解碼,支持漸進式圖像加載,能夠替代 SDWebImage、PINRemoteImage、FLAnimatedImage 等開源庫。
上面提到的全部評測數據表格:image_benchmark.xlsx 推薦用 Excel 打開查看。