|
你是否知道,在某乎上传的每一个GIF都会被“优化”成10倍大小? 经常摸鱼的知友们可能会观察到一个现象:在一些有很多 GIF 图片的文章/回答中,手机通常会非常卡——评论打不开、图片加载不出来、点赞列表更是不用想了。 整个 App 会处于一个“无响应“的状态,划拉半天才加载出几个图片。一看网络上下行,嚯,一下子给我干满带宽了。 不信的话可以试试看下面的回答,给手机上点强度:
[color=inherit !important] 猫和老鼠 GIF 合集2072 赞同 · 293 评论 [url=]回答[/url]
除了手机端优化太差以外,罪魁祸首想必大家都已经猜到了,就是这些 GIF。

上面的回答包含约500MB的图片,平均一张28MB
我是怎么发现的呢,昨天给插件做了一个离线保存文章/回答的功能,然后用我的一篇文章[1]测试了一下,发现——好家伙,一篇文章的图片居然有200MB?要知道我的整个笔记库都没有200MB。高达数十MB的 GIF 随处可见,知乎从哪里搞来的这么大的 GIF?而且更要命的是,这些 GIF 与我本地的 GIF 内容、大小完全一致。我拼了老命调各种参数压缩的 GIF,体积转手就被翻了13倍。

这是两个内容、大小一模一样的GIF,在本地和上传后的对比
这就非常有意思了。 客观上讲,GIF 本身是一个很差的格式[2]。这个发明于1987年的格式除了能动以外一无是处,早就不能顺应时代潮流了。尤其是在互联网时代,任何Bit的压缩都至关重要。 而 GIF 的压缩率远远不如 MP4。比如同样帧率、同样分辨率、同样色彩的 MP4 转成 GIF,体积往往会膨胀10倍,甚至极端情况下50倍以上(动作很多,画面细腻)。 所以早在2010年就有 GIF 的上位替代格式——WebP 格式的存在。WebP 由于各种算法的先进性,体积通常只有 GIF 的10%,但就是浏览器兼容性不是很好,动态的 WebP 要在2020年后才被各大浏览器广泛支持[3]。 但是!问题来了,人家 GIF 虽然已经被扫进了历史垃圾堆,但是能流行这么久也不是吃素的。现代软件在生成 GIF 的时候,都会使用一种叫帧差分的技术。要知道,GIF 的每一帧都有自己的宽高、偏移和透明度。这就允许 GIF 编码器记录上一帧和当前帧之间的差异,然后生成一个局部帧,解码器在播放的时候就可以把局部帧“盖”在上一帧上,让它动起来的同时又不占更多体积。

比如,把上面的这个GIF切成一张张图片是这样的,这不是因为GIF损坏了,而是因为这些都是“局部帧”
帧差分技术可以大大减小 GIF 体积,尤其是像屏幕录制这样,有大量重复像素的画面。大部分情况下,GIF 只需要处理一些鼠标移动的帧就行了。这就是为什么我可以把高清的屏幕录制 GIF 压缩到小于3MB。 那么我们可以自然地猜到,这些 GIF 之所以这么大,因为它全部都是全屏重绘,没有一帧局部帧。为了验证这个猜想,我做了一个对比:一边是132KB的原始 GIF,一边是上传到云端然后膨胀到1.2MB的 GIF。然后用 Pillow 分析了一下每一帧对于上一帧重复像素的比例。结果非常的 Amazing 啊:

这是原始 GIF

这是某平台上的 GIF
可以明显地看到,我本地的 GIF 被优化了——除了第一帧是全量帧(全屏绘制)以外,其他都是局部帧。而知乎的 GIF 居然全都是全量帧,没有一丝一毫的优化。在像素、尺寸一样的情况下,体积膨胀这么多倍也就很合理了。
可见平台后端对于每一个 GIF 图片都进行了深度的负优化,具体流程可能是这样的:拿到原始 GIF -> 开始拆解,拆成一张张PNG -> 加水印或者其他处理 -> 将一组 PNG 转成 WebP 和我们拿到的 GIF。像 GIF 这样的历史遗留产物,某平台不仅当成宝,还要史上加史。如果 WebP 是 4k 全彩显示屏,那么 GIF 就是《哈利·波特》中能动的报纸,某平台就是把一沓这样的报纸用502胶水粘在一起给你。 这样的后端可能几年前就开始运行了,不知道浪费了多少用户宝贵的流量,让手机卡顿了多少秒。
说实话,我想破头皮都不知道为什么后端会采取这样的策略 如果是加水印,那么跟据帧差分的策略,只需要在第一帧写入水印就行了。即使是背景在动的半透明水印,也只需要水印所在的矩形变成差分区域,并不会增加多少体积(10%顶天了)。更何况文中的 GIF 中都不存在水印(因为我把水印关了),照样膨胀10倍。 如果是兼容老设备:那就更说不通了。帧差分的 GIF 早在1989年就已经被写入了标准[4],那时候浏览器还初具雏形。等到 Netscape 和 IE 竞争的那个年代浏览器早就对动态的帧差分 GIF 有完善的支持[5],那时候知乎还没出生呢。 最后只有一种可能—— It is something...

|