Android安裝包精簡系列之圖片優化
這是個人總結的應用安裝精簡系列的關于圖片精簡的第二篇,主要介紹在不降低用戶體驗的前提下,盡可能的精簡圖片的相關方案。 優化總體原則就是:在不降低圖片效果、保證用戶體驗的前提下盡最大可能縮小圖片文件的大小 。
概述
在應用從會存在很多簡單的按鈕,一般這些按鈕都會使用png的圖片,雖然這部分圖片并不會占用太多的資源,但是也是可以優化的內容,就以這部分的優化作為系列的開始。
除 .9圖、帶陰影圖外,所有常見的圖標都做到字體庫里,不使用icon圖片。目前比較成熟的圖標字體庫可以使用font-awsome 。Font Awesome為您提供可縮放的矢量圖標,您可以使用CSS所提供的所有特性對它們進行更改,包括:大小、顏色、陰影或者其它任何支持的效果。
png圖片處理
由于png圖片格式的設計導致png的圖片天然很大,因此我們要盡可能少的使用png圖片,可行的方法包括:
-
對于無透明或漸變的png圖,一律轉化為jpg
如何判斷一張png的圖片有沒有透明或者漸變的處理,該工具基于Java環境,通過命令行處理,可以檢測一張圖片是否有漸變效果。例如:
? getPNGInfo git:(master) java -jar getImgInfo.jar head.png {"ret":0,"msg":"圖片是否有漸變: true ,圖片尺寸為(寬*高): 344 * 344 , 圖片大小: 33 KB,圖片類型: 6","hasAlpha":true,"type":6,"width":344,"height":344,"size":33}
如果 用工具檢查確認圖片不含漸變或者透明的效果,必須將png圖片轉為無alpha通道的jpg,另外對于存在漸變或者透明度的圖片,也要判斷下是否必須,非必須也要轉為jpg 。
-
盡可能使用代碼、.9圖等代替png
在開發中對于一些簡單圖片,我們其實可以通過多種方式來替換,達到精簡圖片的效果,具體包括:
-
對于純色的或者漸變的背景圖等,我們可以使用drawable結合color來制作,這樣不但可以減少圖片大小,還可以提升ui渲染的性能
-
對于一些簡單的,需要適配的圖片,例如進度條、按鈕等很多場景,可以使用.9.png來代替png 。.9.png圖片的制作,Android官方在Android SDK的tools里面已經提供了對應的工具,位于 SDK/tools/draw9patch ,雙擊即可運行程序開始制作。關于.9.png的制作,后續根據情況寫一個文檔吧。
-
還有一些簡單的,通過一些幾何圖形繪出來的圖形,我們也可以考慮徹底將圖形代碼化,通過代碼繪制對應的圖片,這部分內容網上也已經有很多介紹的開源項目。
-
其他圖處理
上面關于png的處理方案中除了png轉jpg,其余的內容和上一篇的圖標轉字體一樣更多的都是是處理一些小圖,這些小圖雖然小但是數量很多,因此還是有處理的必要,接下來的內容都是關于在通過上面的方法排除以后,剩余的圖片怎么處理的方案, 核心原則就是圖片壓縮和預加載 。
所有圖片均需要采用有損壓縮算法進一步壓縮
按照上面的步驟處理以后,目前剩下的主要就是一些透明的png圖片和大量的jpg圖。對于這些圖片,在不影響用戶體驗的前提下,我們要盡可能大的進行有損壓縮。 對于png的圖片,必須使用壓縮率更高的圖片無損壓縮算法ZopFliPng來壓縮,對于jpg的話,則使用tinyjpg來進行壓縮.
ZopFliPng 使用簡介
ZopFli是一個谷歌開源的數據壓縮算法,ZopFliPng是基于此開放的圖片壓縮工具,使用過程中,我們需要將源碼clone到本地并編譯,之后即可使用命令行進行圖片壓縮:
-
github地址:
-
下載并編譯
? temp ? git clone https://github.com/zixieTools/zopfli.git Cloning into 'zopfli'... remote: Counting objects: 518, done. remote: Total 518 (delta 0), reused 0 (delta 0), pack-reused 518 Receiving objects: 100% (518/518), 429.77 KiB | 280.00 KiB/s, done. Resolving deltas: 100% (286/286), done. ? temp ? cd zopfli ? zopfli git:(master) make zopflipng gcc src/zopfli/blocksplitter.c src/zopfli/cache.c src/zopfli/deflate.c src/zopfli/gzip_container.c src/zopfli/hash.c src/zopfli/katajainen.c src/zopfli/lz77.c src/zopfli/squeeze.c src/zopfli/tree.c src/zopfli/util.c src/zopfli/zlib_container.c src/zopfli/zopfli_lib.c -W -Wall -Wextra -ansi -pedantic -lm -O2 -Wno-unused-function -c clang: warning: -lm: 'linker' input unused g++ blocksplitter.o cache.o deflate.o gzip_container.o hash.o katajainen.o lz77.o squeeze.o tree.o util.o zlib_container.o zopfli_lib.o src/zopflipng/lodepng/lodepng.cpp src/zopflipng/lodepng/lodepng_util.cpp src/zopflipng/zopflipng_lib.cc src/zopflipng/zopflipng_bin.cc -W -Wall -Wextra -ansi -pedantic -lm -O2 -Wno-unused-function -o zopflipng
-
使用事例
? zopfli git:(master) ? ./zopflipng ~/temp/1/head.png ~/temp/1/head_optimize.png Optimizing /Users/zixie/temp/1/head.png Input size: 33947 (33K) Result size: 20367 (19K). Percentage of original: 59.996% Result is smaller
tinyjpg 使用簡介
tinyjpg 在設計師人群中比較流行,也是一款圖片壓縮的利器,目前對于jpg圖片的有損壓縮基本上都是用tinyjpg.
-
官網地址:
-
使用方法
最簡單的方法就是直接在官網壓縮,把圖片拖動進官網的窗口,然后就會自動執行壓縮,壓縮完的圖片會提供下載鏈接來下載。為了方便在命令行下使用,我也專門封裝了tinyjpg的SDK,提供了java的命令行工具。
-
github地址:
https://github.com/bihe0832/getImageInfo/tree/master/tinyjpg
-
使用事例:
? getPNGInfo git:(master) ? java -jar ./tinyjpg.jar ~/temp/1/head.jpg tinypng_api_key:QVFA4tI-IBD6Ge4gcCqQX44xTdQTay1f http_proxy:http://dev-proxy.oa.com:8080 file unoptimized size: 8037 file optimized: /Users/zixie/temp/1/head_optimized.jpg file optimized size: 4895 file compress percentage: 39.094193%
非關鍵或基礎場景,大圖云端化
經過上面的流程,目前應該大部分圖片都已經被處理過了,簡單的通過壓縮、優化這些方法已經不能再減少應用安裝包中圖片的大小了,接下來就是一些非技術的優化手段了。
結合 Android安裝包精簡系列之為什么要優化精簡安裝包 中提到的觀點,我們會有下面的一些策略
- 部分必須要保留在安裝包里面的非關鍵或者基礎場景相關的大圖通過云端下發的方式來下發。
- 下發后的圖片緩存本地,后續均使用緩存圖片,不再從云端拉取 。
- 應用提供幾張不同類型的默認圖供全局使用,用于解決網絡等問題導致的圖片首次下發失敗的問題
這里就涉及到兩個問題:
怎么找到非關鍵或基礎場景的大圖
有些應用有上千張圖,因此如果一張一張去判斷太過麻煩,因此我們的做法是先用腳本篩選出所有大于5K的圖片,然后追蹤他們的使用場景。最終確定哪些圖片是可以云端下發的。對于如何找到這些大圖,可以通過下面的命令:
? res git:(master) find . -size +5k | egrep 'png|jpg' | xargs -I {} du -h {} 8.0K ./drawable/dice_1.png 12K ./drawable/dice_2.png 12K ./drawable/dice_3.png 12K ./drawable/dice_4.png 12K ./drawable/dice_5.png 12K ./drawable/dice_6.png 268K ./drawable/dice_barrel.png 8.0K ./drawable/iconfont_blog.png 8.0K ./drawable/iconfont_game.png 24K ./drawable/newer01.png 20K ./drawable/shake.png 16K ./drawable/shake_gray.png
因為是簡單的shell命令,因此不再專門具體介紹,通過命令的組合可以完成很多篩選的條件
怎么找到圖片的使用場景
對于找到的每一張圖,在Android Studio里面右擊圖片,然后選擇Find Usages(或者直接使用快捷鍵Alt + F7),IDE就會幫你找出代碼中所有的引用。如下圖:
接下來的就是具體的代碼分析了。這里要注意 通過反射獲取的資源是無法通過這種方式發現的,因此如果項目中有使用比較多的反射,建議通過別的方法處理,這部分內容我會在后面介紹資源精簡的時候說明。
關于webp
WebP是一種支持有損壓縮和無損壓縮的圖片文件格式,派生自圖像編碼格式 VP8。根據 Google 的測試,無損壓縮后的 WebP 比 PNG 文件少了 45% 的文件大小,即使這些 PNG 文件經過其他壓縮工具壓縮之后,WebP 還是可以減少 28% 的文件大小。使用webp更大的目的并不是為了降低安裝包大小,而是為了降低帶寬占用。
雖然webp存在兼容性的問題,但目前github上已經有解決方案。之前簡單驗證嘗試發現引入的so都比較大,單CPU在80K+,但是開源項目是提供了編碼、解碼等一整套方案的代碼。對于客戶端來說,我們僅僅關注解碼相關的內容,雖然并沒有親自實踐,但是 感覺僅用來兼容低版本解碼的so經過整合以后應該并不是很大,因此個人對于webp還是是比較積極的看法 。
來自:http://blog.bihe0832.com/android-optimize-img.html