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,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(),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 reqHeight) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodefile(filePath,options); options.inSampleSize = calculateInSampleSize(options,reqHeight); options.inJustDecodeBounds = false;// options.inPreferQualityOverSpeed = true; return BitmapFactory.decodefile(filePath,options); } public static int calculateInSampleSize(BitmapFactory.Options options,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全部都要看)
总结以上是内存溢出为你收集整理的Android WebP 图片压缩与传输全部内容,希望文章能够帮你解决Android WebP 图片压缩与传输所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)