大家好,我是程序员牛肉。
今天在和朋友聊天的时候,他发了一张很古老的表情包,整张图片呈现很明显的发绿状态。
这张图片直接将我的思绪拉回到七八年前,当时我还经常在QQ群里和别人斗图。大家发一些很经典的表情包的时候,这些图片就会呈现明显的发绿状态,当时的大家戏称这玩意是“电子包浆”。
你们有这种充满“电子包浆”的图片嘛?可以发在评论区看一看。那大家有没有想过这些图片为什么会发绿呢?
我们首先要明确一点:图片并不是因为反复传播而变绿的,而是因为在传播的过程中,各个软件都会对图片进行压缩来节省网络带宽。在反复压缩的过程中,图片就会出现这种明显的“电子包浆”感。
问题的根源出在安卓自己的核心代码上,它对外提供了一个压缩图片的接口。而这个接口使用的是Google的图像库Skia来提供服务。
https://github.com/google/skia 对应的代码仓库
Google在Skip中采用了libjpeg - turbo来完成实际的压缩工作。而在进行压缩工作时,libjpeg - turbo 会先将图像从常见的 RGB 色彩空间转换为 YUV 色彩空间,这是整个压缩流程中的一个基础环节,为后续的离散余弦变换(DCT)、量化等压缩操作做准备。
[libjpeg - turbo是一个对 JPEG 图像编码和解码进行加速的库,是对传统 JPEG 库的优化和改进版本,具有更高的压缩和解压缩速度,同时保持了良好的图像质量。Skia 在进行 JPEG 图像压缩时,会调用 libjpeg - turbo 来完成实际的压缩工作,借助 libjpeg - turbo 的高效算法和优化实现,提升 JPEG 压缩的性能和效果。]
问题就出在RGB转YUV色彩空间的过程中,采用了降低精度来提高转换速度。而在这一过程中,采用了右移操作进行数据截断。
这个操作可了不得,他会直接截断小数部分。例如3.1就会变成3。也就是说YUV这三个值都会因为这个数据阶段而偏小。
我们来解释一下YUV这三个值的意思:
而网络上有一张图就很好的概括了YUV偏向的结果:
https://commons.wikimedia.org/wiki/File:YUV_UV_plane.svg 图片对应网站
由于RGB转YUV中的阶段操作导致YUV这三个的计算值都要比真实值偏小。而在上述的图片中我们可以看到:这种偏小带来的结果就是整体的显色效果都要向右下角靠拢。
显然,YUV 计算机整体偏小导致结果就是:变暗,变绿。
而大多数互联网公司例如贴吧,QQ的客户端在进行图片压缩算法的时候都采用的是安卓提供的这一套压缩图片的算法。
这也就导致了“电子包浆”的重灾区一般就集中在贴吧和QQ中。
而Google在2016年的4月19日才正式的修复了这个bug。在百度查询了一下对应的Android发布版本,也就是说Android7才消除了这个问题。
这个bug的修复很简单,在代码层面的表现为:把原本 Skia 库 YUV 转换代码全部删掉,把这个过程留给整个过程最底层的 libjpeg-turbo 库自己来做,并且用默认的 JDCT_ISLOW 方法代替 JDCT_IFAST 方法。
https://github.com/google/skia/commit/c7d01d3e1d3621907c27b283fb7f8b6e177c629d 对应的PR
总结一下呢:就是在图片压缩的过程中需要先将RGB色彩空间转化为YUV色彩空间。但是在转化的过程中对小数的处理并不到位。导致计算出来的YUV比真实的YUV值要偏小。反映在图片上就是整体偏暗偏绿。
那么今天关于“图片为什么会有电子包浆”的内容就介绍到这里了。相信通过我的介绍,你已经大致了解了为什么会出现这种情况。希望我的文章可以帮到你。