缘起
它起于一个很具体的观察:内网办公的人压图,靠的是系统自带的「画图」——缩到 50% 再另存,压完要么糊了、要么还是超。
这种电脑上,装软件要审批,文件出不去,在线压缩网站第一步就打不开。而真实需求非常具体:系统只收 5MB 的附件,扫描件一动 40MB。市面上没有一个现成工具是为这个环境做的。
所以做的东西也很具体:一个装进去就能用、全程不联网、把原图保护好的批量压图工具。
背景
目标用户不是设计师也不是程序员,是单位里要交材料的人。这决定了两件事:
参数得替用户做掉。「质量 75」「DPI」「色彩空间」这些词对目标用户没有意义,他们心里只有一个数——系统限的 5MB。所以产品形态是「填一个想要的体积,工具自己想办法压到那个数」,中间的工程决策(二分找最高达标质量、PNG 没有质量旋钮只能缩尺寸、压得太狠要提醒)全部沉到实现里。
**信任要靠如实报告攒。**内网装一个软件有成本,装完发现「悄悄把图压糊了」就再也不用了。所以每一张图发生了什么都有交代:重新保存了几张、哪几张压到了屏幕清晰度、哪几张不支持、哪几张本来就很省空间——不支持的就明说不支持,不悄悄跳过。
方案
**三条图片规则,选着用。**压到指定体积、限制宽高上限、转成哪种格式——三条可以单用也可以同用;体积与尺寸冲突时体积优先。文件夹直接拖进去,递归扫描、按路径去重,默认双 worker 并行。
**PDF 免规则,拖进去就压。**内嵌 JPEG 按质量 75 重存、满页扫描图压到 150 DPI 屏幕清晰度、再做无损结构优化;文字和矢量内容字节级不动。加密的、带签名的直接拒绝——改了签名就失效,这种忙不能帮。这套纯 Go 实现的完整决策过程写在了博客长文《不引 Ghostscript:我用纯 Go 给 PDF 做了一场「压缩手术」里。
**原图零写入。**处理结果先进应用内暂存区,原图所在的文件夹一个字节都不动;点「下载」才保存到用户选的文件夹,先写临时文件再原子落位,失败不留半成品。这是第一版直接写回原图旁边、被真实使用者纠正之后改的——隐性约束不是一次想全的,是踩出来的。
**界面说人话。**用户可见文案有一张术语表当单一真相:「压到了屏幕清晰度」而不是「降采样」、「不支持的图片类型」而不是「JBIG2/CCITT」、已经满足设置的图叫「无需处理」而不是「已达标跳过」。Go 侧返回的提示与前端界面同表取词,改词先改表。
技术架构
| 模块 | 技术选型 |
|---|---|
| 桌面运行时 | Wails v2(Go 后端 + Vue3 前端),hash 路由适配打包形态 |
| 后端 | Go 1.26 + GORM + SQLite(纯 Go 驱动,无 CGO) |
| 图像处理 | 标准库 + golang.org/x/image,目标体积两层搜索(二分质量 + 平方根缩尺寸) |
| PDF 压缩 | pdfcpu 做解析回写底座,图像重压缩对象级自研(质量 75、仅更小才替换、150 DPI 降采样) |
| 工程化 | Makefile 统一入口 + 架构护栏 + 依赖登记制 + OpenSpec 变更治理 |
| 交付 | macOS dmg / Windows NSIS / 麒麟 deb,CI 三平台打包并附 SHA256SUMS |
几个值得说的做法:
- 编解码全纯 Go:不引任何需要外部编译器的图像依赖,同一套代码交叉出三平台(含信创 arm64)安装包,麒麟构建钉死 Ubuntu 20.04 容器对齐 glibc 2.31。
- 约定编译成会红的检查:仓库里有 1802 行护栏测试——前后端契约常量双向核对、日志/事件/版本注入这类「漏了不报错」的接线逐条验证、依赖必须登记、分层纪律强制。任何靠解析源码做断言的护栏,解析到 0 个目标必须报错,防止护栏自己失效了还亮绿灯。
- 版本号四处同源:
wails.json是唯一真相,构建时渲染进安装包与二进制,护栏核对一致性。 - 图标资产单源派生:
build/*.svg是唯一源,make icon派生全部平台图标并登记哈希,派生物不许手改。
成果
- 已发版:v0.2.0 打 tag 自动构建三平台安装包与校验和,GitHub Release 可下载;从第一个提交到交付 0.1.0 用了两周,PDF 压缩作为 0.2.0 的主体功能补齐。
- 质量可数:功能代码约 4400 行,测试与护栏约 6200 行(其中护栏 1802 行);10 份架构决策记录;PDF 压缩 spike 实测整文件 -42.9%、渲染像素差 0.41/765(肉眼不可辨)。
- 自用与家人使用中:家里交材料的活儿现在都走它。没有对外推广,没有用户数可以报,这一栏不填好看的假数字。
体验
源码在 github.com/Benny66/file-processor,Release 页有三平台安装包;没有网页版 demo,桌面工具想用起来就是装一个。
想验两件事的话:
- 拖一个 300 DPI 的扫描件 PDF 进去,点开始。结果消息会写「重新保存了 x 张图片,其中 y 张压到了屏幕清晰度」——体积通常能掉一个数量级。
- 把压好的文件再拖进去跑一遍。这一遍会全部显示「已经很省空间」,一个字节都不会再动——逐张「仅更小才替换」的意义就在这。
