深度解析

有损与无损:图像格式为什么故意遗忘

koboshiCo-founder
·3 分钟阅读
有损与无损:图像格式为什么故意遗忘
概述

无损压缩只重新打包数据,不做任何改动;有损压缩先改动数据,再打包。这一个决定解释了为什么同一张照片存成 JPEG 能压到 10:1,存成 PNG 却勉强只有 2:1,为什么 JPEG 在 1992 年选择有损,PNG 在 1995 年选择无损,以及为什么现代编解码器如今两种模式全都提供。

拿一张 1200 万像素的照片(4000 × 3000),同一张图存两次。一次存 PNG:24 MB;一次存质量 90 的 JPEG:3.4 MB。两张图并排放在屏幕上,你看不出任何区别。放大到 400%,差别才露头:头发和草丛有点发软,最锐利的边缘多了一圈淡淡的光晕。

两个文件,一张图,体积差 7×。哪个文件都没出问题,区别只在取舍。PNG 的选择是一个比特都不丢,JPEG 的选择是把你不会注意到的部分丢掉。图像格式之间几乎所有的差别,都能追溯到这一个分岔上。

压缩为什么分成两个阵营

1948 年,Claude Shannon 发表 "A Mathematical Theory of Communication",给压缩定下了一条硬下限。他的信源编码定理说:任何数据的无损表示都不可能压到它的以下,熵就是每个符号的平均信息量。完全随机的图像一点都压不动,纯白的图像几乎能压到零。每张真实图像都落在这条尺度的某处,任何无损算法都越不过它。

有损压缩能存在,是因为这条下限有个空子可钻:它管的是你手里的原始数据,管不到你最后留下的数据。先把图像换成另一幅稍有不同、熵更低的图,下限就跟着降下来了。手法说穿了就一招:先改数据,再打包。工程上真正要回答的问题是:哪些改动可以接受。

答案取决于两件事。一是内容。设置面板的截图,大半是平色和重复的图形,熵低,好预测;森林的照片,放到像素层面全是光子散粒噪声和传感器读出噪声,熵高,没法预测。二是给谁看。读文件的程序要的是精确的比特,一个都不能错;看图的人眼却天生带容错:对颜色的空间分辨力有限,对细密的高频纹理不敏感,感知亮度时认的是比例而不是绝对值(韦伯定律,大致 1% 到 2% 的亮度级差)。

格式就是这样分成两派的。内容可预测、看文件的是机器或者是会放大逐像素检查的人,选无损。内容满是噪声、看文件的是一臂之外的人眼,你就丢得起。

有损压缩的工作原理

人们常说有损编解码器就是 "扔数据"。大方向没错,但说得太粗。它们扔的不是随便什么数据,而是由一个模拟人眼视觉的模型挑出来的那部分。整条流水线是这样的:

  1. 把 RGB 转成亮度-色度分离的色彩空间(JPEG 用 YCbCr,其他格式也各有类似拆法)。人眼分辨亮度细节远强于分辨颜色细节,所以色度通道可以只存四分之一分辨率(4:2:0 子采样)。光这一步就砍掉约 50% 的原始数据,而大多数照片里根本看不出来。

  2. 把每个块变换成频率。 JPEG 对 8 × 8 的块做离散余弦变换(DCT),JPEG 2000 用小波,AV1 和 HEVC 用更大、尺寸可变的变换。得到的形状总是一样:少数几个大系数描述大轮廓,一大堆小系数描述精细纹理。

  3. 量化。 每个系数除以一个步长,再四舍五入取整。小系数直接变零。这是整条流水线里唯一真正有损的一步,编码器上那个质量设置,无非就是这些步长的乘数。质量 95 用小步长,几乎什么都留下;质量 30 用大步长,大部分精细纹理被清零。

  4. 给剩下的数据做熵编码。 zig-zag 扫描、游程编码、Huffman 编码或算术编码。这一阶段是无损的,只负责把已经量化完的数字打包。

再把这份清单过一遍:第 1、2、4 步都可逆,只是整理和打包数据。真正把图像毁掉的是第 3 步,而且是故意毁掉,一次一个舍入误差。

这么毁数据会留下很好认的痕迹。质量压得太低,就会出现块效应(blocking):天空和墙面上浮出 8 × 8 的网格边;振铃(ringing):文字和高对比度边缘围上一圈光晕;色带(banding):平滑的渐变塌成一级一级台阶。把有损文件再存一次,流水线就在已经受损的数据上再跑一遍,这就是**代际损失(generation loss)**会层层累积的原因。一张 JPEG 重存到第十次,看起来就像第一张的水彩临摹。

无损压缩的工作原理

无损编解码器不能这么干。解码出来的文件必须和原文件逐比特一致,所以它们能做的只有两件事:建模、打包。标准做法分两步。

第一步,去相关(decorrelate)。 PNG 压缩之前先对每一条扫描线做滤波。每一行,编码器从五种预测器(None、Sub、Up、Average、Paeth)里挑一个,存下实际像素和预测值之间的差。一整行纯白,存完就是一个白色像素加几千个零;一段平滑渐变,存完是一串很小、缓慢变化的残差。不管哪种情况,数字都会变小、挤在零附近,而这正是下一步最想要的输入。

第二步,熵编码。 PNG 用的是 DEFLATE,gzip 和 zip 背后的同一个算法,由两个 1970 年代的想法拼成。LZ77 负责找重复的字节序列,每处重复都替换成一个指向前方 32 KB 数据的(距离、长度)指针;Huffman 编码再给出现频率高的值分短码、给罕见的值分长码。这两步都不丢东西。拿到打包后的数据流,你永远能把它原样放回去,一字节不差。

这就解释了为什么 PNG 对付截图得心应手,碰上照片却毫无办法。界面图形到处是重复:相同的行、重复的图标、大段平色,LZ77 走到哪里都有匹配,滤波器再把剩下的变成接近零的残差。照片则什么都不重复。散粒噪声让每个像素都和邻居差一点,预测器猜不中,残差又大又乱,LZ77 一处重复也找不到。一张 1200 万像素的照片,PNG 相对原始像素通常只能压到 1.3:1 到 1.6:1;视觉质量相近的 JPEG 能到 10:1。

文件更大,换来的是一条绝对的保证:解码一张 PNG,对像素算哈希,每次都和源文件一致。要走 OCR 的截图、要反复拿出来改的扫描件、可能进论文或上法庭的医学和科学图像,要的就是这条保证。

JPEG 为什么在 1992 年押注有损

联合图像专家小组(Joint Photographic Experts Group)1986 年开工,那个年代的限制条件几乎解释了它后来的每一个设计决定。一块 20 MB 的硬盘要卖几百美元,1.44 MB 软盘是搬运文件的标准工具。调制解调器运气好能跑 14.4 kbps,按这个速度,一张 921 KB 的未压缩 VGA 照片要下载差不多九分钟。10:1 的有损版本一分钟以内能下完,2:1 的无损版本还得等四分多钟。

委员会自己的测试已经说明,无损这条路走不远。既定目标是照片类内容("连续色调图像"),这类内容天生没多少冗余可利用。账算到这里,他们能压榨的只剩一个环节:看图的人。

知道的人不多:1992 年发布的那份标准(ISO/IEC 10918-1)里其实带着一个无损模式。它完全跳过 DCT,用七种固定预测器之一,从至多三个相邻像素预测当前像素,再对残差做熵编码。思路和 PNG 三年后用的那套是一样的。但几乎没有人去实现它,解码器不理,编码器也不理。等到医学影像真的需要无损 JPEG 时,行业干脆另立了一个标准(JPEG-LS,ISO/IEC 14495,1999)。

委员会还得躲着专利走。JPEG 的算术编码选项陷在 IBM 的 Q-coder 专利里,免版税的基线规格只好定在 Huffman 编码上,大多数实现后来也从没碰过算术那条路。专利问题左右编解码器设计,这在 1992 年不算新鲜事,而且很快还要变本加厉。

说到底,JPEG 押的是一场心理视觉的赌局:压缩的最后 5×,靠的不是数学,是生物学。

PNG 为什么在 1995 年押注无损

PNG 不是被设计出来的,是被一场专利危机逼出来的。

1994 年 12 月,Unisys 宣布要对使用 GIF 的软件收许可费,理由是 GIF 的压缩依赖 LZW 算法,而覆盖这个算法的 1985 年专利在 Unisys 手里。GIF 的作者 CompuServe 和 Unisys 达成协议,把费用转嫁给了开发者。Usenet 上的图形社区炸了:GIF 免费用了七年,整个早期网络的图片和工具,一夜之间全落在了别人的专利范围里。

几周之后,1995 年 1 月初,Thomas Boutell 贴出了替代格式的第一份草案。一群志愿者在邮件列表里干了几个月,把设计敲定了下来。PNG 1.0 在 1996 年 10 月成为 W3C 推荐标准,1997 年 3 月又成了 RFC 2083。

有两条要求从头到尾没有讨论余地。一是所有算法都必须完全不沾专利,答案只能是 DEFLATE(Phil Katz 的 PKZIP 里那套 LZ77 加 Huffman 的组合,由 Jean-loup Gailly 和 Mark Adler 实现在 zlib 里)。二是格式必须无损,没有商量。社区要换掉的是 GIF,一个会把图压坏的替代品,从第一天起就不会有人用。更何况专利审查摆在那里,JPEG 赖以成立的那些感知编码技巧,本来也一点空间都没剩下。

内容同样关键。PNG 是为 GIF 实际承载的东西做的:标志、示意图、线条画、图标、截图,全是锐利边缘加大面积平色,恰好是 JPEG 振铃伪影最扎眼的内容。转头去抢照片市场,等于重新发明一遍 DCT,再跟根深蒂固、免版税的 JPEG 正面硬碰。PNG 选了一场打得赢的仗,而且赢得干干净净。GIF 专利 2003 年到期(美国以外 2004 年),但那时候,PNG 早就把它的活儿接过来了。

有损为什么还是赢下了市场

PNG 守住了自己的一亩三分地,JPEG 拿走了剩下的一切。

原因很简单:体量。网络上的图像绝大多数是照片,而对照片来说,有损不是妥协,是对的工具。2025 年的 Web Almanac 显示,问世三十年后,JPEG 仍约占全网传输图像的 57%。社交信息流、新闻摄影、商品图、房源列表,全是连续色调内容。在人们实际使用的屏幕上,质量 75 的有损编码和源文件看不出区别。

经济账也往同一个方向推。存储和带宽按字节收费,10:1 对 2:1 不是零头差距,而是在画质可以接受的前提下,5× 的分发成本差。页面速度跟着文件大小走,文件大小跟着压缩走。每台相机、每部手机,出厂默认就是有损格式(JPEG 或 HEIC);每个 CMS 生成的都是有损缩略图;社交平台把每一次上传都重编码一遍,一半为了体积,一半为了剥掉元数据和藏在里面的恶意东西。摄影师可以上传一张完美无瑕的 TIFF,时间线上发出去的,是一张质量 85 的 JPEG。

无损其实没输,只是退到了那条保证真正值钱的地方:截图和 UI 素材,伪影在那里一眼就能看到,内容本身也压得好;编辑流水线里的母版,每多一代有损都在累积损伤;医学、法律和科学影像,在那里 "差不多" 不能当证据用。这些地盘上,PNG 和 TIFF 的地位没人撼动,只是网络的流量不从那里走。

各格式的落点

格式年份模式主要阵地
JPEG1992有损(有个无损模式,几乎没人用)照片,通用兜底
JPEG 20002000两种都有(有损 9/7 和无损 5/3 小波)数字电影,档案
PNG1996无损截图,UI,图形
GIF1987无损,最多 256 色简单动画,梗图
TIFF1986容器:原始数据、LZW、ZIP 或 JPEG印刷,扫描,归档
WebP2010两种都有网络分发,约占 LCP 图像的 11%
HEIC2015实际上都是有损(HEVC 有无损模式)iPhone 照片
AVIF2019两种都有浏览器里最好的有损压缩比
JPEG XL2021两种都有,另能无损重压缩 JPEGSafari 已支持,Chrome 需开启 flag

两个趋势值得注意。一是新编解码器不再站队:WebP、HEIC、AVIF 和 JPEG XL 都在同一份规范里同时给出有损和无损两种模式,JPEG 2000 早在 2000 年就这么干了。"有损还是无损" 这个问题,从 "选哪个格式" 变成了 "选哪个模式"。二是边界情况不断冒出来。JPEG XL 能把一张现成的 JPEG 无损地重压到原来的 80% 左右,能做到这一点,是因为两个阵营互相研究了对方三十年的算法。

实际中怎么选

决策树很短:

  • 发布照片?选有损。要兼容选 JPEG,要体积选 WebP 或 AVIF。
  • 保存截图、标志,或任何带文字和平色的内容?选无损,用 PNG。
  • 要编辑?母版保持无损,导出时另存有损副本,并且永远别把有损文件用同一格式再存一遍。每多一代,损伤就叠一层。
  • 要转换?让输出去配合用途,而不是配合输入。一张要进相册的 PNG 截图,应该转成 JPEG 或 WebP;一张要进设计稿的 JPEG,应该转成 PNG。这不是因为它能提升质量(不能),而是因为它到此为止,不会再继续损失。

最后这一点,用 iPhone 拍照的人最容易搞错。HEIC 本身就是有损的 HEVC 压缩,转成 PNG 不会把任何东西变回来,只是把当前状态定住,保证不再继续损失。如果你打算编辑,这仍然有意义。要分享的话,直接转成 JPEG 就完了,不必绕路。我们的 HEIC 转 JPGHEIC 转 PNGHEIC 转 WebP 转换器都在你的浏览器本地运行,文件不会离开你的设备。

矩阵里其他方向也是同一套逻辑。把 JPEG 放进无损编辑流程:JPG 转 PNG。把 PNG 截图压小了好上网:PNG 转 JPG;想更小又要保留透明,用 PNG 转 WebP。反方向,WebP 转 PNGWebP 转 JPG 找回与旧软件的兼容。手里是未压缩的 BMP 扫描件,BMP 转 JPGBMP 转 PNGBMP 转 WebP 一步给出同样的有损-无损选择。连渲染文档都会遇到同一个岔路口:把 PDF 页面导出成图,照片类页面选 PDF 转 JPG,文字必须保持锐利时选 PDF 转 PNG

三十年过去,活下来的格式都有一个共同点:它们清楚自己的用户,哪些数据丢得起,哪些一个比特都不能少。

更多推荐阅读