性能优化<第十一篇>:webp技术

2021-07-07  本文已影响0人  NoBugException

从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

如图:

image.png

[第三步] 添加libwebp_java_wrap

打开Android.mk,并添加:

    swig/libwebp_java_wrap.c \

如图:

image.png

[第四步] 创建Application.mk

在libwebp工程中新建文件Application.mk,并添加代码:

    APP_ABI := armeabi-v7a
    APP_PLATFORM := android-14
image.png

[第五步] 重命名

将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文件夹,如图:
image.png
以及libwebp.so文件
image.png

[第七步] 集成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中。
image.png
2、将libwebp.so文件放入项目的main/jniLibs/文件夹中
image.png
一般情况下,只需要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();
            }
        }
    }
}

[本章完...]

上一篇下一篇

猜你喜欢

热点阅读