Android WebP 图片压缩与传输

1. 简介

直到4g时代,流量依然是宝贵的东西。而移动网络传输中,最占流量的一种载体:图片,成为了我们移动开发者不得不关注的一个问题。

我们关注的问题,无非是图片体积和质量如何达到一个比较和谐的平衡,希望得到质量不错的图片同时体积还不能太大。

走在时代前列的谷歌给出了一个不错的答案——WebP。

WebP是一种图片文件格式,在相同的压缩指标下,webp的有损压缩能比jpg小 25-34%。而在我自己的测试里,有时候能小50%。

2. 大企业背书

WebP在2010年发布第一个版本,到现在已经6年了,谷歌旗下的各种网站G+、以及非常有代表性的YouTube,他的视频文件格式WebM就是基于WebP构造的。

据说腾讯、淘宝、美团也有部分应用。

3. Android 端 JPG 转换 WebP

RxJava线程转换:

String[] imgs = new String[]{"1.jpg", "2.jpg", "3.jpg", "4.jpg", "5.jpg"}; String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/test/"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // test = Api.getBuilder().create(Test.class); String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE , Manifest.permission.READ_PHONE_STATE , Manifest.permission.CAMERA}; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(permissions, 0); } compress(); } private void compress() { Observable.from(imgs) .subscribeOn(Schedulers.io()) .doOnNext(new Action1<String>() { @Override public void call(String imgName) { compress(imgName); } }) .subscribe(); } private void compress(String imgName) { try { File file = new File(path, imgName); Log.i("compress", "jpg start"); byte[] bytes = BitmapUtil.compressBitmapToBytes(file.getPath(), 600, 0, 60, Bitmap.CompressFormat.JPEG); File jpg = new File(path, imgName + "compress.jpg"); FileUtils.writeByteArrayToFile(jpg, bytes); Log.i("compress", "jpg finish"); Log.i("compress", "----------------------------------------------------"); Log.i("compress", "webp start"); byte[] bytes1 = BitmapUtil.compressBitmapToBytes(file.getPath(), 600, 0, 60, Bitmap.CompressFormat.WEBP);//分别是图片路径,宽度高度,质量,和图片类型,重点在这里。 File webp = new File(path, imgName + "compress.webp"); FileUtils.writeByteArrayToFile(webp, bytes1); Log.i("compress", "webp finish"); } catch (IOException e) { e.printStackTrace(); } }

我的测试机器也是Oneplus 1 ,CM13,所以需要获取相应的权限。

利用RxJava来做线程操作,在io线程里做了耗时操作。

public static byte[] compressBitmapToBytes(String filePath, int reqWidth, int reqHeight, int quality, Bitmap.CompressFormat format) { Bitmap bitmap = getSmallBitmap(filePath, reqWidth, reqHeight); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(format, quality, baos); byte[] bytes = baos.toByteArray(); bitmap.recycle(); Log.i(TAG, "Bitmap compressed success, size: " + bytes.length); return bytes; } public static Bitmap getSmallBitmap(String filePath, int reqWidth, int reqHeight) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; // options.inPreferQualityOverSpeed = true; return BitmapFactory.decodeFile(filePath, options); } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int h = options.outHeight; int w = options.outWidth; int inSampleSize = 0; if (h > reqHeight || w > reqWidth) { float ratioW = (float) w / reqWidth; float ratioH = (float) h / reqHeight; inSampleSize = (int) Math.min(ratioH, ratioW); } inSampleSize = Math.max(1, inSampleSize); return inSampleSize; }

根据输入的宽高值计算分辨率的缩小比例,再根据输入的压缩质量数值,压缩图片,获得压缩后bitmap,然后再将其保存成本地文件。

这是非常常见的图片压缩手段。

4. WebP对比

我用我日常生活里拍下的照片来做简单的对比测试,不是特别严谨,仅供简单的参考。

拍照设备是刷了CM13的 一加 1 。拍照场景都是日常生活特别常见的。

以下是原图预览,就不一个个放出来了,太大。

缩小分辨率,同时压缩质量

文件名 照片原图 压缩后jpg 压缩后webp 压缩比 1.jpg 5760 kb 98 kb 74 kb 24.49% 2.jpg 4534 kb 64 kb 35 kb 45.31% 3.jpg 4751 kb 93 kb 68 kb 26.88% 4.jpg 7002 kb 121 kb 95 kb 21.49% 5.jpg 5493 kb 111 kb 91 kb 18.02%

平均压缩比是:27.24%

按照原图大小,不缩小分辨率,仅压缩质量。

文件名 照片原图 压缩后jpg 压缩后webp 压缩比 3.jpg 4751 kb 796 kb 426 kb 46.48%

至此,我们就非常方便的使用了webp来对图片进行更加极致的压缩,兼顾了图片体积和质量。

呃,csdn不支持上传webp的图片。你们可以看压缩包。
我嫌麻烦,可能不会传压缩包了……所以,你们看截图吧~

睁大眼睛对比一下有啥区别,不缩小分辨率,仅压缩质量,这个3.jpg可是有46.48%的压缩比噢。
这个场景是晚上在灯光充足的室内吃饭拍的。

5. 用Gzip再压缩

刚刚是针对本地图片的压缩,接下来,我们需要将图片传输到服务器。这个过程依然有优化空间,就是利用Gzip。

Gzip的作用对象是整个请求体,具体来说是对请求体中的内容进行可逆的压缩,类似pc上zip的那种。

Gzip压缩的请求体,需要加入相应的header: 「Content-Encoding:gzip」。
这事情Retrofit会帮你做好。

后台服务器接收到在此类型的请求,就会对请求体解压,因此需要后端的支持。

另外要注意的是,Gzip针对比较大的请求体压缩效果不错,尤其是未经过压缩的纯文本类型。

如果请求本来就很小,那么就不要使用gzip压缩了,压缩包自己的元数据可能比你的请求体还大,得不偿失。你可以自己测试一下,我估计zip和gzip的压缩字典比较类似,可以直接在pc上做测试。

6. Retrofit对请求Gzip压缩

网络请求方面,我项目里使用Retrofit (OKHttp) + RxJava。

Retrofit的Gzip压缩,本质上是通过OKHttp的拦截器来完成的。

0拦截请求
1加入header
2压缩请求
3发送出去

搞定,方便。

https://github.com/square/okhttp/wiki/Interceptors

/** This interceptor compresses the HTTP request body. Many webservers can't handle this! */ final class GzipRequestInterceptor implements Interceptor { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request originalRequest = chain.request(); if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) { return chain.proceed(originalRequest); } Request compressedRequest = originalRequest.newBuilder() .header("Content-Encoding", "gzip") .method(originalRequest.method(), gzip(originalRequest.body())) .build(); return chain.proceed(compressedRequest); } private RequestBody gzip(final RequestBody body) { return new RequestBody() { @Override public MediaType contentType() { return body.contentType(); } @Override public long contentLength() { return -1; // We don't know the compressed length in advance! } @Override public void writeTo(BufferedSink sink) throws IOException { BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); body.writeTo(gzipSink); gzipSink.close(); } }; } }

7. 请求体抓包对比

我会用Fiddler4 监测整个请求过程,以方便我们得知实际传输了多大的数据。

上传的具体代码就不发了,这个不是重点。

我把请求抓包之后,把request这个保存下来。

这是同时上传两张图片的大小

文件名 请求体大小 WebP+Gzip 169kb WebP 222kb

用Gzip压缩 比不加Gzip 又小 23% ! jpg我就不发了,可以按照前面的估算一下~

WebP比Jpg小27%,然后gzip+webp又比单纯的webp小23%,节省下来的流量多可观啊!

8. 最后

WebP默认只支持Android 4.0以上,现在项目最低支持的版本是16,所以没什么问题。如果你的项目最低要支持到2.0,好像也有第三方支持,但是我建议你抓产品出去打一顿。

在我们的项目里,iOS没用使用该技术。

根据下面的参考链接的数据以及我本人测试数据来看,WebP不仅大大的节省了用户的流量,同时还可以加速图片传输速度。就照片传输的角度来看,是非常有利的。

如果还是有人告诉你:“IOS做不了,不做了。”,“后台XXX不做了。”

我建议你抓产品出去打一顿。

相关参考:

http://isux.tencent.com/introduction-of-webp.html(产品经理看这个)

http://blog.csdn.net/GeekLei/article/details/41147479 (后台需要看这个)

https://developers.google.com/speed/webp/

http://www.infoq.com/cn/articles/sdk-optimazation?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term (他们表示IOS也没有用上)

http://blog.csdn.net/mingchunhu/article/details/8155742(Android全部都要看)

时间: 2024-08-01 17:37:30

Android WebP 图片压缩与传输的相关文章

Android WebP 图片压缩与传输_Android

1. 简介 直到4g时代,流量依然是宝贵的东西.而移动网络传输中,最占流量的一种载体:图片,成为了我们移动开发者不得不关注的一个问题. 我们关注的问题,无非是图片体积和质量如何达到一个比较和谐的平衡,希望得到质量不错的图片同时体积还不能太大. 走在时代前列的谷歌给出了一个不错的答案--WebP. WebP是一种图片文件格式,在相同的压缩指标下,webp的有损压缩能比jpg小 25-34%.而在我自己的测试里,有时候能小50%. 2. 大企业背书 WebP在2010年发布第一个版本,到现在已经6年

Android中图片压缩方案详解及源码下载

Android中图片压缩方案详解及源码下载 图片的展示可以说在我们任何一个应用中都避免不了,可是大量的图片就会出现很多的问题,比如加载大图片或者多图时的OOM问题,可以移步到Android高效加载大图及多图避免程序OOM.还有一个问题就是图片的上传下载问题,往往我们都喜欢图片既清楚又占的内存小,也就是尽可能少的耗费我们的流量,这就是我今天所要讲述的问题:图片的压缩方案的详解. 1.质量压缩法 设置bitmap options属性,降低图片的质量,像素不会减少 第一个参数为需要压缩的bitmap图

Android 开发图片压缩/缩略图的方法

在开发图片浏览器等软件是,很多时候要显示图片的缩略图,而一般情况下,我们要将图片按照固定大小取缩略图,一般取缩略图的方法是使用BitmapFactory的decodeFile方法,然后通过传递进去 BitmapFactory.Option类型的参数进行取缩略图,在Option中,属性值inSampleSize表示缩略图大小为原始图片大小的几分之一,即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4. 然而,如果我们想取固定大小的缩略图就比较困难了,比如,我

Android实现简单图片压缩的方法_Android

本文实例讲述了Android实现简单图片压缩的方法.分享给大家供大家参考,具体如下: 在开发图片浏览器等软件是,很多时候要显示图片的缩略图,而一般情况下,我们要将图片按照固定大小取缩略图,一般取缩略图的方法是使用BitmapFactory的decodeFile方法,然后通过传递进去 BitmapFactory.Option类型的参数进行取缩略图,在Option中,属性值inSampleSize表示缩略图大小为原始图片大小的几分之一,即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图

Android图片压缩(质量压缩和尺寸压缩)

在网上调查了图片压缩的方法并实装后,大致上可以认为有两类压缩:质量压缩(不改变图片的尺寸)和尺寸压缩(相当于是像素上的压缩):质量压缩一般可用于上传大图前的处理,这样就可以节省一定的流量,毕竟现在的手机拍照都能达到3M左右了,尺寸压缩一般可用于生成缩略图.两种方法都实装在了我的项目中,结果却发现在质量压缩的模块中,本来1.9M的图片压缩后反而变成3M多了,很是奇怪,再做了进一步调查终于知道原因了.下面这个博客说的比较清晰: android图片压缩总结 总结来看,图片有三种存在形式:硬盘上时是fi

Android图片压缩几种方式总结

Android图片压缩几种方式总结 图片压缩在Android开发中很常见也很重要,防止图片的OOM也是压缩的重要原因. 首先看下Bitmap图片文件的大小的决定因素: Bitmap所占用的内存 = 图片长度 x 图片宽度 x 一个像素点占用的字节数.3个参数,任意减少一个的值,就达到了压缩的效果. 接下来看下Bitmap图片的几种格式的特点: ALPHA_8  表示8位Alpha位图,即A=8,一个像素点占用1个字节,它没有颜色,只有透明度  ARGB_4444 表示16位ARGB位图,即A=4

android-关于webp图片格式在Android中的应用

问题描述 关于webp图片格式在Android中的应用 我现在在做一个类似壁纸的应用,app获取服务端图片展示,有一半图片是webp格式.我们提供下载和分享功能.但是webp图片下载到手机本地不能打开,同时分享webp图片都会出错.求助,该怎么解决.是要把服务端的图片格式都转换为jpg或者png吗?有代码能实现转换吗 解决方案 Android优化-webp图片格式 解决方案二: 你的参考答案在哪啊? 解决方案三: app端的图片格式一般都是**Jpg**和**png**的. 没有用webp的.

Android中3种图片压缩处理方法

  这篇文章主要介绍了Android中3种图片压缩处理方法,本文讲解了质量压缩方法.获得缩略图.图片缩放三种方法并分别给出示例代码,需要的朋友可以参考下 Android中图片的存在形式: 1:文件形式:二进制形式存在与硬盘中. 2:流的形式:二进制形式存在与内存中. 3:Bitmap的形式 三种形式的区别: 文件形式和流的形式:对图片体积大小并没有影响.也就是说,如果你手机SD卡上的图片通过流的形式读到内存中,在内存中的大小也是原图的大小. 注意:不是Bitmap的形式. Bitmap的形式:图

Android图片压缩上传之基础篇_Android

在android程序开发中我们经常见到需要上传图片的场景,在这里有个技术点,需要把图片压缩处理,然后再进行上传.这样可以减少流量的消耗,提高图片的上传速度等问题. 关于android如何压缩,网上的资料也是很多,但大多数都是代码片段,讲解压缩步骤,而没有一个实用的工具类库.那么如何将压缩算法封装成一个实用工具库呢?其中会遇到些什么问题,比如: 1.需要压缩的图片有多少 2.压缩后的图片是覆盖还是保存到另外的目录 3.如果是另存目录需要将原始图片删除吗 4.如果改变压缩后的图片的尺寸大小是按照原图