【Android 安裝包優化】WebP 應用 ( Android 中使用 libwebp.so 庫解碼 WebP 圖片 )
文章目錄
一、Android 中使用 libwebp.so 庫解碼 WebP 圖片
二、完整代碼示例
三、參考資料
一、Android 中使用 libwebp.so 庫解碼 WebP 圖片
libwebp.jar 中解碼相關的的方法如下 : libwebpJNI 是 Java 層調用 libwebp.so 動態庫的入口類 ;
public static byte[] WebPDecodeRGB(byte[] var0, long var1, int[] var3, int[] var4) { return libwebpJNI.WebPDecodeRGB(var0, var1, var3, var4); } public static byte[] WebPDecodeRGBA(byte[] var0, long var1, int[] var3, int[] var4) { return libwebpJNI.WebPDecodeRGBA(var0, var1, var3, var4); } public static byte[] WebPDecodeARGB(byte[] var0, long var1, int[] var3, int[] var4) { return libwebpJNI.WebPDecodeARGB(var0, var1, var3, var4); } public static byte[] WebPDecodeBGR(byte[] var0, long var1, int[] var3, int[] var4) { return libwebpJNI.WebPDecodeBGR(var0, var1, var3, var4); } public static byte[] WebPDecodeBGRA(byte[] var0, long var1, int[] var3, int[] var4) { return libwebpJNI.WebPDecodeBGRA(var0, var1, var3, var4); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在本博客示例中 , 使用的是 WebPDecodeARGB 方法 , 傳入的 4 4 4 個參數作用 :
byte[] var0 : ARGB 字節數據 ;
int var1 : ARGB 字節數據字節個數 ;
int[] var3 : 圖像寬度 , 傳入的是數組 , 只有 1 個元素 , 作為返回值使用 ;
int[] var4 : 圖像高度 , 傳入的是數組 , 只有 1 個元素 , 作為返回值使用 ;
public static byte[] WebPDecodeARGB(byte[] var0, long var1, int[] var3, int[] var4) { return libwebpJNI.WebPDecodeARGB(var0, var1, var3, var4); }
1
2
3
使用 libwebp.so 庫解碼 WebP 圖片 : 讀取 R.mipmap.icon_webp 資源文件 , 使用 libwebp 解碼出 RGBA 數據 , 然后將 RGBA 數據轉換為 Bitmap 位圖 , 最后將 Bitmap 位圖顯示到界面中 ;
@SuppressLint("ResourceType") fun libwebpDecode() { var webPStart = System.currentTimeMillis() // 獲取 WebP 資源文件的輸入流 var inputStream: InputStream = resources.openRawResource(R.mipmap.icon_webp) // 將數據讀取到 Byte 數組輸出流中 var bos: ByteArrayOutputStream = ByteArrayOutputStream() var buffer: ByteArray = ByteArray(2048) // 記錄長度 var len = inputStream.read(buffer) while ( len != -1 ){ bos.write(buffer, 0, len) len = inputStream.read(buffer) } inputStream.close() // 讀取完畢后 , 獲取完整的 Byte 數組數據 var data_webp: ByteArray = bos.toByteArray() // 將 ByteArray 解碼成 ARGB 數據 var width = IntArray(1) var height = IntArray(1) var data_argb_byte: ByteArray = libwebp.WebPDecodeARGB(data_webp, data_webp.size.toLong(), width, height) // 將 data_argb: ByteArray 轉為 IntArray var data_argb_int = IntArray(data_argb_byte.size / 4) // 使用 nio 中的 ByteBuffer 進行讀寫 var byteBuffer: ByteBuffer = ByteBuffer.wrap(data_argb_byte); // 將 byteBuffer 轉為 IntBuffer , 然后獲取其中的 int 數組 byteBuffer.asIntBuffer().get(data_argb_int) // 將 ARGB 數據轉為 Bitmap 位圖圖像 var bitmap: Bitmap = Bitmap.createBitmap( data_argb_int, // 圖像數據 , int 數組格式 width[0], // 圖像寬度 height[0], // 圖像高度 Bitmap.Config.ARGB_8888 // 圖像顏色格式 ) // 界面顯示解碼后的位圖 binding.imageView.setImageBitmap(bitmap) Log.e(TAG, "使用 libwebp.so 庫解碼 WebP 格式圖片時間 : ${System.currentTimeMillis() - webPStart} ms") }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
二、完整代碼示例
調用 libweb.jar 中的 libwebp.WebPDecodeARGB 函數 , 進行 WebP 圖片的解碼操作 ;
同時測試解碼的時長 ;
package kim.hsl.webp import android.annotation.SuppressLint import android.graphics.Bitmap import android.graphics.BitmapFactory import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import com.google.webp.libwebp import kim.hsl.webp.databinding.ActivityMainBinding import java.io.ByteArrayOutputStream import java.io.FileOutputStream import java.io.InputStream import java.nio.ByteBuffer class MainActivity : AppCompatActivity() { companion object{ val TAG = "MainActivity" init { System.loadLibrary("webp") } } lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) Log.e(TAG, "libwebp 函數庫版本 : ${libwebp.WebPGetDecoderVersion()}") // 測試 WebP 解碼速度 decodeWebP() // 測試 WebP 編碼速度 encodeWebP() // 使用 libwebp 庫編碼 WebP 圖片 libwebpEncode() // 使用 libwebp 庫解碼 WebP 圖片 libwebpDecode() } @SuppressLint("ResourceType") fun libwebpDecode() { var webPStart = System.currentTimeMillis() // 獲取 WebP 資源文件的輸入流 var inputStream: InputStream = resources.openRawResource(R.mipmap.icon_webp) // 將數據讀取到 Byte 數組輸出流中 var bos: ByteArrayOutputStream = ByteArrayOutputStream() var buffer: ByteArray = ByteArray(2048) // 記錄長度 var len = inputStream.read(buffer) while ( len != -1 ){ bos.write(buffer, 0, len) len = inputStream.read(buffer) } inputStream.close() // 讀取完畢后 , 獲取完整的 Byte 數組數據 var data_webp: ByteArray = bos.toByteArray() // 將 ByteArray 解碼成 ARGB 數據 var width = IntArray(1) var height = IntArray(1) var data_argb_byte: ByteArray = libwebp.WebPDecodeARGB( data_webp, data_webp.size.toLong(), width, height) // 將 data_argb: ByteArray 轉為 IntArray var data_argb_int = IntArray(data_argb_byte.size / 4) // 使用 nio 中的 ByteBuffer 進行讀寫 var byteBuffer: ByteBuffer = ByteBuffer.wrap(data_argb_byte); // 將 byteBuffer 轉為 IntBuffer , 然后獲取其中的 int 數組 byteBuffer.asIntBuffer().get(data_argb_int) // 將 ARGB 數據轉為 Bitmap 位圖圖像 var bitmap: Bitmap = Bitmap.createBitmap( data_argb_int, // 圖像數據 , int 數組格式 width[0], // 圖像寬度 height[0], // 圖像高度 Bitmap.Config.ARGB_8888 // 圖像顏色格式 ) // 界面顯示解碼后的位圖 binding.imageView.setImageBitmap(bitmap) Log.e(TAG, "使用 libwebp.so 庫解碼 WebP 格式圖片時間 : ${System.currentTimeMillis() - webPStart} ms") } fun libwebpEncode(){ var webPStart = System.currentTimeMillis() // 讀取一張本地圖片 var bitmap = BitmapFactory.decodeResource(resources, R.mipmap.icon_png) // 獲取位圖寬高 var width = bitmap.width var height = bitmap.height // 申請一個 Byte 緩沖區 var byteBuffer: ByteBuffer = ByteBuffer.allocate(bitmap.byteCount) // 將 位圖 數據拷貝到 Byte 緩沖區中 bitmap.copyPixelsToBuffer(byteBuffer) // 使用 libwebp.so 進行 WebP 格式編碼 var data: ByteArray = libwebp.WebPEncodeRGBA( byteBuffer.array(), // 位圖數據 width, // 位圖寬度 height, // 位圖高度 width * 4, // 位圖每行數據 75F // 圖像質量 ) // 將數據寫出到文件中 var fos = FileOutputStream("${cacheDir}/icon_webp2.webp") fos.write(data) fos.close() Log.e(TAG, "使用 libwebp.so 庫編碼 WebP 格式圖片時間 : ${System.currentTimeMillis() - webPStart} ms , " + "輸出文件 : ${cacheDir}/icon_webp2.webp") } fun encodeWebP(){ // 讀取一張本地圖片 var bitmap = BitmapFactory.decodeResource(resources, R.mipmap.icon_png) var pngStart = System.currentTimeMillis() var fos = FileOutputStream("${cacheDir}/icon_png.png") bitmap.compress(Bitmap.CompressFormat.PNG, 75, fos) fos.close() Log.e(TAG, "編碼 png 格式圖片時間 : ${System.currentTimeMillis() - pngStart} ms , " + "輸出文件 : ${cacheDir}/icon_png.png") var webPStart = System.currentTimeMillis() fos = FileOutputStream("${cacheDir}/icon_webp.webp") bitmap.compress(Bitmap.CompressFormat.WEBP, 75, fos) fos.close() Log.e(TAG, "編碼 WebP 格式圖片時間 : ${System.currentTimeMillis() - webPStart} ms , " + "輸出文件 : ${cacheDir}/icon_webp.webp") } fun decodeWebP(){ var pngStart = System.currentTimeMillis() BitmapFactory.decodeResource(resources, R.mipmap.icon_png) Log.e(TAG, "解碼 png 格式圖片時間 : ${System.currentTimeMillis() - pngStart} ") var webPStart = System.currentTimeMillis() BitmapFactory.decodeResource(resources, R.mipmap.icon_webp) Log.e(TAG, "解碼 WebP 格式圖片時間 : ${System.currentTimeMillis() - webPStart} ") } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
執行結果 :
2021-04-25 17:24:20.486 12660-12707/kim.hsl.webp E/libc: Access denied finding property "vendor.debug.egl.profiler" 2021-04-25 17:24:20.653 12660-12660/kim.hsl.webp E/MainActivity: libwebp 函數庫版本 : 1537 2021-04-25 17:24:20.933 12660-12660/kim.hsl.webp E/MainActivity: 解碼 png 格式圖片時間 : 280 2021-04-25 17:24:21.134 12660-12660/kim.hsl.webp E/MainActivity: 解碼 WebP 格式圖片時間 : 201 2021-04-25 17:24:23.814 12660-12660/kim.hsl.webp E/MainActivity: 編碼 png 格式圖片時間 : 2410 ms , 輸出文件 : /data/user/0/kim.hsl.webp/cache/icon_png.png 2021-04-25 17:24:26.902 12660-12660/kim.hsl.webp E/MainActivity: 編碼 WebP 格式圖片時間 : 3088 ms , 輸出文件 : /data/user/0/kim.hsl.webp/cache/icon_webp.webp 2021-04-25 17:24:30.289 12660-12660/kim.hsl.webp E/MainActivity: 使用 libwebp.so 庫編碼 WebP 格式圖片時間 : 3387 ms , 輸出文件 : /data/user/0/kim.hsl.webp/cache/icon_webp2.webp 2021-04-25 17:24:30.457 12660-12660/kim.hsl.webp E/MainActivity: 使用 libwebp.so 庫解碼 WebP 格式圖片時間 : 168 ms
1
2
3
4
5
6
7
8
使用 libwebp.so 庫解碼 WebP 圖片的速度要 高于 Android 本身自帶 API 的速度 ;
界面顯示 :
三、參考資料
參考文檔 :
創建 WebP 圖片 : https://developer.android.google.cn/studio/write/convert-webp
Android 中支持的媒體格式 : https://developer.android.google.cn/guide/topics/media/media-formats
isparta 工具官網 : http://isparta.github.io/
isparta 工具 GitHub 地址 : https://github.com/iSparta/iSparta
Google 提供的 WebP 工具 ( 國內不能訪問 ) : https://developers.google.com/speed/webp/download
Google WebP 主頁 : https://developers.google.com/speed/webp
WebP 相關工具下載頁 : https://developers.google.com/speed/webp/download
WebP工具和函數庫使用文檔 : https://developers.google.com/speed/webp/docs/using
Android NDK 編譯構建腳本參考文檔 :
ndk-build 腳本 : https://developer.android.google.cn/ndk/guides/ndk-build
Android.mk 構建腳本 : https://developer.android.google.cn/ndk/guides/android_mk
Application.mk 構建腳本 : https://developer.android.google.cn/ndk/guides/application_mk
博客資源 :
iSparta 工具 : https://download.csdn.net/download/han1202012/17496041
Google libwebp 庫 : https://download.csdn.net/download/han1202012/17498155
libwebp 源碼及編譯相關資源 : https://download.csdn.net/download/han1202012/17826464 ( 源碼 , 編譯腳本 , 編譯結果 so 庫 )
博客源碼 :
GitHub 地址 : https://github.com/han1202012/Webp
CSDN - : https://download.csdn.net/download/han1202012/18125733
Android 數據結構
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。