从Android 4.0开始,Android开始支持webp格式图片的编码和解码,但Android4.0~4.3之间仍然有些手机不支持webp,正确的说,从Android4.3开始支持webp。
为了解决webp兼容性问题,我们通过ndk的方式来解决。
[第一步]
在网络上下载libwebp源码,地址是:
https://www.linuxfromscratch.org/blfs/view/systemd/general/libwebp.html
下载最新版本的源码。
[第二步]
添加ENABLE_SHARED
打开Android.mk,并添加:
ENABLE_SHARED := 1
如图:
[第三步]
添加libwebp_java_wrap
打开Android.mk,并添加:
swig/libwebp_java_wrap.c \
如图:
[第四步]
创建Application.mk
在libwebp工程中新建文件Application.mk,并添加代码:
APP_ABI := armeabi-v7a
APP_PLATFORM := android-14
[第五步]
重命名
将libwebp工程重命名成jni
[第六步]
打包so文件
切换到jni文件夹,执行D:\android_sdk\ndk-bundle\ndk-build.cmd,执行过程如下:
E:\Project\libwebp-1.2.0.tar\jni>D:\android_sdk\ndk-bundle\ndk-build.cmd
Android NDK: android-14 is unsupported. Using minimum supported version android-16.
[armeabi-v7a] Compile thumb : cwebp <= cwebp.c
[armeabi-v7a] Compile arm : webpdemux <= anim_decode.c
[armeabi-v7a] Compile arm : webpdemux <= demux.c
[armeabi-v7a] Compile arm : webp <= cost.c
[armeabi-v7a] Compile arm : webp <= cost_mips32.c
[armeabi-v7a] Compile arm : webp <= cost_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webp <= cost_neon.c
[armeabi-v7a] Compile arm : webp <= cost_sse2.c
[armeabi-v7a] Compile arm : webp <= enc.c
[armeabi-v7a] Compile arm : webp <= enc_mips32.c
[armeabi-v7a] Compile arm : webp <= enc_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webp <= enc_msa.c
[armeabi-v7a] Compile arm : webp <= enc_neon.c
[armeabi-v7a] Compile arm : webp <= enc_sse2.c
[armeabi-v7a] Compile arm : webp <= enc_sse41.c
[armeabi-v7a] Compile arm : webp <= lossless_enc.c
[armeabi-v7a] Compile arm : webp <= lossless_enc_mips32.c
[armeabi-v7a] Compile arm : webp <= lossless_enc_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webp <= lossless_enc_msa.c
[armeabi-v7a] Compile arm : webp <= lossless_enc_neon.c
[armeabi-v7a] Compile arm : webp <= lossless_enc_sse2.c
[armeabi-v7a] Compile arm : webp <= lossless_enc_sse41.c
[armeabi-v7a] Compile arm : webp <= ssim.c
[armeabi-v7a] Compile arm : webp <= ssim_sse2.c
[armeabi-v7a] Compile arm : webp <= alpha_enc.c
[armeabi-v7a] Compile arm : webp <= analysis_enc.c
[armeabi-v7a] Compile arm : webp <= backward_references_cost_enc.c
[armeabi-v7a] Compile arm : webp <= backward_references_enc.c
[armeabi-v7a] Compile arm : webp <= config_enc.c
[armeabi-v7a] Compile arm : webp <= cost_enc.c
[armeabi-v7a] Compile arm : webp <= filter_enc.c
[armeabi-v7a] Compile arm : webp <= frame_enc.c
[armeabi-v7a] Compile arm : webp <= histogram_enc.c
[armeabi-v7a] Compile arm : webp <= iterator_enc.c
[armeabi-v7a] Compile arm : webp <= near_lossless_enc.c
[armeabi-v7a] Compile arm : webp <= picture_enc.c
[armeabi-v7a] Compile arm : webp <= picture_csp_enc.c
[armeabi-v7a] Compile arm : webp <= picture_psnr_enc.c
[armeabi-v7a] Compile arm : webp <= picture_rescale_enc.c
[armeabi-v7a] Compile arm : webp <= picture_tools_enc.c
[armeabi-v7a] Compile arm : webp <= predictor_enc.c
[armeabi-v7a] Compile arm : webp <= quant_enc.c
[armeabi-v7a] Compile arm : webp <= syntax_enc.c
[armeabi-v7a] Compile arm : webp <= token_enc.c
[armeabi-v7a] Compile arm : webp <= tree_enc.c
[armeabi-v7a] Compile arm : webp <= vp8l_enc.c
[armeabi-v7a] Compile arm : webp <= webp_enc.c
[armeabi-v7a] Compile arm : webp <= bit_writer_utils.c
[armeabi-v7a] Compile arm : webp <= huffman_encode_utils.c
[armeabi-v7a] Compile arm : webp <= quant_levels_utils.c
[armeabi-v7a] Compile arm : webp <= libwebp_java_wrap.c
[armeabi-v7a] Compile thumb : cpufeatures <= cpu-features.c
[armeabi-v7a] StaticLibrary : libcpufeatures.a
[armeabi-v7a] Compile arm : webpdecoder_static <= alpha_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= buffer_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= frame_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= idec_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= io_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= quant_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= tree_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= vp8_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= vp8l_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= webp_dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= alpha_processing.c
[armeabi-v7a] Compile arm : webpdecoder_static <= alpha_processing_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= alpha_processing_neon.c
[armeabi-v7a] Compile arm : webpdecoder_static <= alpha_processing_sse2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= alpha_processing_sse41.c
[armeabi-v7a] Compile arm : webpdecoder_static <= cpu.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec_clip_tables.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec_mips32.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec_msa.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec_neon.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec_sse2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= dec_sse41.c
[armeabi-v7a] Compile arm : webpdecoder_static <= filters.c
[armeabi-v7a] Compile arm : webpdecoder_static <= filters_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= filters_msa.c
[armeabi-v7a] Compile arm : webpdecoder_static <= filters_neon.c
[armeabi-v7a] Compile arm : webpdecoder_static <= filters_sse2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= lossless.c
[armeabi-v7a] Compile arm : webpdecoder_static <= lossless_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= lossless_msa.c
[armeabi-v7a] Compile arm : webpdecoder_static <= lossless_neon.c
[armeabi-v7a] Compile arm : webpdecoder_static <= lossless_sse2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= rescaler.c
[armeabi-v7a] Compile arm : webpdecoder_static <= rescaler_mips32.c
[armeabi-v7a] Compile arm : webpdecoder_static <= rescaler_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= rescaler_msa.c
[armeabi-v7a] Compile arm : webpdecoder_static <= rescaler_neon.c
[armeabi-v7a] Compile arm : webpdecoder_static <= rescaler_sse2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= upsampling.c
[armeabi-v7a] Compile arm : webpdecoder_static <= upsampling_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= upsampling_msa.c
[armeabi-v7a] Compile arm : webpdecoder_static <= upsampling_neon.c
[armeabi-v7a] Compile arm : webpdecoder_static <= upsampling_sse2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= upsampling_sse41.c
[armeabi-v7a] Compile arm : webpdecoder_static <= yuv.c
[armeabi-v7a] Compile arm : webpdecoder_static <= yuv_mips32.c
[armeabi-v7a] Compile arm : webpdecoder_static <= yuv_mips_dsp_r2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= yuv_neon.c
[armeabi-v7a] Compile arm : webpdecoder_static <= yuv_sse2.c
[armeabi-v7a] Compile arm : webpdecoder_static <= yuv_sse41.c
[armeabi-v7a] Compile arm : webpdecoder_static <= bit_reader_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= color_cache_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= filters_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= huffman_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= quant_levels_dec_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= random_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= rescaler_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= thread_utils.c
[armeabi-v7a] Compile arm : webpdecoder_static <= utils.c
[armeabi-v7a] StaticLibrary : libwebpdecoder_static.a
[armeabi-v7a] SharedLibrary : libwebp.so
[armeabi-v7a] SharedLibrary : libwebpdemux.so
[armeabi-v7a] Compile thumb : example_util <= example_util.c
[armeabi-v7a] StaticLibrary : libexample_util.a
[armeabi-v7a] Compile thumb : imagedec <= image_dec.c
[armeabi-v7a] Compile thumb : imagedec <= jpegdec.c
[armeabi-v7a] Compile thumb : imagedec <= metadata.c
[armeabi-v7a] Compile thumb : imagedec <= pngdec.c
[armeabi-v7a] Compile thumb : imagedec <= pnmdec.c
[armeabi-v7a] Compile thumb : imagedec <= tiffdec.c
[armeabi-v7a] Compile thumb : imagedec <= webpdec.c
[armeabi-v7a] StaticLibrary : libimagedec.a
[armeabi-v7a] Compile thumb : imageio_util <= imageio_util.c
[armeabi-v7a] StaticLibrary : libimageio_util.a
[armeabi-v7a] Executable : cwebp
[armeabi-v7a] Install : cwebp => libs/armeabi-v7a/cwebp
[armeabi-v7a] Compile thumb : dwebp <= dwebp.c
[armeabi-v7a] Compile thumb : imageenc <= image_enc.c
[armeabi-v7a] StaticLibrary : libimageenc.a
[armeabi-v7a] Executable : dwebp
[armeabi-v7a] Install : dwebp => libs/armeabi-v7a/dwebp
[armeabi-v7a] Compile thumb : img2webp_example <= img2webp.c
[armeabi-v7a] Compile arm : webpmux <= anim_encode.c
[armeabi-v7a] Compile arm : webpmux <= muxedit.c
[armeabi-v7a] Compile arm : webpmux <= muxinternal.c
[armeabi-v7a] Compile arm : webpmux <= muxread.c
[armeabi-v7a] SharedLibrary : libwebpmux.so
[armeabi-v7a] Executable : img2webp_example
[armeabi-v7a] Install : img2webp_example => libs/armeabi-v7a/img2webp_example
[armeabi-v7a] Install : libwebp.so => libs/armeabi-v7a/libwebp.so
[armeabi-v7a] SharedLibrary : libwebpdecoder.so
[armeabi-v7a] Install : libwebpdecoder.so => libs/armeabi-v7a/libwebpdecoder.so
[armeabi-v7a] Install : libwebpdemux.so => libs/armeabi-v7a/libwebpdemux.so
[armeabi-v7a] Compile thumb : webpinfo_example <= webpinfo.c
[armeabi-v7a] Executable : webpinfo_example
[armeabi-v7a] Install : webpinfo_example => libs/armeabi-v7a/webpinfo_example
[armeabi-v7a] Install : libwebpmux.so => libs/armeabi-v7a/libwebpmux.so
[armeabi-v7a] Compile thumb : webpmux_example <= webpmux.c
[armeabi-v7a] Executable : webpmux_example
[armeabi-v7a] Install : webpmux_example => libs/armeabi-v7a/webpmux_example
最后在jni同级路径下找到libs文件夹,如图:
以及libwebp.so文件
[第七步]
集成so文件和jar文件
一般情况下,使用
BitmapFactory.decodeXXX
解码一张图片,包括webp格式的图片,但是Android 4.0~4.3可能不支持webp,低于Android 4.0肯定不支持webp,
为了保证兼容,需要集成libwebp.so文件。
1、将libwebp.jar文件放入项目的libs文件夹中
libwebp.jar文件可以在\jni\swig中可以找到,放到app/libs中。
2、将libwebp.so文件放入项目的main/jniLibs/文件夹中
一般情况下,只需要armeabi-v7a架构的so文件即可。但是,如果想在Android 模拟器中运行,
Android模拟器的CPU架构大部分是x86或者x86_64,所以需要集成对应的so文件。
3、当然,so库和jar的引入代码别忘记
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
}
dependencies {
...
implementation files('libs/libwebp.jar')
}
4、在Application或者Activity初始化的时候加载so文件
System.loadLibrary("webp");
5、另外,补充一点
在libwebp工程的Application.mk文件中,如果将:
APP_ABI := armeabi-v7a
改成
APP_ABI := all
那么,打包so文件时,会生成arm64-v8a、armeabi-v7a、x86、x86_64这四种CPU架构的so文件。
[第八步]
关键代码实现
图片的编码和解码,常规的代码实现是:
BitmapFactory.decodeXXXX(解码)
bitmap.compress(format, 75, fos)(编码)
webp的解码实现:
private Bitmap decodeWebp() {
@SuppressLint("ResourceType")
InputStream is = getResources().openRawResource(R.drawable.ceshi);
byte[] bytes = stream2Bytes(is);
// 将webp格式的数据转成 argb
int[] width = new int[1];
int[] height = new int[1];
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
byte[] argb = libwebp.WebPDecodeARGB(bytes, bytes.length, width, height);
// 将argb byte数组转成 int数组
int[] pixels = new int[argb.length/4];
ByteBuffer.wrap(argb).asIntBuffer().get(pixels);
// 获得bitmap
Bitmap bitmap = Bitmap.createBitmap(pixels, width[0], height[0], Bitmap.Config.ARGB_8888);
return bitmap;
}
byte[] stream2Bytes(InputStream is) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int len;
try {
while ((len = is.read(buffer)) != -1) {
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
return bos.toByteArray();
}
webp的编码实现:
private void encodeWebp(Bitmap bitmap) {
// 获取bitmap宽高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 获得bitmap中的ARGB数据nio
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getByteCount());
bitmap.copyPixelsToBuffer(buffer);
// 编码获得webp格式文件数据 4 * width
byte[] bytes = libwebp.WebPEncodeRGBA(buffer.array(), width, height, width * 4, 75);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/libwebp.webp");
fos.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != fos) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
[本章完...]