← 返回信息流
AI 资讯Hacker News·4 小时前

JPEG压缩新研究揭示退化问题

原标题:Regressive JPEGs

速览

一项新研究指出,标准JPEG压缩算法在特定条件下会导致图像质量退化,出现伪影和细节丢失。该问题可能影响广泛使用的图像存储和传输格式。研究团队提出了改进建议以缓解退化影响。

AI 深度解读

背景

JPEG 是最广泛使用的图像压缩格式之一,其标准定义了一种渐进式(progressive) 模式。与传统的基线(baseline)JPEG 不同,渐进式 JPEG 允许图像在下载过程中先呈现低分辨率预览,再逐步增加细节。这一特性依赖于将压缩数据拆分为多个“扫描(scan)”,每个扫描包含不同频率范围的 DCT 系数。Hacker News 上的一篇技术文章深入探讨了如何利用渐进式 JPEG 的扫描结构,在单个 JPEG 文件中嵌入多个不同图像,甚至实现类似视频的播放效果。

核心内容

JPEG 文件中的渐进式扫描通过特殊的标记(marker)进行组织。以一张代表性图像的第一扫描为例,其头部结构如下:

  • FF DA:扫描开始标记(Start of Scan)。
  • 00 0C:大端长度字段,值为 12 字节(包含自身)。
  • 03:本扫描中的颜色通道数(3 个)。
  • 0100:第一个通道的全局 ID 和对应的 Huffman 表索引(DC=0,AC=0)。
  • 0210:第二个通道的全局 ID 和 Huffman 表索引(DC=1,AC=0)。
  • 0310:第三个通道的全局 ID 和 Huffman 表索引(DC=0,AC=0)。
  • 0000:起始和结束的 DCT 频率 bin(此处仅为 DC 分量)。
  • 01:精度(半精度,无先前数据)。
  • 后续为 Huffman 编码的 DCT 系数。

该扫描仅包含所有三个颜色通道的最低频(DC 分量)。在 JPEG 中,颜色空间大致为:Y = 亮度(绿色相关),Cb = 蓝色减绿色,Cr = 红色减绿色。

文件的后续扫描(共九次)逐次填充剩余数据:

  • 扫描 0:极低分辨率预览。
  • 扫描 1:为亮度添加细节。
  • 扫描 2–5:包含完整的低精度数据(其中扫描 4 的频谱范围特殊,用于填补扫描 1 留下的缺口)。
  • 扫描 6–9:添加最后的缺失位,达到全质量。

由于每个扫描可以显式设置其频谱范围,理论上可以构造一个 JPEG 文件,让后续扫描覆盖已渲染的图像数据。实际上,实现这一点非常简单:将多个分辨率相同的图像文件拼接起来,并过滤掉每个文件中的 SOI(Start of Image)、SOF(Start of Frame)和 EOI(End of Image)标记。作者使用了一个快速 C 程序完成拼接,但也可用十六进制编辑器手动操作。

当通过慢速网络加载这个拼接文件时,浏览器会随着扫描的接收而切换显示不同的图像,形成类似动画的效果。然而,大多数解码器在扫描数量达到一定上限后会放弃进一步渲染。作者认为这种行为是为了避免 ZIP 炸弹式的问题,但也限制了该技巧只能用于 9 帧以内,不足以制作真正的动画。

为了增加帧数,需要最小化每帧的扫描数量。最简单的想法是使用基线 JPEG(仅含单个扫描),但行不通:在渐进模式下,一个扫描不能同时包含 AC(高于 0 的频率 bin)和 DC(bin 0)数据;基线模式没有这个限制,但基线解码器在第一个扫描后就停止处理。由于 AC 数据必须跟在 DC 数据之后,最小的“渐进式”JPEG 只能包含一个仅含 DC 的扫描。因为 DCT 基于 16×16 的块,这样的图像分辨率只有原始图像的 1/16(每个块只保留一个 DC 值)。

通过这种 DC-only 的渐进 JPEG,作者在 Chrome 中成功渲染了约 90 帧后浏览器才放弃。其他浏览器(如 Firefox)有更高的耐心,但 90 扫描的图像在几乎所有环境中都能正常工作。此外,这种方法避免了初版拼接尝试中的“鬼影”问题——原本的 AC 扫描会试图细化旧数据,导致图像过渡不自然。而 DC-only 扫描没有渐进性,因此不会出现该问题。

创建 DC-only 帧不需要特殊工具,只需使用标准 JPEG 工具 jpegtran 并指定扫描参数:

cat >frame.scans <<EOF
# DC only scan: 0,1,2:0-0,0,0; # and nothing else
EOF
jpegtran -scans frame.scans -outfile out.jpg in.jpg

利用这些技术,可以将一个完整的视频打包进单个 JPEG 图像中。除了恶搞(如 Rickroll)和捉弄人之外,这没有实际应用——因为无法添加时间信息,播放完全取决于网络延迟。不过,利用部分渲染进行创意展示仍很有趣。作者提供了一个纯 HTML 视频示例(使用 <dialog> 标签),地址为 badapple.rose.systems。此外,也可以动态生成数据,例如一个无需 CSS 或 JavaScript 的单页交互应用。

关键要点

  • 渐进式 JPEG 通过多个扫描逐步传输图像,每扫描包含不同频率范围的 DCT 系数,允许低分辨率预览后再细化。
  • 可以通过拼接多个 JPEG 文件并移除 SOI/SOF/EOI 标记,在单个文件中嵌入多个图像,利用网络加载顺序实现图像切换。
  • 大多数解码器对扫描数量有限制(通常 9 帧),原因是防止 ZIP 炸弹式攻击。
  • 使用基线 JPEG 单扫描无法实现多帧切换,因为基线模式只处理第一扫描;而渐进模式不允许单扫描同时包含 DC 和 AC。
  • 最小可行方案是使用仅含 DC 的渐进 JPEG(分辨率降为 1/16),这样可以将帧数提升至约 90 帧(Chrome)或更多。
  • DC-only 扫描避免了 AC 扫描带来的“鬼影”问题,因为不会有旧数据的细化。
  • 创建 DC-only 帧只需在 jpegtran 中指定扫描参数为仅 DC。
  • 这种方法没有实际应用价值(无时间控制,依赖网络延迟),但可用于恶搞和创意演示。
  • 相关代码:/projects/bad_jpeg/merge.c 用于生成拼接图像。

意义与影响

该技术探讨揭示了 JPEG 格式在标准之外的一些隐藏可能性,尤其凸显了渐进式扫描机制的灵活性。虽然“在 JPEG 中嵌入视频”更多是概念验证和趣味性演示,但它展示了图像格式底层数据结构如何被巧妙地重新利用。从技术角度看,这类技巧有助于加深对 JPEG 编码、扫描标记、解码器行为以及浏览器兼容性差异的理解。同时,它也提醒安全研究人员注意:大量扫描可能被用于构造特殊文件,触发解码器资源耗尽或意外行为(类似 ZIP 炸弹)。不过,在实用层面,由于缺乏时序控制,该技术不会取代真正的视频格式,更多是作为一种“魔法”式的恶搞手段存在于开发者社区中。

查看原文 →maurycyz.com