源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

Android WebP 图片压缩与传输

  • 时间:2022-08-22 16:18 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:Android WebP 图片压缩与传输
[b]1. 简介[/b] 直到4g时代,流量依然是宝贵的东西。而移动网络传输中,最占流量的一种载体:图片,成为了我们移动开发者不得不关注的一个问题。 我们关注的问题,无非是图片体积和质量如何达到一个比较和谐的平衡,希望得到质量不错的图片同时体积还不能太大。 走在时代前列的谷歌给出了一个不错的答案——WebP。 WebP是一种图片文件格式,在相同的压缩指标下,webp的有损压缩能比jpg小 25-34%。而在我自己的测试里,有时候能小50%。 [b]2. 大企业背书[/b] WebP在2010年发布第一个版本,到现在已经6年了,谷歌旗下的各种网站G+、以及非常有代表性的YouTube,他的视频文件格式WebM就是基于WebP构造的。 据说腾讯、淘宝、美团也有部分应用。 [b]3. Android 端 JPG 转换 WebP[/b] 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,然后再将其保存成本地文件。 这是非常常见的图片压缩手段。 [b]4. WebP对比[/b] 我用我日常生活里拍下的照片来做简单的对比测试,不是特别严谨,仅供简单的参考。 拍照设备是刷了CM13的 一加 1 。拍照场景都是日常生活特别常见的。 以下是原图预览,就不一个个放出来了,太大。 [img]http://files.jb51.net/file_images/article/201608/2016830154210505.jpg?2016730154233[/img] [b]缩小分辨率,同时压缩质量[/b]
文件名 照片原图 压缩后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%
[b]平均压缩比是:27.24%[/b] [b]按照原图大小,不缩小分辨率[/b][b],仅压缩质量。[/b]
文件名 照片原图 压缩后jpg 压缩后webp 压缩比
3.jpg 4751 kb 796 kb 426 kb 46.48%
至此,我们就非常方便的使用了webp来对图片进行更加极致的压缩,兼顾了图片体积和质量。 呃,csdn不支持上传webp的图片。你们可以看压缩包。 我嫌麻烦,可能不会传压缩包了……所以,你们看截图吧~ 睁大眼睛对比一下有啥区别,不缩小分辨率,仅压缩质量,这个3.jpg可是有46.48%的压缩比噢。 这个场景是晚上在灯光充足的室内吃饭拍的。 [img]http://files.jb51.net/file_images/article/201608/2016830154533420.jpg?2016730154558[/img] [img]http://files.jb51.net/file_images/article/201608/2016830154629450.jpg?2016730154648[/img] [b]5. 用Gzip再压缩[/b] 刚刚是针对本地图片的压缩,接下来,我们需要将图片传输到服务器。这个过程依然有优化空间,就是利用Gzip。 Gzip的作用对象是整个请求体,具体来说是对请求体中的内容进行可逆的压缩,类似pc上zip的那种。 Gzip压缩的请求体,需要加入相应的header: 「Content-Encoding:gzip」。 这事情Retrofit会帮你做好。 后台服务器接收到在此类型的请求,就会对请求体解压,因此需要后端的支持。 另外要注意的是,Gzip针对比较大的请求体压缩效果不错,尤其是未经过压缩的纯文本类型。 如果请求本来就很小,那么就不要使用gzip压缩了,压缩包自己的元数据可能比你的请求体还大,得不偿失。你可以自己测试一下,我估计zip和gzip的压缩字典比较类似,可以直接在pc上做测试。 [b]6. Retrofit对请求Gzip压缩[/b] 网络请求方面,我项目里使用Retrofit (OKHttp) + RxJava。 Retrofit的Gzip压缩,本质上是通过OKHttp的拦截器来完成的。 0拦截请求 1加入header 2压缩请求 3发送出去 搞定,方便。 [url=https://github.com/square/okhttp/wiki/Interceptors]https://github.com/square/okhttp/wiki/Interceptors[/url]
/** 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();
 }
 };
 }
}
[b]7. 请求体抓包对比[/b] 我会用Fiddler4 监测整个请求过程,以方便我们得知实际传输了多大的数据。 上传的具体代码就不发了,这个不是重点。 我把请求抓包之后,把request这个保存下来。 [img]http://files.jb51.net/file_images/article/201608/2016830154821012.jpg?2016730154840[/img] 这是同时上传两张图片的大小
文件名 请求体大小
WebP+Gzip 169kb
WebP 222kb
[b]用Gzip压缩 比不加Gzip 又小 23% ! jpg我就不发了,可以按照前面的估算一下~[/b] [b]WebP比Jpg小27%,然后gzip+webp又比单纯的webp小23%,节省下来的流量多可观啊![/b] [b]8. 最后[/b] WebP默认只支持Android 4.0以上,现在项目最低支持的版本是16,所以没什么问题。如果你的项目最低要支持到2.0,好像也有第三方支持,但是我建议你抓产品出去打一顿。 在我们的项目里,iOS没用使用该技术。 根据下面的参考链接的数据以及我本人测试数据来看,WebP不仅大大的节省了用户的流量,同时还可以加速图片传输速度。就照片传输的角度来看,是非常有利的。 如果还是有人告诉你:“IOS做不了,不做了。”,“后台XXX不做了。” 我建议你抓产品出去打一顿。 相关参考: http://isux.tencent.com/introduction-of-webp.html(产品经理看这个) [url=http://www.1sucai.cn/article/91587.htm]http://blog.csdn.net/GeekLei/article/details/41147479[/url] (后台需要看这个) 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也没有用上) [url=http://www.1sucai.cn/article/91591.htm]http://blog.csdn.net/mingchunhu/article/details/8155742(Android全部都要看)[/url]
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部