扫描件 PDF 去水印(白点压缩方案)
纯本地图像处理,无需 API 密钥,支持 Windows / macOS / Linux。
适用场景
- 扫描版 PDF:每页是一张图片(页面无文字层,pypdf
pg.images非空),水印/二维码/推广文字烤进图像像素里 - 用户要求去掉水印后打印使用(关键:先问用途!打印用白点压缩;屏幕观感用 inpainting 但需管理预期——水印压文字处会生成假笔画)
- 典型水印形态:浅灰大号斜排文字(如"XX在线",灰度 232~248)、第1页右上角二维码 + "扫码添加领取"推广文字
核心原理(为什么打印用白点压缩)
水印笔画是浅灰(232~248 灰阶),正文是深色(<200)。把 ≥TH(默认225) 的像素拉成纯白 255:
- 水印笔画整体变白消失;正文深色像素一个不动
- 无 AI 生成、无涂抹、无纹理痕迹——彻底绕开 inpainting 的"假字/花图"问题
- 附带:扫描纸面噪点(249~255)也统一成纯白,打印底色更干净
- 已知代价:正文抗锯齿过渡像素(225~240)变白 → 字边缘略细,打印无感
安装(一次性,任何机器通用)
# 1. 安装依赖(Python 3.9+)
pip install -r <技能目录>/requirements.txt
# Windows 可选 CPU 版 torch 加速(默认已含)
# pip install torch --index-url https://download.pytorch.org/whl/cpu
# 2. 下载 LaMa 权重(~205MB,用于第1页二维码修复;仅处理纯水印可跳过)
python <技能目录>/scripts/download_model.py
脚本会自动定位权重:环境变量 LAMA_MODEL → 技能目录/models/big-lama.pt → 找不到时提示下载。缺依赖时会输出友好安装指引。
工作流
第0步:先确认用途(必须问)
打印/存档/屏幕观感,决定方案:
- 打印 → 白点压缩(本技能主流程)
- 屏幕观感 → LaMa inpainting,并明确告知压字区会有假笔画风险,验收标准按"水印词消失+无花图"而非无损
第1步:判断水印类型(只读分析)
from pypdf import PdfReader
r = PdfReader(src)
for pg in r.pages: print(len(pg.images)) # >0 → 扫描件,走本流程
- 对象层水印(文字可选/可删)→ 用 Acrobat/WPS 删水印即可,不走本流程
第2步:白点压缩 + 第1页 LaMa 局部修复
主脚本 scripts/batch_whitepoint.py(批量,推荐):
python scripts/batch_whitepoint.py "<源目录>" "<输出目录>"
- 所有页:
np.where(a >= 225, 255, a)白点压缩 - 第1页:二维码(QR 检测)+ 推广文字(rapidocr 定位右上角 x>50%,y<40%)→ LaMa 局部修复深色块
- 输出
{原名}_打印版.pdf
单份脚本scripts/whitepoint_batch.py(指定单文件 + 输出路径)
第3步:验证(三件套)
python scripts/verify_batch.py "<输出目录>" 8 # 抽检 OCR 水印词
精确验证(对单份):
1. 水印笔画消除率:median 掩码 ∩ 原图 225~249 像素 → 处理后 ≥250 的比例,目标 100%
2. 带内正文保留率:median 掩码 ∩ 原图 <200 像素 → 处理后 == 原图的比例,目标 100%
3. OCR 水印词(梯方/在线/扫码/领取/金元宝 等)零命中
第4步:交付
- 副本输出到用户原目录(命名
{原名}_打印版.pdf),原文件一律不动 - 非工作区路径(如 W:/Z: 挂载盘)写入可能需要运行环境授权
- 汇报:份数、抽检结果、副本位置
脚本说明
| 脚本 | 用途 |
|---|---|
batch_whitepoint.py |
批量:目录下所有 PDF → _打印版.pdf |
whitepoint_batch.py |
单份:指定文件 → 指定输出 |
verify_batch.py |
抽检:OCR 水印词 |
download_model.py |
下载 LaMa 权重到 models/ |
_env.py |
公共:依赖检查 + 权重自动定位 |
踩坑记录(血泪,务必先读)
- rapidocr 返回的 boxes/txts 是 numpy 数组:
getattr(out,'boxes',None) or []会触发truth value ambiguous崩溃!必须[] if boxes is None else boxes - 部分环境(WorkBuddy 沙箱)Python 有"安全删除"钩子:脚本里
os.remove/os.rmdir可能报SAFE_DELETE_FAIL_CLOSED。处理:脚本内不删临时文件(PDF 在清理前已生成,不影响产物),tmp 目录用外部命令统一清 - torch C++ 层读不了中文路径:LaMa 权重(big-lama.pt)必须放在纯英文路径(技能目录 models/ 通常满足;若技能装在中文路径下,用环境变量
LAMA_MODEL指定英文路径的权重) - SimpleLama 返回 PIL Image(带 8px padding),需
.crop((0,0,W,H))裁回原尺寸 - 验证指标别用"均值差"——用"水印笔画消除率+带内正文保留率"这对(均值差好≠肉眼干净)
- 深色水印(<225 灰阶)白点压缩去不掉 → 只能 inpainting;水印压正文处白点压缩保留正文(最优),inpainting 会生成假笔画
已知边界
- 本技能专精"扫描件浅灰水印 + 打印用途":批量快(40 份约 8 分钟)、正文零损伤、无涂抹痕迹
- 不适用:深色水印、矢量/对象层水印、短视频平台水印(那是另一类技能)
- 每份第1页需 OCR 定位推广文字 + LaMa 修复(约 10-20s/份)