图片压缩为什么放在浏览器里:Canvas 和 WASM 的取舍
· 2 分钟阅读
最省事的图片压缩写法是三行:createImageBitmap 解码、画到 canvas、canvas.toBlob('image/webp', 0.75)。我先按这个思路做了个原型,然后发现它和「专业压缩工具」差了不止一个档次。
Canvas 方案的短板
浏览器的 toBlob 用的是内置编码器,参数只有格式和质量两档。对照片来说,质量 0.75 的 WebP 通常能减 60%–80%,看着不错;但再往下压,细节会先糊成一片,而专业工具还能再省一半。
原因不在算法,而在编码器:浏览器给的是通用实现,而 mozjpeg、libwebp、oxipng 这些是专门为「同画质下更小体积」调过的。
换成 WASM 编码器
我用 jSquash 打包的三个编码器:
- mozjpeg 处理 JPEG,支持质量、渐进式等参数;
- libwebp 处理 WebP,且会自动检测 CPU 是否支持 SIMD,选更快的版本;
- oxipng 做 PNG 无损优化——不解码像素,直接重排压缩块。
三条路径都跑通后,实测(合成图,仅作量级参考):
| 用例 | 输入 | 输出 | 变化 |
|---|---|---|---|
| JPEG → JPEG | 342 KB | 136 KB | -60% |
| PNG → WebP | 1.7 MB | 24 KB | -99% |
| PNG → PNG(oxipng) | 1.3 MB | 476 KB | -65% |
一个容易被忽略的细节
PNG 走「无损优化」时,像素一个都不变,只是压缩方式更聪明。这对截图、图标、纯色块特别有效,而且没有画质损失的心理负担。所以工具里我把它设成默认:选 PNG 且不缩放时,直接走 oxipng,不经过 canvas。
代价是 WASM 体积:四个二进制加起来约 1 MB。但它们是按需加载的,用户不点压缩就一个字节都不下载。
经验
压缩不是「把质量调低」,而是「用对的编码器」。canvas 适合做缩略图和快速预览,真要交付体积,还是得请专业编码器上场。
