浏览器端为什么导不出渐进式JPEG

发布时间:2026/10/3 6:55:23
浏览器端为什么导不出渐进式JPEG 组里讨论首屏大图要不要换渐进式 JPEG 时有人问了一句很实在的话。既然渐进式能先糊后清为什么浏览器里压出来的 JPG 全是基线式我在图映 ImgIng 负责的就是端侧编解码这个问题落到我头上不奇怪。先把实测的部分摆出来。我在一台 Apple M4 / 16 GB 的 Mac 上用 Chromium 149 开源构建的 toBlob 按质量 0.85 导出一张图帧头是 SOF0。图映前几天测红字海报时留下的两份导出 JPG 帧头也是 SOF0。下面从编码这一侧拆原因实测和推测我分开写。canvas 能调的编码入口只有两个。HTMLCanvasElement 的 toBlob 收回调、类型和质量三个参数。OffscreenCanvas 的 convertToBlob 收一个对象规范里只给它定义了 type 和 quality 两个键。扫描方式、色度抽样、哈夫曼表这些编码器选项一个口子都没开。我不死心又拿网上找的那张稿定设计放假通知模板图在 Chromium 149 里多试了几种写法。给 convertToBlob 的对象加上 progressive: true 导出的还是 SOF0。换成 interlace: true 也一样。字节数和什么都不加时完全相同都是 754,479。给 toBlob 在质量后面再多传一个对象也还是这个数。多出来的键全被静默吞掉了控制台里连一条警告都没有。有一种写法会反过来坑人。把 { progressive: true } 直接放在 toBlob 的质量位上质量就被当成没给。导出来是 1,042,239 字节和显式写 0.92 的结果一字节不差。帧头照样是 SOF0。想开渐进式没开成文件反倒多了 287,760 字节。这种写法评审时很难看出来因为它不报错导出的图看着也正常。规范为什么不留这个开关我没找到明确的说法下面这段是我的推测。toBlob 的定位是把画布存成一张图。参数越少各家浏览器的输出越容易对齐。编码器选项一旦开放每家底下用的编码库都得支持同一组开关并且保证语义一致。渐进式本身的收益也撑不起这个成本。我在服务端用 Pillow 11.3 把两张网上找的图各编了基线式和渐进式两份。两边都开了 optimize。一张是 Wikimedia Commons 上的风景照缩到 2736×1824。另一张就是那张放假通知模板。在质量 75 和 85 两档下渐进式只小了 3.9% 到 6.3%。风景照质量 85 是 1,098,272 字节对 1,048,255 字节。解码反过来更贵。我同样在 Chromium 149 里用 createImageBitmap 各解 7 次取中位数风景照质量 85 的基线式要 11.1 ms渐进式要 28.3 ms。两张图两档质量一共四组渐进式的解码耗时都在基线式的约 2.3–2.6 倍之间。图映的 JPG 为什么走原生编码我能照实说的是架构上的一条。图映的编解码能力是按需加载的。用户真选到 AVIF 才去下 libavif 的 WASM。JPG 浏览器自己就能编走原生不用额外下载任何东西。要在端侧出渐进式就得另外打包一个 JPEG 编码器进来。为了 4% 到 6% 的体积让每个压 JPG 的人多下一份编码器我个人觉得不划算。这句只是我的判断不是产品已经定下的结论。我对照用的是图映 ImgInghttps://imging.cn/在同一台 M4 上导出的那两份海报 JPG两份都是 FF C0。网慢时先出整张模糊图这一点我只用解码器模拟过。只收到一半字节时渐进式已经接近原图基线式只画出了上半截。浏览器里首屏到底快了多少我没测到。真需要渐进式就放到服务端去转。上传链路里本来就有一步服务端处理的话就在那一步加上渐进式开关只给首屏那张大图用。转完读一下帧头确认是 FF C2 再上线。前端这边就别往 toBlob 里塞参数了塞了也不会生效。