给 IOPaint 加了图像压缩功能,聊聊这个开源修图工具
最近花了点时间研究了一个叫 IOPaint 的开源项目,还顺手给它加了个图像压缩的功能。这篇文章记录一下这个工具本身,以及做了些什么。
IOPaint 是什么
IOPaint 是一个完全免费开源的 AI 图像编辑工具。简单说,你涂抹掉图片上不想要的东西,它用 AI 给你补上。水印、路人、杂物,涂掉就行。
底层用的是各种 SOTA 的 AI 模型:
- LaMA:快速擦除,处理普通物体/水印/缺陷
- Stable Diffusion inpainting:更智能的填充,适合复杂场景
- PowerPaint:不只是擦除,还能替换物体、扩展画布
- AnyText:在图上写字
架构很干净:FastAPI 后端 + React 前端,PyTorch 做推理,支持 CPU / CUDA / MPS。
项目在 GitHub 上 21k+ stars,社区活跃,持续更新。
为什么要折腾它
IOPaint 本身已经很能打了,但有个问题——输出的图片太大了。
它的默认质量是 95/100,而且保持原格式输出。如果你处理的是 PNG 原图,输出的 PNG 可能几 MB 甚至十几 MB。如果只是去个水印发个网页,完全没必要那么大。
所以我想加一个导出压缩的功能:让用户选择输出格式(JPEG / WebP / AVIF / PNG),控制质量,甚至无损压缩。处理完后直接拿到体积合适的文件,省掉「导出→再压缩」的步骤。
技术选型
核心是图像压缩库的选择。调研了几个方案:
| 方案 | 说明 |
|---|---|
| Pillow 原生 | IOPaint 已有,但 JPEG/WebP 压缩率一般 |
| Squoosh CLI | Google 出品,效果好,但得装 Node.js |
| imagecodecs | Python 库,封装了 mozjpeg/libwebp/libavif,一步到位 |
最终选了 imagecodecs。纯 Python 包,底层就是 Squoosh 用的那套 C 库(mozjpeg、libwebp、libaom),压缩效果完全一样。
就是有个坑:imagecodecs 的版本和 API 有点混乱。VERSION.txt 翻了好久才发现,imwrite(None, data) 不行,得用 jpeg_encode()、webp_encode() 这种函数。
如果你的环境里没有 imagecodecs,代码自动退回到 Pillow,不会报错。
前端改动
IOPaint 的前端是 React + Vite + shadcn/ui,代码写得不错,接入起来很顺畅。在设置面板里加了一个 Compress 标签页:
- 开关:启用/禁用压缩
- 格式选择:JPEG(兼容性最好)、WebP(平衡)、AVIF(最小体积)、PNG(无损)
- 质量滑块:1-100
- 无损开关:WebP/PNG 下可选
设置会持久化,保存在浏览器的 zustand store 里,下次打开还在。
部署体验
Docker 构建花了不少时间,主要是 PyTorch 太大了(2.2GB)。改成了多阶段构建:
- base 阶段:CUDA 12.1 + PyTorch 2.1.2 + imagecodecs
- frontend 阶段:Node 20 Alpine 编译前端 TypeScript
- final 阶段:合并后安装 IOPaint
镜像总大小约 4GB,主要是 PyTorch 和 CUDA runtime 占了绝大部分。
启动一条命令:
docker run -d --gpus all -p 8080:8080 --name iopaint iopaint:gpu-compress
RTX 3090 上推理一张 1080p 图片的 LaMA 擦除大约 200ms。
代码仓库
改动已推送到 GitHub: https://github.com/yinguobing/IOPaint
改了 10 个文件,新增 330 行。如果你想在本地跑,直接拉代码用 Docker 构建就行。
几点感想
- Python AI 工具的依赖管理是痛点。 一个 IOPaint 装下来几十个包,PyTorch + transformers + diffusers + gradio,哪个都不小。Docker 是唯一靠谱的交付方式。
- imagecodecs 是个好库,但文档太差。 好在源码可读,对着测试用例写调用比看文档快得多。
- 开源项目改起来比想象中舒服。 IOPaint 的代码结构清晰,前后端分离,插件体系完善,要扩展功能不需要大规模重构。
- AI 修图 + 压缩是一个很自然的组合。 处理图片的最终目的是使用,压缩应该是一站式体验的一部分,而不是额外步骤。
评论 ()