美文网首页
解决低于4.0版本无法使用webp问题

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

作者: 禅座 | 来源:发表于2019-06-16 19:05 被阅读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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/whvlxctx.html