ARTICLE · 1192444
不装软件、不上传文件:一个纯前端 OFD 工具箱,把转换、校验、发票抽取全塞进了浏览器
关键词:OFD、Golang、WebAssembly、WASM、电子发票、版式文档、纯前端
一、先说个熟悉的场景
同事甩给你一个 .ofd 文件——发票、合同、电子证照,现在越来越多是这种格式。你双击,打不开;想转成 PDF 发给客户,搜到的工具要么让你先注册账号,要么让你上传到它的服务器再下载。
发票里有税号、金额、开票方,合同里有公章和签署信息。这些东西你敢往陌生网站上贴吗?
装个桌面软件?体积大、平台挑、升级烦,而且多数只做"转 PDF"一件事。想校验一下文件结构、看看到底有哪些资源、批量把几十张发票的金额汇总出来——基本没有顺手的工具。
今天聊的这个开源项目就是冲这些痛点来的:zc310/ofd-toolbox——一个用 Go 编译成 WebAssembly 的纯前端 OFD 工具箱。文件不上传,没有服务端,也没有账号,打开网页就能用。
项目地址:https://github.com/zc310/ofd-toolbox
在线使用:https://zc310.github.io/ofd-toolbox/
二、它到底是什么
一句话概括:
把一整套 OFD 文档处理能力,编译成一个 WebAssembly 模块,放进浏览器里跑。所有文件的理解与改写都在你这台机器上完成。
底层能力来自 zc310/ofd 这个 Go 工具包,ofd-toolbox 负责把它包成浏览器能用的形态:WASM 构建、Worker 调度、流式产物传输、Service Worker 缓存和界面。
界面一共 7 个工具 Tab:
| 转换 | |
| 校验 | |
| 分析 | |
| 发票 | |
| 水印 | |
| 合并 | |
| 长期保存 |
输入格式(浏览器里能直接用的):OFD、PDF、PNG、JPG、TIFF、Markdown。
三、最有价值的点:文件真的不上传
市面上的在线转换工具,绝大多数是"上传 → 服务器处理 → 下载"。这对普通文档无所谓,但 OFD 常常是发票、合同、证照——恰恰是最不该外传的那类文件。
ofd-toolbox 的架构从根上避免了这个问题:
能力来自 Go 工具包,编译成 一个 .wasm模块;模块在浏览器 Worker 里运行,计算全在本机; 没有后端接口,没有文件上传这一步; 首次加载后由 Service Worker 缓存,之后离线也能用。
你可以在开发者工具的 Network 面板里盯着看:处理过程中除了加载静态资源,没有任何数据离开这台设备。
四、工程上几个"不显眼但很关键"的决定
一个纯前端工具最难的不是"能跑",而是大文件不卡死、错误不炸库、行为不骗人。这个项目在这几件事上做了不少取舍,很值得记载。
1. WASM 跑在 Worker 里,主线程始终能交互
模块有 50MB 量级。如果装载和计算都在主线程,页面会长时间不可交互——进度条卡住、取消按钮点不动、滚动条卡死。
所以整个引擎跑在 Web Worker 里,主线程只负责界面。进度、取消、产物分块全部走消息传递。
2. 产物分块下发,Worker 内部确认(ACK)
WASM 回调给出一块产物,写进接收端后立刻确认,下一块才生成。
这不是优化,是保命:少了确认,中间产物会堆在 WASM 内存里,50MB 的模块再加一份未落盘的产物,足以让浏览器直接杀掉标签页。
ACK 特意不经过主线程——主线程此时无事可做,绕一圈只会多一次消息投递延迟。
3. 命令边界统一兜 panic
第三方库里最容易崩的地方是"找不到系统字体"(font.FindSystemFonts 在无字体目录的环境里解引用 nil)。这类错误不是 error 而是直接 panic,调用方写不了 if err != nil。
不在边界上兜住的话,一次 panic 就终止整个 WASM 实例:已打开的文档、缓存的报告、正在跑的任务一起丢失,只能整页刷新。
所以在每个导出的 JS 命令外面套了一层 safe(),把 panic 变成一条正常的错误结果。
4. Service Worker 缓存名由内容哈希算出
页面的 HTML、JS 与 WASM 必然同版本,不会出现"新 JS 调旧 WASM"。代价是换版要用户点一次刷新——新的 Service Worker 只在下次打开时接管,因此界面上有一条"已有新版本"的提示。
5. 字体只取本机或用户上传的文件,不联网
浏览器里没有系统字体目录。OFD 没内嵌字体时,中文会变成方块。工具允许你选本机字体或上传字体文件兜底,候选列表还会标出哪些能补齐文档缺字、哪些已注册。
6. 界面不硬编码任何格式名或参数名
转换 Tab 的格式卡片、参数面板显隐,校验 Tab 的可选项,全部由 WASM 侧的 capabilities 清单驱动。库侧增删格式时界面自动跟随,不需要两处同步。
五、几个"把用户当成年人"的细节
用过一堆工具的经验是:真正拉开差距的往往是错误信息和小开关的设计。这个项目有几处很"较真":
发票金额用十进制字符串,绝不当数字传。1130.00 一旦变成数字 1130 再转回文本,就少了小数位——财务对账场景下这是事故。所以金额走 Decimal 类型,序列化成字符串。
合并默认保留签名。 加水印会改动页面内容、签名摘要随即失效。库的零值默认是删掉签名条目——对"给已签章的合同加机密水印"这种需求,静默删掉签名痕迹是不可接受的。所以工具默认改成"保留",并把警告透传给界面。
长期保存拆成两步走。 预检(Plan)只读、算出计划改动;执行(Apply)才写文件。其中一类动作是不可逆的删除,让用户先看到"会发生什么"再决定,比执行完再解释好。
生成汇总页需要一个中文字体,没有就不让生成。 而不是让它生成一页空白——空白页比报错难发现得多,用户会以为汇总就是空的。
内存诊断区分"堆"和"线性内存"。 WASM 线性内存只增不减,这是浏览器引擎的固有行为,不该被当成泄漏。所以诊断面板会明确告诉你:Go 存活堆高才说明文档太大、确实该关。
六、自己跑一遍
在仓库根目录执行:
make build-wasmpython3 -m http.server 8080 --directory cmd/toolbox-wasm/web然后打开 http://localhost:8080。注意浏览器不能通过 file:// 加载 WASM,必须走 HTTP 服务。
make build-wasm 做三件事:编译 toolbox.wasm、按需用 wasm-opt 优化、从 GOROOT 复制 wasm_exec.js,最后按各资源的内容哈希重算 service-worker.js 里的缓存名。找不到 wasm-opt 时会告警并改用未优化版本,不让构建直接失败。
目录结构也很干净:
cmd/toolbox-wasm/├── *.go WASM 侧命令,每个文件带 //go:build js && wasm└── web/ 页面资源(无框架、无构建步骤,直接就是浏览器要的东西) ├── index.html 单页,7 个工具 Tab ├── app.js 主线程:界面、状态、Worker 消息 ├── worker.js Worker:WASM 装载、命令分发、流式产物接收 └── toolbox.wasm 构建产物,50MB 量级,不入库没有前端框架,没有打包步骤——页面资源就是浏览器最终要加载的东西,少了一层工具链的复杂度。
七、已知边界(作者自己写清楚的)
一个项目愿意把"做不到什么"写在显眼位置,是成熟的表现:
- Office 与 HTML 输入不可用。
docx/odt/rtf/wps/pptx/xlsx 和 html/mhtml 依赖 LibreOffice 或 Chrome 命令行,浏览器里没有。界面仍然接受这些文件并说明缺什么,免得用户只能在失败之后才明白原因。 - 校验与分析报告不提供 XLSX 与 PDF。
PDF 报告要嵌入中文字体,而浏览器里没有系统字体目录。两者可导出 JSON / Markdown / 纯文本。发票报表不受此限。 - WASM 有 63MB。
发票 XLSX 导出要引入 excelize,单独贡献约 12.6MB。首次加载要下载整个模块,之后由 Service Worker 缓存。 - OFD 支持范围以
zc310/ofd的文档为准,不同厂商的 OFD 存在扩展差异。
八、适合谁?
✅ 适合:
手里有 OFD,需要在不上传的前提下转成 PDF / 图片 / Word / Markdown 需要校验 OFD 包结构、排查引用关系与签名问题 财务、审计要把成批的增值税电子发票金额汇总出来,导出成 Excel 要给合同、文档批量加水印,或把多份 OFD 合并成一份 做数字档案,需要按 GB/T 42133 做长期保存预检与处理 想找一个"打开即用、不留痕迹"的在线工具
❌ 不适合:
需要处理 Office / HTML → OFD(浏览器里缺 LibreOffice/Chrome) 需要 OCR(图片转 OFD 不含文字层) 对电子签名的法律有效性做最终认定(工具不保证合规结论,签章有效性需用 OFD 阅读器另行核验)
九、最后说点判断
OFD 是国标版式文档格式,在电子发票、电子证照、政务档案这些场景里越来越普及。但"打开它、看懂它、改对它"的工具生态一直不算友好——要么要装臃肿的桌面软件,要么被迫把敏感文件传上云端。
ofd-toolbox 提供了一条第三条路:
用 WebAssembly 把完整的处理能力搬到本机浏览器里,既能干重活(互转、校验、发票汇总、水印、合并、长期保存),又不需要上传、不需要安装、不需要账号。
它的工程完整度也超出"玩具 demo":Worker 隔离、分块 ACK 背压、panic 边界、内容哈希缓存、capabilities 驱动的界面、两步式不可逆操作、连财务对账的小数位都想到了。
更难得的是边界写得诚实:做不到的、体积大的、需要外部工具的,全部摆在明面上。技术选型里最怕的不是能力有限,而是踩坑后才知道边界在哪。
如果你经常和 OFD 打交道,这个工具值得收藏进浏览器书签。
项目地址:https://github.com/zc310/ofd-toolbox
在线体验:https://zc310.github.io/ofd-toolbox/
📌 留言区聊聊:你平时打开和转换 OFD,最烦的是"装软件"、"格式转不出来",还是"敏感文件不敢上传"?















































































