1. Regressive JPEGs (maurycyz.com)
渐进式JPEG允许先保存低频分量,使未完全下载的图像可以低分辨率整体呈现,而非局部截断。文件将压缩数据拆分为多个扫描(scan),每个扫描前带头部,注明所含通道、霍夫曼表索引、DCT系数起始与结束频带,以及精度模式。
以文中示例的首个扫描为例,它包含全部三个颜色通道(YCbCr)的直流分量(DC,即DCT 0号频带),精度减半。JPEG使用YCbCr色彩空间,亮度通道(Y)需要保留较多细节,色度通道(Cb、Cr)则可大幅压缩;加之色度通常以半分辨率记录,数据量反而更小。后续扫描依次补充Y的中高频细节、Cb与Cr的剩余频带等,直至恢复完整画质。其中扫描4的频谱范围特意填补扫描1留下的空缺,以便扫描5能在完整的低精度数据上继续精修。
文章的核心发现是:由于每个扫描都显式设定自身频谱范围,后续扫描可以覆盖先前已渲染的图像数据。实现方式是将多幅同分辨率图像拼接,并剔除中间多余的图像开始(SOI)、帧开始(SOF)和图像结束(EOI)标记。这样在慢速网络传输时,浏览器逐段解码会在不同内容间切换,形成类似动画的效果。
但大多数解码器为防止 zip bomb 攻击,会在一定数量扫描后停止,通常只能渲染约9帧,不足以构成连续动画。若尝试改用基线JPEG的单扫描来减少扫描数,基线解码器会在第一帧后停止;而渐进模式不允许单个扫描同时包含DC与AC系数。因此最小可行的“渐进”单元只能是仅含DC分量的单扫描。按文中说法,DCT以16×16块运行,纯DC帧分辨率约为原图的1/16,但已能独立构成一副标准合规的图像。
仅使用DC扫描还有一个好处:由于不存在用于精修旧数据的AC扫描,不会产生此前实验中的残影问题。在Chrome中可渲染约90帧后才放弃,Firefox等浏览器容忍度更高,90扫描的图像几乎可在所有环境中正常显示。借助 jpegtran 及如下扫描描述即可生成此类DC-only帧:
0,1,2:0-0,0,0;
将大量仅含DC的帧合并进同一个JPEG文件,就能把整段视频封装在单张“图片”内。然而这并无实际用途:JPEG扫描没有时序信息,画面切换完全取决于网络延迟。作者展示了切换的猫图、黑猫行走等演示,还据此制作了仅用HTML <dialog>标签的“纯HTML视频”,以及不依赖CSS或JavaScript的单页交互应用。相关生成代码见 merge.c。