關於Android圖片資源瘦身的奇思妙想

版權聲明:本文由張紹文原創文章,轉載請註明出處: 
文章原文連接:https://www.qcloud.com/community/article/77android

來源:騰雲閣 https://www.qcloud.com/community算法

分析大部分apk,能夠發如今android中圖片應用較多的主要包括jpg和png兩種資源類型。對於顏色不少尺寸大的圖片通常用jpg,主要適用場景是用於作背景展現,這類圖片除了調整壓縮參數作有損壓縮外,無損壓縮可優化的空間則通常不會太大。相對而言,png圖片的應用場景更多,一方面是因爲其擁有透明值,另外一方面也由於其能夠方便縮放(九宮格)。png這部分資源通常在apk中佔用了比較大的體積,不少時候能夠經過tinypng有損壓縮減小顏色表來減小體積,但容易被像素眼的設計師挑戰;另外一種方案是無損壓縮,常規方法包括轉換爲索引圖片、改變編碼方式、提高壓縮級別等,相較而言體積小了但效果同樣,本文也將就這一方面結合源碼對其在Android的實踐和問題進行闡述。工具

一.選擇壓縮工具

首先是選擇壓縮工具的問題,在這以前先看下系統是如何作的。android的aapt在編譯階段實際上是會對png圖片進行壓縮的,用的則是libpng和zlib,這個能夠用aapt的源碼佐證:優化

  • 用libpng對圖片進行預處理
  • 用zlib對預處理後的圖片進行壓縮生成新圖片

能夠看到aapt對圖片的壓縮等級使用了最高等級9,期間系統也會作顏色錶轉換,這樣能夠減小很大一部分圖片的體積,但系統的壓縮方案是否是天衣無縫呢?目前經常使用的無損壓縮大概有Pngrewrite、pngcrush、optipng、advancecom、pngout,參考了不少文章,得出的結果是pngout仍然是王者,畢竟是Ken神童(聽說Doom and Quake的做者John都尊敬他,作遊戲的確定都知道John )寫的。另外因爲pngout能夠很好的支持命令行,方便放到編譯腳本中自動化,因此暫時選它好了。google

二.實踐案例

壓縮工具選好了,第二步即是實驗了。拿手Q爲例,直接對手Q中的全部png壓一遍,Pngout的速度確實通常,對4千張圖片所有處理一遍大概須要13分鐘,不過這個過程只須要在本地作一遍,因此能夠忍受,但處理完的結果不理想,由於沒什麼效果,減少量爲十幾KB~~ 仔細分析得知這裏面犯渾做怪的居然是aapt,因爲先調pngout再調aapt會致使壓縮效果覆蓋。那麼可不能夠關閉aapt呢? 查看aapt的參數,關於壓縮相關的只有下面這兩個參數:編碼

其中crunch即是預處理資源了,可是沒有關閉crunch的參數。。。。有點技窮了對不對。只能去源碼中找靈感了,看aapt的源碼:spa

google把它隱藏了,沒有打印出來給用戶~打開這個參數,在手Q中資源打包腳本處分別加入--no-crunch參數,即可以把系統壓縮給屏蔽掉了,樣式以下:命令行

至於爲何設置了這個參數就能夠屏蔽呢,其實源碼調用過程以下:設計

第1步 (Main.cpp)code

第2步 (Command.cpp)

第3步 (Resource.cpp)

終結: (Resource.cpp)

但是實驗尚未結束,由於這樣屏蔽掉會出現奇葩的景象,獲得的手Q畫面效果以下:

爲何呢?仔細分析發現九宮格圖片被壓出問題了,aapt在處理png圖片時會判斷是否是九宮格圖片,若是是則作特殊預處理:

do_9patch其實主要的是九宮格信息弄出來,寫入到info9Patch字段,並最終寫入nptc的chunk中:

到這裏又回到第一步爲何我說Ken是神童了,由於Pngout能夠選擇chunk進行壓縮,因此解決方案即是:對於九宮格圖片,咱們單獨拎出來,先用aapt的aapt crunch進行預處理獲得npTc字段,再用pngout在壓縮時調用"knptc"參數保護一下npTc塊,這樣便獲得了正確的九宮格圖片,安裝包的效果圖也就正常了。

三.總結

上面大概就是png無損壓縮在android中應用的基本思路和遇到的問題,概括爲一句話即是:替換掉系統的壓縮算法。若是你不嫌麻煩和喜歡折騰的話能夠在你的apk使用一下,效果仍是很是顯著的。不改變安裝包內圖片像素內容,輕輕鬆鬆減小几百K體積,何樂而不爲呢?

相關文章
相關標籤/搜索