原文首發(fā)于我的個(gè)人博客網(wǎng)站,歡迎訪問(wèn),轉(zhuǎn)載請(qǐng)注明出處
本文介紹在 Android 平臺(tái)下合成 GIF 的方法,查閱資料的過(guò)程中發(fā)現(xiàn)大致有兩種方案。
使用
giflen(一個(gè)C的合成gif的庫(kù)) 進(jìn)行gif合成。使用
java層的GifEncoder、LZWEncoder、NeuQuant來(lái)進(jìn)行gif合成。
當(dāng)然二者都是基于 LZW 算法,簡(jiǎn)單測(cè)試的結(jié)果是,速度上差不多,由于對(duì) C 不是很擅長(zhǎng),因此我選擇了 java 層進(jìn)行合成的方法,但是兩種方法速度上都是 很慢很慢 ??。
因此本文還將會(huì)使用多線程獨(dú)立編碼的方法來(lái)進(jìn)行優(yōu)化,每幀圖片并行編碼,加快合成速度,現(xiàn)在的成果是 600 * 450 的圖片 20 張的話,時(shí)間大約在 12s 左右。
本文相關(guān)源碼在 GitHub - GifMaker
使用 giflen 合成
使用 jni 合成,感興趣的同學(xué)可以 google 一下 giflen 這個(gè)庫(kù),這里有一個(gè)編譯好的 so 和 jar 文件,以及相關(guān) C 源碼,備份在 GitHub 上,有需要的同學(xué)可以直接下載使用。經(jīng)過(guò)我的簡(jiǎn)單嘗試發(fā)現(xiàn),使用 so 合成的速度和 java 合成的速度差不多,都是慢的要死...
優(yōu)化后的 java 合成
原始的合成方法,真的慢...特別慢,簡(jiǎn)直不能忍。
原始的合成方法是將每一個(gè) Bitmap 使用 LZWEncoder 進(jìn)行編碼,由于是一個(gè)串行的邏輯,后面的圖片需要等待前面的編碼完成才可以繼續(xù)下一張編碼,優(yōu)化后的邏輯是啟動(dòng)一個(gè)線程池,每張圖片獨(dú)立編碼,最后在所有圖片編碼完成之后輸出流合并,輸出到文件中,就完成了 gif 的合成。
缺點(diǎn):大量的 Bitmap 持有在內(nèi)存中并行編碼,可能會(huì) OOM,不過(guò)我測(cè)試 20 張 450 * 600 的圖片,暫時(shí)沒(méi)有出現(xiàn)問(wèn)題。合成的圖片要求寬高應(yīng)該是一樣的,當(dāng)然使用寬高不一致的圖片也不會(huì)有問(wèn)題,但是會(huì)優(yōu)先使用第一張的圖片的寬高作為 gif 的寬高,出來(lái)的圖片就有些尷尬,因此圖片的轉(zhuǎn)換和處理需要在外面完成。
簡(jiǎn)單演示
private void composeGif(List<Bitmap> bitmaps) {
String absolutePath = new File(Environment.getExternalStorageDirectory()
, System.currentTimeMillis() + ".gif").getAbsolutePath();
new GifMaker(100, mExecutorService)
.makeGifInThread(bitmaps, absolutePath, new GifMaker.OnGifMakerListener() {
@Override
public void onMakeGifSucceed(String outPath) {
if (!isFinishing()) {
GlideUtils.with(mActivity, outPath).into(mImageView);
}
}
});
}
看一下輸出的結(jié)果,20 張大約維持在 12s 左右
I/GifMaker: 完成第10幀,耗時(shí):9.594 s - bitmap [600,450]
I/GifMaker: 完成第11幀,耗時(shí):9.774 s - bitmap [600,450]
I/GifMaker: 完成第18幀,耗時(shí):9.880 s - bitmap [450,600]
I/GifMaker: 完成第9幀,耗時(shí):10.41 s - bitmap [600,450]
I/GifMaker: 完成第17幀,耗時(shí):10.145 s - bitmap [450,600]
I/GifMaker: 完成第16幀,耗時(shí):10.331 s - bitmap [450,600]
I/GifMaker: 完成第6幀,耗時(shí):10.586 s - bitmap [450,600]
I/GifMaker: 完成第5幀,耗時(shí):10.557 s - bitmap [450,600]
I/GifMaker: 完成第8幀,耗時(shí):10.701 s - bitmap [450,600]
I/GifMaker: 完成第15幀,耗時(shí):10.715 s - bitmap [450,600]
I/GifMaker: 完成第4幀,耗時(shí):10.736 s - bitmap [450,600]
I/GifMaker: 完成第1幀,耗時(shí):10.835 s - bitmap [450,600]
I/GifMaker: 完成第19幀,耗時(shí):10.842 s - bitmap [450,600]
I/GifMaker: 完成第13幀,耗時(shí):10.940 s - bitmap [450,600]
I/GifMaker: 完成第0幀,耗時(shí):10.944 s - bitmap [450,600]
I/GifMaker: 完成第14幀,耗時(shí):10.967 s - bitmap [450,600]
I/GifMaker: 完成第3幀,耗時(shí):10.989 s - bitmap [450,600]
I/GifMaker: 完成第12幀,耗時(shí):10.994 s - bitmap [450,600]
I/GifMaker: 完成第2幀,耗時(shí):10.994 s - bitmap [450,600]
I/GifMaker: 完成第7幀,耗時(shí):11.148 s - bitmap [450,600]
I/GifMaker: 合成完成,耗時(shí):11.167 s