JPEG XL 这个格式的处境相当尴尬。Chrome 在 2021 年曾经通过 flag 支持过它,2022 年又悄悄撤掉了;Firefox 只在 Nightly 版本里保留;Safari 倒是原生支持。结果就是:一个 .jxl 文件,在你某个浏览器里是能打开的图片,换到另一个浏览器(或操作系统)里,系统只会给你一个“无法识别”的耸肩。 这种状态很烦人,因为真的会有人手里攒下这种文件。部分相机和手机导出管线会生成 .jxl,凡是走过“把我的照片库重新编码一遍”这条路的人,手里多少都有一文件夹这样的文件。然后他们在一台非 Mac 机器上试图打开其中一个,毫无反应。 我想要的是一个完全在浏览器里运行的查看器——不传文件到服务器,不碰用户数据。这一点对我来说没有商量余地:你要看自己的照片,就不该先把它们 POST 给一个陌生人。所以解码器只能是 WASM。 接下来是我实际踩过的坑,包括它在生产环境直接崩掉的那一回。 最顺手的起点是 @jsquash/jxl。它是 libjxl 的一个封装好的 WASM 构建,确实能跑。我先用它上线了。 然后有个 Reddit 网友拿了一张 22.4 兆像素的文件来试,结果报错: ``` RuntimeError: index out of bounds at toWireType ``` 这个报错信息毫无帮助。实际上编码器在 1200 万到 1600 万像素之间的某个点就死了——低于这个范围没事,高于就崩。WASM 堆理论上能涨到 2GB,但它远没到那个值就倒了,所以也不能靠简单的“调大内存”来解决。 就算没崩,速度也拉胯。一张 1200 万像素的图,在 effort 7 档下要跑 21 秒。没人会等 21 秒。 于是,我决定自己构建 libjxl。 标准的 emscripten 环境搭建: ```bash git clone --depth 1 https://github.com/emscripten-core/emsdk.git cd emsdk && ./emsdk install latest && ./emsdk activate latest git clone --depth 1 --recurse-submodules --shallow-submodules https://github.com/libjxl/libjxl.git ``` cmake 的调用方式才是所有关键决策所在:启用哪些编码器、是否开启 SIMD、线程模型怎么映射到 WASM,还有到底要不要把解码和编码放在同一个二进制里,这些都直接决定最终产物体积和运行时表现。折腾到最后,我自己编译的版本不仅越过了 22.4 兆像素的崩溃阈值,速度也远比现成封装包稳定。至于那些 cmake 参数的取舍细节,足够再开一篇单独讲了。

打开网易新闻 查看精彩图片