Android 关于WebP的那些事

什么是webp格式

WebP格式,谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器宽带资源和数据空间。WebP既支持有损压缩也支持无损压缩。相较编码JPEG文件,编码同样质量的WebP文件需要占用更少的计算资源. 可以使用Chrome打开WebP格式。

怎么把png转为webp

下载地址:

https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html(不需要梯子)

下载下来之后可以通过查看README来看指令如何使用, 这里主要用到img2webp.
example: img2webp -loop 2 in0.png -lossy in1.jpg -d 80 in2.tiff -o out.webp
-loop: 循环次数
-lossless/-lossy: 无损压缩/有损压缩 默认是无损压缩
-o: 输出文件格式
-d: 帧持续时间 默认100毫秒, 一定要放在图片的前面才会生效
-q: 质量0-100,越高越好,越高生产文件也越大

shell脚本: towebp.sh

#!/bin/bash

path=$1

if [ ! $path ]; then
    path='.'
fi

cd $path

filelist=$(ls .)
imgs=''
echo $filelist
for file in $filelist; do
    #如果是文件且后缀名为png
    if [ -f $file ] && [ "${file##*.}" = "png" ]; then
        imgs=$imgs$file" "
    fi
done
echo $imgs
img2webp -d 50 -lossy $imgs -o $path"/"out.webp

执行sh towebp.sh ~/xxx/xxx/imgs 后面的路径填写绝对路径,如果已经在是要打包的资源目录则可以不传, 最后会在你图片资源目录下生成一个out.webp的文件, 可有用浏览器打开进行预览.

怎么使用webp

android源码其实已经提供了支持, 只是还没有开放出来! 源码位置位于:
/frameworks/ex/framesequence
需要用到libframesequence.so和FrameSequence.java,FrameSequenceDrawable.java

View drawableView = findViewById(R.id.drawableview);
        InputStream is = getResources().openRawResource(mResourceId);

        FrameSequence fs = FrameSequence.decodeStream(is);
        mDrawable = new FrameSequenceDrawable(fs, mProvider);
        mDrawable.setOnFinishedListener(new FrameSequenceDrawable.OnFinishedListener() {
            @Override
            public void onFinished(FrameSequenceDrawable drawable) {
                Toast.makeText(getApplicationContext(),
                        "The animation has finished", Toast.LENGTH_SHORT).show();
            }
        });
        drawableView.setBackgroundDrawable(mDrawable);

简单说一下原理

我们主要用到的是FrameSequenceDrawable这个类, 这个类继承了Drawable, 构造函数中需要传如webp文件的InputStream, 通过so库去解析webp资源拿到图片的宽高,总的帧数等信息, 这里还初始化2张bitmap, 一张是当前要显示的那一帧, 另一张是下一张要显示的那一帧, 最后还初始化一个异步的handle, 执行start的时候会发送handle执行一个异步任务, FrameSequenceState的getFrame(int frameNr, Bitmap output, int previousFrameNr), frameNr是即将要显示的这一帧index, output是需要绘制的bitmap, previousFrameNr是前一帧的index, 该方法会返回这一帧的播放时间, 然后再调用Drawable的scheduleSelf方法, 传入上面计算好的时间, 时间到了之后就调用draw方法, 把bitmap显示到了ImageView上, 如果还有一帧则继续发handler走上面的过程.

这里需要注意的是, 系统默认系统的方案是实时去往bitmap上绘制绘制完之后就立马释放, 所以getFrame这个 方式是一个比较吃CPU的方法, 如果你帧率越高则cpu吃的越多, 你也可以将bitmap进行缓存, 直接从缓存中拿, 这样好处在不会暂用太多cpu但是会暂用内存, 所以大家可以折中一下, 根据当前设备情况做动态的调整.

你可能感兴趣的:(android)