大家好,欢迎来到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