一个被沿用了很久的架构假设
把图片拖进网页工具,几秒后拿到压缩结果——这个交互背后,多数实现是把文件上传到服务端处理,再把结果传回来。
这个选择在早期 Web 是合理的。浏览器既没有高性能的编解码能力,也缺少稳定的本地文件写入通道,把计算放到服务端是当时唯一可行的路径。问题在于,这个由能力限制推导出的工程决策,后来被当成了"网页工具"这个形态的固有属性沿用下来,很少被重新审视。
本地处理链路由哪些环节组成
File / Blob 对象
→ 解码(原生解码器 或 WASM 解码器)
→ 像素处理(Canvas 2D / OffscreenCanvas / WebGL / WebGPU)
→ 编码(原生编码器 或 WASM 编码器)
→ 本地保存(下载 或 File System Access)
值得强调的是,这条链路上每一环都是独立能力,不能相互推断。这一点后面会再展开。
三类执行路径解决的不是同一个问题
浏览器原生 API。 JPEG、PNG、WebP 的解码与编码大多可由浏览器直接完成,无额外下载、启动快,成本最低。代价是覆盖的格式集合有限,而且不同浏览器的实现并不一致。
WebAssembly。 这是变化最大的一环。当浏览器原生不具备某项编解码能力时,可以用 WASM 把成熟的 C/C++ 编解码库编译进页面来补足——libwebp、libavif、libheif 这类在服务端和桌面端已经验证多年的开源项目,由此获得了在浏览器里直接运行的可能。代价是模块体积与加载时间,因此适合按需加载而非全量预置。
WebGPU 与 GPU 加速。 神经网络推理和大规模像素运算需要并行算力。WebGPU 可用时性能显著优于 CPU 路径,但它依赖安全上下文(HTTPS 或 localhost),部分场景还需要跨源隔离。不可用时必须有 WASM 后端兜底,否则功能直接失效。
为什么"支持某浏览器"不足以判断能否完成任务
-
一个常见的工程错误,是按浏览器型号或 UA 字符串决定功能开关。实际上以下能力彼此独立:
-
能否读取某种输入格式
-
能否把画面正确绘制到画布
-
能否编码成目标格式
-
能否加载多线程 WASM
-
能否启用 WebGPU
-
能否直接写入本地文件
-
"能读"不等于"能写"。典型例子是 HEIC:读取可以通过 WASM 补足,但浏览器本地写出并不总是可行。按型号做判断,结果往往是界面显示支持、执行时才失败。
-
可行的做法是把判断挪到运行时:先验证输入能否被真实解码、目标格式能否被真实编码,再检查 WASM 编解码器可否加载、推理所需后端是否就绪、安全上下文与文件保存能力是否满足,最后结合设备内存、像素规模与帧数决定执行路径。国内的图映(imging.cn)在其图片工作台中采用的就是这一思路——用运行时能力探测替代型号判断,让能力边界可以被界面直接解释给用户,而不是在执行中途报错。
按需加载不是优化项,是前提
AVIF 编码、HEIC 解码、AI 抠图、视频人像分割、PDF 处理,这些能力的资源体量差异很大。如果一次性装入,一个只想压缩单张 PNG 的用户也要承担全部下载与内存成本。
必须讲清楚的边界
本地优先不等于全部本地,这一点决定了一个技术方案是否诚实。
对技术读者而言,一个讲清楚边界的方案,比一句无法验证的口号更值得信任。
开发者可以自己验证
-
开发者工具网络面板。 处理过程中观察是否存在图片体积级别的上行请求。模型与编解码器的下载是拉取静态资源(下行),与上传原图是两回事。
-
断网测试。 首次加载完所需模块后断开网络,再执行一次同类任务。能完成,说明该任务确实跑在本地。
这两个方法对任何同类工具都适用。
对 Web 应用架构的意义
这件事的意义不止于图片工具。开源编解码库经 WASM 进入浏览器,加上 WebGPU 提供的并行算力,实际上把一类原本默认属于服务端的计算重新变成了可选项。随之改变的是几个默认假设:数据是否必须离开设备、算力成本由谁承担、离线是否可用。
对开发者来说,需要跟着调整的是判断方式——从"这个功能能不能做",变成"在这个具体运行环境里,这条链路的每一环是否都成立"。能力检测因此从边缘细节变成了架构的一部分。
技术与许可说明:WebP 能力可能使用浏览器原生实现或 libwebp WASM;AVIF 写出使用 libavif 相关 WASM 能力;HEIC 读取使用 libheif 相关 WASM 能力;浏览器 AI 推理可使用 WebGPU 或 WASM 后端。