1. 程式人生 > >支援Android4.0以下webp的使用

支援Android4.0以下webp的使用

最近專案中需要使用到webp,主要目的是減少網路流量(同一張圖片,webp格式能比jpg格式小約30%)。但是Android在4.0以上BitmapFactory才支援webp,今天的操作就是要使Android4.0以下的版本也能進行webp的解壓縮。

首先,需要搭建NDK開發的環境

1.下載並安裝Cygwin

按照嚮導一路向下,(使用預設的映象路徑http://www.mirrors.163.com/,這個貌似比較快)。

到達這一步:

選擇Devel,點開。選擇我們必須安裝的5個元件:binutils ,gcc(包含core和g++) ,gcc-mingw(包含core和g++) ,gdb,make。(有的時候你需要更多的元件,根據自己需要再安裝)

選擇完後,點選下一步,直到安裝完成。

執行cygwin,輸入make -v 和 gcc -v 如果能顯示版本,則表示安裝成功。

2.下載並配置NDK

NDK安裝很簡單,下載完成後把檔案解壓到指定的位置即可。

NDK環境配置:

修改Cygwin目錄/home/<username> 下的.bash_profile檔案,在檔案末尾加入如下程式碼:

ANDROID_NDK_ROOT=/cygdrive/解壓後NDK檔案的路徑 /*(例如:/cygdrive/d/android-ndk-r9b)*/

export ANDROID_NDK_ROOT

至此,準備工作已經完畢。

其次,我們需要下載並編輯webp的原始檔

下載完成後,解壓縮,提出Android.mk檔案、src資料夾和swig檔案下的libwebp.jar檔案和libwebp_java_wrap.c檔案。並將libwebp_java_wrap.c檔案移動到src資料夾下。

在工程目錄下新建名字為jni的資料夾。然後將Android.mk檔案、src資料夾移動到jni資料夾下。最後,將libwebp.jar引入到工程中。

編輯Android.mk資料夾,在include $(CLEAR_VARS)
LOCAL_SRC_FILES := \中新增:src/libwebp_java_wrap.c \

並將include $(BUILD_STATIC_LIBRARY)該為include $(BUILD_SHARED_LIBRARY)

如下:


然後在jni資料夾下建立Application.mk檔案,編輯內容如下:

# The ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8

其中APP_PLATFORM設定為支援的SDK最低版本。

儲存後,我們啟動Cygwin,然後通過cd指令進入到我們工程的資料夾下,執行指令:$NDK/ndk-build。

等到編譯結束:

至此so庫已經生成(檢視libs資料夾就會發現對應的.so檔案。同時你會發現工程目錄下多了一個obj資料夾,而且還不小。放心,它只是生成so檔案的中間檔案,不會打包到apk中)。

接下來的任務是使用JNI呼叫so庫進行應用層的開發了。

應用層的開發工程一般如下:

1. 載入so庫。

	static {
		System.loadLibrary("webp");//loadLibrary和Android.mk中LOCAL_MODULE:= **的定義相關,我們在Android.mk中定義為webp,這裡就寫webp。
	}
2.宣告與Native方法相對應的方法。

native方法是:

SWIGEXPORT jint JNICALL Java_com_google_webp_libwebpJNI_WebPGetDecoderVersion(JNIEnv *jenv,
     jclass jcls) {
  jint jresult = 0 ;
  int result;

  (void)jenv;
  (void)jcls;
  result = (int)WebPGetDecoderVersion();
  jresult = (jint)result;
  return jresult;
}
native方法命名規則為:Java_包名_類名_應用層方法名。其中包名中的點被下劃線替代。
應用層中需用生命的方法為:
public static final native int WebPGetDecoderVersion();
應用層只用宣告,不用定義,但要加上native關鍵字。

3.使用應用層宣告的方法。

下面我們按照上述方法來在應用層使用我們剛生成的so庫

記得有一個libwebp.jar檔案不,這個jar已經把應用層宣告的native方法搞好了,而且幫我們封裝了一層,我們只用呼叫其方法就ok了,但是我們還是要載入so庫,因為這個它沒有幫我們實現。

我們寫兩個方法:

	static {
		System.loadLibrary("webp");
	}

	private Bitmap webpToBitmap(byte[] encoded) {

		int[] width = new int[] { 0 };
		int[] height = new int[] { 0 };
		byte[] decoded = libwebp.WebPDecodeARGB(encoded, encoded.length, width,
				height);

		int[] pixels = new int[decoded.length / 4];
		ByteBuffer.wrap(decoded).asIntBuffer().get(pixels);

		return Bitmap.createBitmap(pixels, width[0], height[0],
				Bitmap.Config.ARGB_8888);

	}

	public static boolean isWebp(byte[] data) {
		return data != null && data.length > 12 && data[0] == 'R'
				&& data[1] == 'I' && data[2] == 'F' && data[3] == 'F'
				&& data[8] == 'W' && data[9] == 'E' && data[10] == 'B'
				&& data[11] == 'P';
	}
基於這兩個方法,我們可以對webp圖片進行解壓縮。

下面有一個demo,大家可以參考下:

參考資料: