Webp是什么, 請移步 What‘s Webp?
由于webp與生俱有優(yōu)點(diǎn)帆谍,webp如今使用已經(jīng)很廣泛了,包括客戶端轴咱。比如今日頭條客戶端頁面的圖片都是webp格式的汛蝙。客戶端碰到與webp有關(guān)的一些問題嗦玖,大概有:
- webp圖片的顯示
- webp轉(zhuǎn)成其他格式圖片
- 其他格式圖片轉(zhuǎn)成webp
比如我們有一個(gè)這樣的需求:
客戶端將webp格式的圖片轉(zhuǎn)成png后上傳到服務(wù)端(由于服務(wù)端暫時(shí)還不支持webp圖片的上傳)
如何將webp轉(zhuǎn)成png患雇?我們需要依賴Google的webp源碼的支持,但是webp的源碼都是用C來實(shí)現(xiàn)的宇挫,需要將它編譯成.so庫,同時(shí)還需要提供幾個(gè)供Java層調(diào)用的API酪术,用于實(shí)現(xiàn)webp與png相互轉(zhuǎn)換器瘪。在這里我們參考開源項(xiàng)目webp-android-backport
下面詳細(xì)說說如何編譯出我們想要的.so庫
1. 將webp-android-backport項(xiàng)目源碼下載至本地后用AS打開
2. webp源碼下載
因?yàn)檫@個(gè)開源項(xiàng)目對于webp的源碼依賴方式是通過git submodule來管理的,如果沒有Google 開發(fā)者賬號(hào)不方便下載绘雁。
還可以通過下面的鏈接獲取源碼
3. 編譯
下載源碼后放置到工程目錄/jni橡疼,進(jìn)行編譯,如圖
認(rèn)真看了開源項(xiàng)目源碼后發(fā)現(xiàn)庐舟,這樣編譯出來的aar庫其實(shí)是有bug的,尷尬??
為了解決該bug欣除,我們需要將接口類中私有API定義成public,方便上層使用挪略。這里的修改涉及到j(luò)ni的編譯了历帚,期間我也碰到了一些比較坑的問題。(這里我會(huì)用另一篇博客來詳細(xì)說明)
在編譯so庫的時(shí)候杠娱,可以修改webp-android-backport-library包下面的Application.mk文件中APP_ABI 參數(shù)挽牢,來指定項(xiàng)目需要支持的cpu架構(gòu)平臺(tái)。
#APP_ABI := armeabi-v7a x86 armeabi
#APP_ABI := armeabi
APP_ABI := armeabi-v7a
APP_CPPFLAGS := -fno-rtti -fno-exceptions
APP_PLATFORM := android-8
ifndef WEBP_BACKPORT_DEBUG_NATIVE
# Force release compilation in release optimizations, even if application is debuggable by manifest
APP_OPTIM := release
endif
編譯完成會(huì)在webp-android-backport-library/build/outputs目錄下生成一個(gè)aar文件摊求,這樣我們就完成了webp庫的編譯了禽拔。
如何使用編譯生成的庫來實(shí)現(xiàn)webp轉(zhuǎn)png呢?
上代碼:
/**
* author : J.Chou
* e-mail : who_know_me@163.com
* time : 2018/08/13 10:53 PM
* version: 1.0
* description:
*/
public class Webp2PngUtil {
public static boolean isWebpImage(File imageFile) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);
String type = options.outMimeType;
return type.equals("image/webp");
}
public static Bitmap webp2Bitmap(String path) {
Bitmap bitmap = null;
try {
bitmap = WebPFactory.nativeDecodeFile(path, null);
} catch (Throwable t) {
t.printStackTrace();
}
return bitmap;
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static String bitmap2Png(Bitmap bitmap) {
if(bitmap == null) return null;
String pngImagePath = null;
File pngFile = new File(FileUtil.getCacheDir() + File.separator + "webp2png" + System.currentTimeMillis() + ".png");
if(pngFile.exists()){
pngFile.delete();
}
FileOutputStream out;
try{
out = new FileOutputStream(pngFile);
if(bitmap.compress(Bitmap.CompressFormat.PNG, 90, out)) {
out.flush();
out.close();
}
pngImagePath = pngFile.getAbsolutePath();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
return pngImagePath;
}
}
這個(gè)工具類使用到aar庫中的接口類WebPFactory.
這里簡單說一下上傳圖片的邏輯
先判斷上傳文件(webpFile)是否是webp格式(不能判斷圖片后綴名)室叉,如果是睹栖,則將該文件轉(zhuǎn)成png圖片文件(webpFile ---> pngFile),然后將pngFile上傳到服務(wù)端茧痕。
使用工具類Webp2PngUtil來實(shí)現(xiàn)webp轉(zhuǎn)png的實(shí)例代碼
if (Webp2PngUtil.isWebpImage(new File(originalImagePath))) {
String pngImagePath = Webp2PngUtil.bitmap2Png(Webp2PngUtil.webp2Bitmap(originalImagePath));
if (!TextUtils.isEmpty(pngImagePath)) {
originalImagePath = pngImagePath;
}
}
實(shí)現(xiàn)這樣的需求還是比較容易野来,主要的精力可以會(huì)消耗在aar庫的編譯上。
由于aar中包含了webp的so庫凿渊,而且這個(gè)so庫其實(shí)不小(隨著webp的源碼越來越多梁只,編譯后的so庫也在不斷的增大)缚柳,考慮到APP包的size,支持的cpu架構(gòu)也不能太多搪锣。