0%

为什么图片转发多了会变绿?

第一次写科普文,写的不好多多包涵。

前言

在群里聊天的时候表情包飞来飞去,发现有些表情包已经发绿,人称:电子包浆。

green

早期贴吧里边这种表情包很多,在调侃“你这表情都绿了”的时候我突然想,那么为什么他会发绿呢?去查了一些资料终于搞明白了原因。

图片压缩

首先我们要明白一个道理:为了节省空间,上传到网上的表情包或多或少都会被压缩。所以我们把问题就定位到了具体的地方:为什么图片压缩之后会变绿?在这之前我们先介绍一点其他知识。可以跳过

谷歌自家的图像库:Skia

这是自安卓诞生以来就引入的开源的二维图形库,提供各种常用的API,并可在多种软硬件平台上运行。谷歌Chrome浏览器、Chrome OS、安卓、火狐浏览器、火狐操作系统以及其它许多产品都使用它作为图形引擎。

RGB 与 YUV

对一种颜色进行编码的方法统称为颜色空间色域,世界上任意一种颜色的色域我们都可以用一组固定的数字进行描述,RGB(红,绿,蓝)就是很常用的一种。采用这种编码方法,每种颜色都是通过三个变量来表示这个颜色的属性。YUV是什么呢?Y 表示亮度,也就是灰阶值,U 和 V 表示的则是色度,它允许降低 U 和 V 的采样率来节省带宽,所以我们在上传图片的时候他大都是采用 YUV 格式上传的。

Skia 的图像压缩算法

这些会使图片变绿的 App 都不约而同的采用了一个 Android接口 bitmap.compress,这个接口为了达到更好的压缩效果,把图片压缩成 jpg 的时候采用的是将 RGB 转化为 YUV 的方式,降低京都的同时提高了速度。这个转换的算法不需要了解,这里不再赘述。正常情况下这个算法是有损的,但其实他也不会偏绿。

问题所在

说了这么多,终于进入正题:为什么变绿?请看下面的算法:

rgb2yuv
这是我在 GitHub 的 skia 库的 commit中截取的代码,核心部分就是 y,u,v 的计算。我们可以看到,这里使用右移的操作代替了除法操作,那么问题来了:**y,u,v 都是整数,你右移之后小数点后面的东西呢?

我们知道计算机使用补码来储存数字,那么如果截断了小数,我们很容易可以得到他是向下取整的,也就是说他的三个值都会偏小,或者说往负数方向移动。维基上的图片很直观的告诉我们,如果 u 和 v 往负数方向移动我们会得到什么:

yuv

结果已经很明确了,颜色会向绿色方向偏移。本文结束

一次?很多次?

可能有人会问:这么说偏移只会发生一次,那为什么会越转发越糊?小问号,你是否有很多朋友?

这是很好解释的:图片上传之后还会进行其他操作,会使 YUV 产生小的变化,只要一变化就有可能有小数 → 只要有小数就有可能小于0.5 → 只要小于零点五就有可能被舍去 → 只要被舍去就会变绿 → 完蛋

所以可以得出一个明确的结论:只要出现了,变绿是会一直发生的变绿,只有零次和无数次

好像出现了什么奇怪的东西

解决?

很简单啊!你用 double 不就行了吗!!哪有这么多鬼事情!!!

我不是开发者办么办?我只是想用用怎么办?

那只好。。。直接用就行了

因为在 2016年4月19日,这个问题已经被修复了。

fix

最后

总的来说,问题就是旧版系统上的算法问题导致图片压缩变绿,在新版已经修复了,完毕。

现在安卓采用了很棒的压缩算法,基本上保证了图片的质量在压缩之后不会有太大的变化,所以大家只要放心使用就行了。从时间上来看是 Android 7 就进行了修复,所以之后的系统就不会出现这个问题。也就是说现在你用的绿图都是老古董了你以为你还年轻嘛

就是这样!感谢读到这里!

最后的最后

立下flag去探究一下为什么手机QQ保存图片作为表情质量变差,希望成为下一篇科普文

-------------本文结束感谢您的阅读-------------