(十七)WebP 的测试与使用

(十七)WebP 的测试与使用版权声明 本文为博主原创文章 未经博主允许不得转载

大家好,欢迎来到IT知识分享网。

一、WebP

1.什么是 WebP

WebP(发音 weppy),是一种同时提供了有损压缩与无损压缩(可逆压缩)的图片文件格式,派生自视频编码格式 VP8,被认为是 WebM 多媒体格式的姊妹项目,是由 Google 在购买 On2 Technologies 后发展出来,以 BSD 授权条款发布。

WebP 最初在2010年发布,目标是减少文件大小,但达到和 JPEG 格式相同的图片质量,希望能够减少图片档在网络上的发送时间。 2011年11月8日,Google 开始让 WebP 支持无损压缩和透明色(alpha 通道)的功能,而在 2012 年 8 月 16 日的参考实做 libwebp 0.2.0 中正式支持。根据 Google 较早的测试,WebP 的无损压缩比网络上找到的 PNG 档少了 45% 的文件大小,即使这些 PNG 档在使用 pngcrush 和 PNGOUT 处理过,WebP 还是可以减少 28% 的文件大小。

WebP 支持的像素最大数量是16383×16383。有损压缩的 WebP 仅支持 8-bit 的 YUV 4:2:0 格式。而无损压缩(可逆压缩)的 WebP 支持 VP8L 编码与 8-bit 之 ARGB 色彩空间。又无论是有损或无损压缩皆支持 Alpha 透明通道、ICC 色彩配置、XMP 诠释数据。

这是一段来自维基百科对 WebP 的介绍,简单的说,就是 WebP 比 PNG 等其他图片小得多
在这里插入图片描述

2.WebP 图片的生成

使用 AS 进行转换:

在 Android Studio 中,右键图片或文件夹,选择 Convert to WebP ,即可生成 WebP 图片。在 Android Studio 中,要使用 WebP ,需要 Android API 在 18 以上。
在这里插入图片描述
在这里插入图片描述
原先 6.6KB 的 JPG 图片转换成 WEBP 的图片,只有1.6 KB。这是非常可观的。

使用工具生成

使用 iSparta 进行转换,点击进行下载使用。(个人使用 win 10 笔记本,不知道什么原因,不能选择图片。所以就不再这边进行使用讲解。)

3.WebP 性能

这边使用 WEBP 格式与 JPEG 格式进行比较。

对同一张 png 图片进行编码生成不同 quality 的 WEBP 和 JPEG 图片,记录时间,然后把生成的图片在进行解码,记录时间,进行对比。
MainActivity:

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); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xiaoyue_png); compress(bitmap, Bitmap.CompressFormat.JPEG, 100); compress(bitmap, Bitmap.CompressFormat.JPEG, 70); compress(bitmap, Bitmap.CompressFormat.JPEG, 50); compress(bitmap, Bitmap.CompressFormat.JPEG, 30); compress(bitmap, Bitmap.CompressFormat.JPEG, 0); compress(bitmap, Bitmap.CompressFormat.WEBP, 100); compress(bitmap, Bitmap.CompressFormat.WEBP, 70); compress(bitmap, Bitmap.CompressFormat.WEBP, 50); compress(bitmap, Bitmap.CompressFormat.WEBP, 30); compress(bitmap, Bitmap.CompressFormat.WEBP, 0); } / * 压缩图片到文件 * @param bitmap 待压缩图片 * @param format 压缩的格式 * @param quality 质量 */ private void compress(Bitmap bitmap, Bitmap.CompressFormat format, int quality){ String path; if (format == Bitmap.CompressFormat.WEBP){ path = Environment.getExternalStorageDirectory().getPath() + "/xiaoyue_png" + quality + ".webp"; }else { path = Environment.getExternalStorageDirectory().getPath() + "/xiaoyue_png" + quality + ".jpeg"; } long time = System.currentTimeMillis(); FileOutputStream outputStream; try{ outputStream = new FileOutputStream(path); bitmap.compress(format, quality, outputStream); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } Log.e(TAG, "111 zx 编码 " + format + " 图片, 质量 " + quality + " 耗时:" + (System.currentTimeMillis() - time)); time = System.currentTimeMillis(); BitmapFactory.decodeFile(path); Log.e(TAG, "111 zx 解码 " + format + " 图片, 质量 " + quality + " 耗时:" + (System.currentTimeMillis() - time)); } } 

在 AndroidManifest.xml 中配置文件读写权限。

AndroidManifest.xml:

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 

结果:
在这里插入图片描述
生成的图片文件:
在这里插入图片描述
结论: 相同的 quality 下:

编码 :WEBP 比 JPEG 耗时多很多 解码:耗时差不多,JPEG 稍微快一点点,可忽略不计 内存:WEBP 的图片内存比 JPEG 的图片内存小很多 

注: 我们把 drawable 下的图片换成 WEBP,这时候生成图片耗时对应用是没有影响的,但是可以缩小图片的大小。其他情况自行选择。

4.WebP 的兼容现状

安卓中国中有明确的说明:https://developer.android.google.cn/guide/topics/media/media-formats.html
在这里插入图片描述

4.2.1 + 对于 WEBP 的d ecode、encode 是完全支持的(包含半透明的webp图) 4.0 + 到 4.2.1 ,只支持完全不透明的 decode、encode 的 WEBP 图 4.0 以下,应该是默认不支持 WEBP了 

从上面可以发现,对 WEBP 完全支持必须是 4.2.1 以上,目前大部分安卓手机应该都在这个范围。如果说要在安卓 4.0 以下使用 WEBP 的话,需要使用 libwebp 进行支持。

二、libwebp

1.libwebp 的配置

1 下载

在谷歌中国中进行 libweb 源码下载。
在这里插入图片描述
解压出来,可以发现压缩包中提供多种编码方式,这边直接采用 mk 方式进行编码。

2 修改 Android.mk
在 Android.mk 文件中进行修改,添加:

ENABLE_SHARED := 1 

在这里插入图片描述

在 libwebp 下面配置中添加一个源文件:

swig/libwebp_java_wrap.c \ 

在这里插入图片描述

3 新建 Application.mk
在 libwebp 目录下新建 Application.mk 文件。
在这里插入图片描述
指定支持的 CPU 架构以及安卓版本,根据实际情况进行调整:

APP_ABI := armeabi-v7a x86 APP_PLATFORM = android-14 

4 编译
修改目录名为 jni,在父级目录开启命令行。
在这里插入图片描述
执行 ndk-build.cmd 命令。
在这里插入图片描述
等待编译成功,会生成一个 jni 同级目录 libs,在这个目录下有我们需要的 CPU 架构对应的库文件。
在这里插入图片描述

5 导入 so
在 main 下面新建 jnilibs 文件夹,把上面编译生成的 libwebp.so 拷贝到项目中。
在这里插入图片描述
6 添加 jar
把 libwebp 下的 libwebp.jar 这个包添加到项目中。
在这里插入图片描述

二、libwebp 的使用

1.编码

 / * 将 bitmap 使用 libwebp 编码为 webp 图片 * * @param bitmap */ private void encodeWebp(Bitmap bitmap, int quality) { long time = System.currentTimeMillis(); //获取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, quality); FileOutputStream fos = null; try { fos = new FileOutputStream(Environment .getExternalStorageDirectory() + "/libwebp" + quality +".webp"); fos.write(bytes); } catch (Exception e) { e.printStackTrace(); } finally { if (null != fos) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } Log.e(TAG, "111 zx libwebp 编码图片, 质量 " + quality + " 耗时:" + (System.currentTimeMillis() - time)); } 

libwebp.WebPEncodeRGBA 需要五个参数,分别是图片数据、宽、高、一行数据的字节数、图片质量。(这边 bitmap 默认·是 ARGB_8888,所以是 width * 4)。

2.解码

 / * libwebp 解码 webp图片 */ private Bitmap decodeWebp(String path) { byte[] bytes = null; InputStream is = null; try { is = new FileInputStream(path); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int len; while ((len = is.read(buffer)) != -1) { bos.write(buffer,0,len); } bytes = bos.toByteArray(); } catch (IOException e) { e.printStackTrace(); }finally { try { if (is != null){ 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; } 

3.效率
在这里插入图片描述

跟上面的 webp 编解码对比,在编码速度上相对会快一些,解码速度差不多。(不同手机结果可能有差异)

三、完整代码

MainActivity :

package com.xiaoyue.libwebp; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import com.google.webp.libwebp; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; public class MainActivity extends AppCompatActivity { static { System.loadLibrary("webp"); } private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xiaoyue_png); compress(bitmap, Bitmap.CompressFormat.JPEG, 100); compress(bitmap, Bitmap.CompressFormat.JPEG, 70); compress(bitmap, Bitmap.CompressFormat.JPEG, 50); compress(bitmap, Bitmap.CompressFormat.JPEG, 30); compress(bitmap, Bitmap.CompressFormat.JPEG, 0); compress(bitmap, Bitmap.CompressFormat.WEBP, 100); compress(bitmap, Bitmap.CompressFormat.WEBP, 70); compress(bitmap, Bitmap.CompressFormat.WEBP, 50); compress(bitmap, Bitmap.CompressFormat.WEBP, 30); compress(bitmap, Bitmap.CompressFormat.WEBP, 0); encodeWebp(bitmap, 100); encodeWebp(bitmap, 70); encodeWebp(bitmap, 50); encodeWebp(bitmap, 30); encodeWebp(bitmap, 0); } / * 压缩图片到文件 * @param bitmap 待压缩图片 * @param format 压缩的格式 * @param quality 质量 */ private void compress(Bitmap bitmap, Bitmap.CompressFormat format, int quality){ String path; if (format == Bitmap.CompressFormat.WEBP){ path = Environment.getExternalStorageDirectory().getPath() + "/xiaoyue_png" + quality + ".webp"; }else { path = Environment.getExternalStorageDirectory().getPath() + "/xiaoyue_png" + quality + ".jpeg"; } long time = System.currentTimeMillis(); FileOutputStream outputStream; try{ outputStream = new FileOutputStream(path); bitmap.compress(format, quality, outputStream); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } Log.e(TAG, "111 zx 编码 " + format + " 图片, 质量 " + quality + " 耗时:" + (System.currentTimeMillis() - time)); time = System.currentTimeMillis(); BitmapFactory.decodeFile(path); Log.e(TAG, "111 zx 解码 " + format + " 图片, 质量 " + quality + " 耗时:" + (System.currentTimeMillis() - time)); } / * libwebp 解码 webp图片 */ private Bitmap decodeWebp(String path) { byte[] bytes = null; InputStream is = null; try { is = new FileInputStream(path); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int len; while ((len = is.read(buffer)) != -1) { bos.write(buffer,0,len); } bytes = bos.toByteArray(); } catch (IOException e) { e.printStackTrace(); }finally { try { if (is != null){ 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, int quality) { long time = System.currentTimeMillis(); //获取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, quality); FileOutputStream fos = null; try { fos = new FileOutputStream(Environment .getExternalStorageDirectory() + "/libwebp" + quality +".webp"); fos.write(bytes); } catch (Exception e) { e.printStackTrace(); } finally { if (null != fos) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } Log.e(TAG, "111 zx libwebp 编码图片, 质量 " + quality + " 耗时:" + (System.currentTimeMillis() - time)); time = System.currentTimeMillis(); decodeWebp(Environment .getExternalStorageDirectory() + "/libwebp" + quality +".webp"); Log.e(TAG, "111 zx libwebp 解码图片, 质量 " + quality + " 耗时:" + (System.currentTimeMillis() - time)); } } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/148503.html

(0)
上一篇 2025-03-30 17:26
下一篇 2025-03-30 17:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信