1、api和自注冊機制
skia中編碼解碼圖檔都隻需要一行代碼:
skimagedecoder中規定的解碼器工廠注冊函數:
gif的解碼器工廠便按如下方法注冊:
2、解碼的流程:
(1)周遊所有解碼器,找到支援該檔案的解碼器:
周遊的代碼見:
external/skia/src/images/skimagedecoder_factoryregistrar.cpp
(2)解碼器調用相應的解碼庫函數(簡單的圖檔如bmp自行處理),解出原始圖檔,見各個解碼器的ondecode方法
(3)在ondecode方法中,一般需要用skscaledbitmapsampler類作圖檔後續的縮放和透明度預乘
編碼的流程相對簡單,就是根據類型取相應的編碼器做檔案編碼,不詳述
3、解碼中流的設定:
從framework層調skia的解碼,主要是以下幾個函數:
nativedecodestream:以java的inputstream類作為輸入解碼,建立javainputstreamadaptor流(其實作是先回調java中inputstream的讀取方法,将其讀到緩存區,再從緩存區中讀到目标記憶體。)
nativedecodefiledescriptor:以檔案描述符作為輸入解碼,建立skfilestream,直接讀取檔案内容
nativedecodeasset:以asset作為輸入解碼,建立assetstreamadaptor(frameworks/base/core/jni/android/graphics/utils.cpp)。
nativedecodebytearray:以bytearray作為輸入解碼,建立skmemorystream,直接從記憶體中讀。
由于以檔案描述符和inputstream為輸入時,不能保證該流可以rewind,是以加了一層 skfrontbufferedstream 的包裝,這個主要作用是緩存輸入流中最前面的一段區域(#define bytes_to_buffer 64),以便在讀這段區域時可以回溯(rewind),這個主要作用讓解碼器讀完檔案頭判斷類型後可以回溯。
詳細見:
external/skia/src/utils/skfrontbufferedstream.cpp
4、解碼選項
external/skia/include/core/skimagedecoder.h
這些私有變量對應于bitmapfactory.options中的相應的配置項,見
frameworks/base/graphics/java/android/graphics/bitmapfactory.java
設定的代碼見dodecode方法:
frameworks/base/core/jni/android/graphics/bitmapfactory.cpp
部分java層的配置項并不反映在skimagedecoder中,而是作為函數參數傳入,如解碼模式mode
5、典型解碼器的ondecode方法
這一部分的代碼可做為這些圖像編解碼庫使用方法的參考
(1)jpeg
a、配置jpeg解碼選項(輸出格式、采樣率、idct類型、下采樣率等等,在skimagedecoder.h的注釋中解釋過一些)
b、在不設定下采樣且目标格式為rgba時,直接解碼到目标bitmap上(jpeg是按yuv三分量分别壓縮的,設定為jpeg庫解碼時作yuv-rgba的顔色轉換)。
c、需要下采樣時,由于jpeg庫可作簡化處理,是以重新計算一個下采樣率,由skscaledbitmapsampler将解碼出來的圖像下采樣到目标bitmap上。
(2)png
png格式的圖像可能包含透明度。skia作了一個額外處理是檢查其透明度是否全為255,是則置不透明标志,畢竟不透明的圖像在後續渲染時消耗較少。
(3)gif
由于适配不同版本的gif庫的原因,這段代碼寫得略顯雜亂,也存在一些bug。
值得注意的是skia對于gif動态圖,隻解最後一幀(savedimage* image = &gif->savedimages[gif->imagecount-1];)
至于gif動畫,由skgifmovie類處理,走不同的流程。應用需要調另外的類(詳細見:frameworks/base/graphics/java/android/graphics/movie.java)。
(4)bmp
這個是最簡單的一種格式,用得較少,skia裡面的處理也比較随意。
a、将流中内容全部讀到記憶體(copystreamtostorage)
b、解析流中的内容,将其轉化為rgb格式(image_codec::bmpdecoderhelper::decodeimage)
c、使用skscaledbitmapsampler,将rgb轉成目标格式,同時作下采樣。
6、典型編碼器的onencode方法
jpeg是有損壓縮,傳入的quality決定其量化參數表。
a、skia預設先将圖檔轉為yuv444格式,再進行編碼(we_convert_to_yuv宏預設打開狀态,否則就是先轉為rgb888格式,再傳入jpeg編碼時轉yuv)。
b、預設使用jdct_ifast方法做傅立葉變換,很明顯會造成一定的圖檔品質損失(即使quality設成100也存在,是計算精度的問題)。
a、将圖像格式統一轉為rgba8888,再去作png編碼,另外注明是否包含透明度資訊。
b、對于原先帶透明的圖像格式(rgba8888,rgba4444),做反alpha預乘,也即每個像素值除以其alpha值,自然,除法會做些轉化由乘法替代的。