解决低于4.0版本无法使用webp问题

2019-06-16  本文已影响0人  禅座

关于4.0以下版本无法使用webp的问题,我们可以通过libwebp的decode与encode解决
在实现libWebP的编码与解码的同时,我们顺便验证一下webP与jpg和png的编码解码时间消耗情况

webp和jpeg的解码时间对比

public class MainActivity extends AppCompatActivity {
 private static final String TAG = "MainActivity";

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 ImageView test = findViewById(R.id.test);
 long l = System.currentTimeMillis();
 //ARGB
 BitmapFactory.decodeResource(getResources(), R.drawable.splash_bg);
 Log.e(TAG, "解码webp图片耗时:" + (System.currentTimeMillis() - l));

 l = System.currentTimeMillis();
 BitmapFactory.decodeResource(getResources(), R.drawable.splash_bg_jpeg);
 Log.e(TAG, "解码jpeg图片耗时:" + (System.currentTimeMillis() - l));
 }

}

结果:
解码webp图片耗时:48
解码jpeg图片耗时:50
webp和jpeg的编码时间对比

public class MainActivity extends AppCompatActivity {
 private static final String TAG = "MainActivity";

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 ImageView test = findViewById(R.id.test);
 long l = System.currentTimeMillis();
 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.splash_bg_png);
 l = System.currentTimeMillis();
 compressBitmap(bitmap, Bitmap.CompressFormat.WEBP, Environment
        .getExternalStorageDirectory() + "/test.webp");
 Log.e(TAG, "编码webp图片耗时:" + (System.currentTimeMillis() - l));

 l = System.currentTimeMillis();
 compressBitmap(bitmap, Bitmap.CompressFormat.JPEG, Environment
        .getExternalStorageDirectory() + "/test.jpeg");
 Log.e(TAG, "编码jpeg图片耗时:" + (System.currentTimeMillis() - l));
 }


//编码速度webP比jpeg慢了10倍,解码差不多
private void compressBitmap(Bitmap bitmap, Bitmap.CompressFormat format, String file) {
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    bitmap.compress(format, 75, fos);
    if (null != fos) {
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
}

结果:
编码webp图片耗时:501
编码jpeg图片耗时:52
编码方面webp被jpeg完虐,但是需要的情况比较少,所以不是问题

实现libwebp的解码,针对4.0一下机型用这种方式

libwebp解码webp

//针对4.0以下设备可以使用这种方式
/**
 * libwebp解码webp图片
 */
private Bitmap decodeWebp() {
    InputStream is = getResources().openRawResource(R.drawable.splash_bg);
    byte[] bytes = stream2Bytes(is);
    try {
        is.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    //将webp格式的数据转成 argb
    int[] width = new int[1];
    int[] height = new int[1];
    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();
}

实现libwebp的编码

/**
 * 将bitmap 使用libwebp编码为 webp图片
 *
 * @param bitmap
 */
private void encodeWebp(Bitmap bitmap) {
    //获取bitmap 宽高
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    //获得bitmap中的 ARGB 数据
    ByteBuffer buffer = ByteBuffer.allocate(bitmap.getByteCount());
    bitmap.copyPixelsToBuffer(buffer);
    //编码 获得 webp格式文件数据,width*4是因为ARGB占四个字节
    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();
            }
        }
    }
}

完整代码

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";


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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView test = findViewById(R.id.test);
        long l = System.currentTimeMillis();
        //ARGB
        BitmapFactory.decodeResource(getResources(), R.drawable.splash_bg);
        Log.e(TAG, "解码webp图片耗时:" + (System.currentTimeMillis() - l));

        l = System.currentTimeMillis();
        BitmapFactory.decodeResource(getResources(), R.drawable.splash_bg_jpeg);
        Log.e(TAG, "解码jpeg图片耗时:" + (System.currentTimeMillis() - l));


        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.splash_bg_png);
        l = System.currentTimeMillis();
        compressBitmap(bitmap, Bitmap.CompressFormat.WEBP, Environment
                .getExternalStorageDirectory() + "/test.webp");
        Log.e(TAG, "编码webp图片耗时:" + (System.currentTimeMillis() - l));

        l = System.currentTimeMillis();
        compressBitmap(bitmap, Bitmap.CompressFormat.JPEG, Environment
                .getExternalStorageDirectory() + "/test.jpeg");
        Log.e(TAG, "编码jpeg图片耗时:" + (System.currentTimeMillis() - l));

        l = System.currentTimeMillis();
        encodeWebp(bitmap);
        Log.e(TAG, "libwebp编码图片耗时:" + (System.currentTimeMillis() - l));


        test.setImageBitmap(decodeWebp());
    }

    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();
    }



    //针对4.0以下设备可以使用这种方式
    /**
     * libwebp解码webp图片
     */
    private Bitmap decodeWebp() {
        InputStream is = getResources().openRawResource(R.drawable.splash_bg);
        byte[] bytes = stream2Bytes(is);
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将webp格式的数据转成 argb
        int[] width = new int[1];
        int[] height = new int[1];
        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;
    }

    /**
     * 将bitmap 使用libwebp编码为 webp图片
     *
     * @param bitmap
     */
    private void encodeWebp(Bitmap bitmap) {
        //获取bitmap 宽高
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        //获得bitmap中的 ARGB 数据
        ByteBuffer buffer = ByteBuffer.allocate(bitmap.getByteCount());
        bitmap.copyPixelsToBuffer(buffer);
        //编码 获得 webp格式文件数据
        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();
                }
            }
        }
    }

    //编码速度webP比jpeg慢了10倍,解码差不多
    private void compressBitmap(Bitmap bitmap, Bitmap.CompressFormat format, String file) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        bitmap.compress(format, 75, fos);
        if (null != fos) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

上述执行需要用到上一章节编译的libwebp.jar和libwebp.so,如图

image.png
提供依据编译好的so包:
https://pan.baidu.com/s/1hl1f2V2D1Ivf3-etnOhNow
https://pan.baidu.com/s/1906GsbPy1lp_T4BevThq5A
上一篇下一篇

猜你喜欢

热点阅读