Passer au contenu principal
Z

pdf-background-gray-codex-skill

zjsthmjialin/pdf-background-gray-codex-skill

Enregistre la skill remove-pdf-background-gray pour DSH : blanchit les fonds de scan gris ou cassés des PDF imagés tout en préservant la résolution, la géométrie des pages et les bords de texte anticrénelés (réécriture Flate sans perte), via un unique script Python (pypdf + Pillow + numpy).

Installer

dsh plugin --profile web add github:zjsthmjialin/pdf-background-gray-codex-skill

README

PDF 去底灰(原分辨率)Codex Skill

Awesome DSH Plugin

remove-pdf-background-gray 是一个用于扫描型 PDF 的 Codex Skill。它可以去除纸张扫描产生的灰底或偏白底色,同时保持页面尺寸、嵌入图像的原始像素尺寸和文字的连续抗锯齿边缘。

这个项目既可以作为 Codex Skill 自动调用,也可以直接运行其中的 Python 脚本。

DeepSeek Harness (DSH) 插件安装

remove-pdf-background-gray 也是 DeepSeek Harness (DSH) 插件,一条命令安装:

dsh plugin --profile web add dsh-pdf-background-gray

重启 DSH Web 后,向 Agent 说"把这份扫描 PDF 去底灰"即自动走技能工作流(要求本机 Python 3.10+ 与 python -m pip install pypdf Pillow numpy)。

核心特点

  • 保持原分辨率:直接处理 PDF 内嵌图像,不缩放图像。
  • 不整页重绘:不先把 PDF 页面渲染成新图片再重新组装。
  • 保护文字边缘:使用连续的高光映射,不使用容易产生锯齿的硬阈值或黑白二值化。
  • 无损写回:处理后的图像使用 Flate 无损压缩写回 PDF,避免再次 JPEG 压缩文字边缘。
  • 内置验证:输出后检查页数、页面框和嵌入图像像素尺寸是否改变。
  • 安全中止:遇到内联图像或透明蒙版时停止处理,避免悄悄破坏复杂页面。

适用范围

适合以下情况:

  • 扫描书籍、档案、讲义或合同的纸张底色发灰。
  • 希望背景变白,但不希望文字被二值化或出现明显锯齿。
  • 需要保持原始 DPI、图像宽高和 PDF 页面尺寸。
  • PDF 页面主要由 JPEG、灰度图或 RGB 扫描图组成。

不建议直接用于:

  • 以矢量文字、复杂插画或透明图层为主的 PDF。
  • 灰色本身就是内容的一部分,例如铅笔画、浅灰表格、医学影像或艺术作品。
  • 需要极致压缩体积,而不是优先保证文字边缘质量的场景。
  • 带有透明蒙版、内联图像或特殊色彩空间且尚未人工检查的文件。

处理前建议使用 pdfinfo、pdffonts 和 pdfimages -list 检查 PDF 结构,并先对一页代表性内容做测试。

已验证效果

本 Skill 最初用于处理一份真实扫描 PDF,验证结果如下:

项目结果
PDF 页数194 页
处理的独立图像对象713 个
页面数量处理前后相同
页面尺寸与页面框处理前后相同
嵌入图像像素尺寸处理前后相同
文字边缘保留连续灰阶抗锯齿,未做黑白二值化
原文件大小48,838,427 字节,约 46.6 MiB
输出文件大小174,219,856 字节,约 166.1 MiB

背景灰度在代表页中主要集中于约 252。默认参数保持灰度 230 及以下不变,并将 230 到 252 的高光区域平滑过渡到纯白。

文件体积增大是预期结果:原 PDF 的扫描图像主要使用有损 JPEG 压缩,而处理后为了避免再次损伤文字边缘,改用 Flate 无损压缩。不同 PDF 的体积变化会有明显差异。

上述结果来自一个具体文件,不代表所有 PDF 都会获得相同的视觉效果或体积变化。处理重要资料前请保留原文件并抽查输出。

在 Codex 中安装

方法一:通过 Git 克隆

将仓库克隆到 Codex 的个人 Skills 目录:

git clone https://github.com/zjsthmjialin/pdf-background-gray-codex-skill.git `
  "$HOME\.codex\skills\remove-pdf-background-gray"

如果仓库为私有状态,需要先配置 GitHub 凭据或使用 GitHub CLI 登录:

gh auth login

安装完成后重启 Codex,使新 Skill 被自动发现。

方法二:手动复制

把整个项目目录复制到:

%USERPROFILE%\.codex\skills\remove-pdf-background-gray

最终结构中应直接包含 SKILL.md,不要多嵌套一层目录。

在 Codex 中使用

可以显式调用 Skill:

使用 $remove-pdf-background-gray 处理 C:\path\input.pdf,去掉扫描底灰,保持原分辨率和文字抗锯齿。

也可以用自然语言触发:

把这个扫描 PDF 的页面底色去除,保持原分辨率不变,文字不要出现锯齿,只去底灰。

Codex 应先检查 PDF 类型和代表页,再调用脚本生成新文件并验证输出。

直接运行脚本

环境要求

  • Python 3.10 或更高版本
  • pypdf
  • Pillow
  • NumPy

安装依赖:

python -m pip install pypdf Pillow numpy

基本命令

在项目根目录运行:

python scripts/remove_pdf_background_gray.py `
  "C:\path\input.pdf" `
  "C:\path\output.pdf"

输入和输出路径必须不同。脚本不会覆盖原文件。

调整参数

python scripts/remove_pdf_background_gray.py `
  "C:\path\input.pdf" `
  "C:\path\output.pdf" `
  --low 235 `
  --white-point 250
参数默认值作用
--low230此值及以下保持不变;提高它可保护更多浅灰细节
--white-point252达到此值时映射为纯白;降低它会更积极地去除较深底灰

参数必须满足:

0 <= low < white-point <= 255

调参建议:

  • 背景仍然偏灰:逐步降低 --white-point,每次调整 2 到 5。
  • 浅灰线条或细节变淡:提高 --low,或提高 --white-point。
  • 先用单页样本测试,不要直接对唯一原件批量处理。

技术原理

1. 直接处理嵌入图像

脚本使用 pypdf 读取 PDF,并定位每页引用的图像 XObject。共享的图像对象只处理一次,然后替换原对象的数据流。

这种方式不会把整页重新渲染,因此可以保留:

  • PDF 页面的物理尺寸和页面框。
  • 每个扫描图块的原始像素宽高。
  • 原有页面排版和图像定位关系。

2. 只处理高光区间

默认情况下,灰度值 230 及以下完全不变。只对 230 到 252 之间的高光区域计算调整量。

映射使用 smoothstep 曲线:

t = clamp((value - low) / (white_point - low), 0, 1)
smooth = t * t * (3 - 2 * t)
result = value + (255 - value) * smooth

这条曲线在区间两端连续且变化平缓。与“超过某个值就直接变白”的硬阈值相比,它不会突然切断文字边缘的浅灰过渡。

对于 RGB 图像,脚本只处理接近中性灰的高光像素;通道差异较大的彩色像素不会被当作纸张灰底处理。

3. 无损写回

处理后的像素使用 /FlateDecode 写回 PDF:

  • 灰度图使用 /DeviceGray。
  • RGB 图使用 /DeviceRGB。
  • 每通道保持 8 bit。
  • 图像宽高保持不变。

Flate 是无损压缩,因此不会引入新的 JPEG 方块、振铃或文字边缘模糊。但对于扫描图像,它通常比 JPEG 占用更多空间。

4. 输出验证

脚本写出 PDF 后会重新打开文件,并检查:

  1. 页数是否一致。
  2. 每页 MediaBox 是否一致。
  3. 所有嵌入图像的像素宽高是否一致。

任何一项不一致都会抛出错误,而不是把未验证的文件当作成功结果。

制作过程

这个 Skill 来源于一次实际的 PDF 修复任务,主要步骤如下:

  1. 使用 pdfinfo 确认文件共有 194 页并读取页面尺寸。
  2. 使用 pdffonts 确认文件中没有字体对象,判断文字来自扫描图像。
  3. 使用 pdfimages -list 检查图像尺寸、DPI、颜色空间和压缩方式。
  4. 渲染代表页,观察纸张底色和文字边缘。
  5. 统计代表图块的灰度分布,确认背景主要集中在约 252。
  6. 放弃整页重新栅格化和硬阈值二值化方案。
  7. 采用直接替换图像对象、连续高光映射和 Flate 无损压缩。
  8. 对全部 194 页和 713 个独立图像对象执行处理。
  9. 核对页数、页面框和图像像素尺寸,并抽查前段、中段和末页渲染结果。
  10. 将可复用流程封装为脚本和 Codex Skill,并用官方 Skill 校验器检查目录结构。

验证建议

即使脚本内置结构验证,仍建议进行视觉检查:

  1. 用 pdfinfo 比较输入和输出的页数、页面尺寸。
  2. 用 pdfimages -list 抽查图像宽高和 DPI。
  3. 渲染首页、正文页、中间页和末页。
  4. 在 200% 到 400% 缩放下检查文字笔画边缘。
  5. 检查浅灰表格线、印章、插图和页面污渍是否被误处理。
  6. 确认输出可以被常用 PDF 阅读器完整打开。

安全机制与限制

  • 发现内联图像时,脚本会中止,因为当前实现不能安全地替换它们。
  • 发现 /SMask 或 /Mask 透明蒙版时,脚本会中止,避免破坏透明关系。
  • 非 L 或 RGB 图像会转换为 RGB,特殊印刷色空间需要额外检查。
  • 脚本不执行 OCR,也不会创建可搜索文字层。
  • 脚本不会自动判断所有浅灰内容究竟是纸张背景还是有效信息。
  • 输出使用无损压缩,文件可能明显增大。
  • 当前实现依赖 pypdf 的部分内部对象接口;升级依赖后应重新运行样本测试。

常见问题

输出背景仍然偏灰

适当降低 --white-point。建议小步调整,并检查浅灰细节是否仍然完整。

浅灰表格线变淡

提高 --low 或 --white-point,缩小被调整的高光范围。如果浅灰线与纸张底色亮度接近,自动处理无法完全区分两者。

输出文件变大

这是无损 Flate 替代有损 JPEG 后的常见结果。项目优先保证处理后的像素不再经历一次有损压缩。

提示没有找到嵌入图像

该 PDF 可能主要由矢量内容构成,或采用了当前脚本未支持的图像组织方式。不要强行处理,应先检查 PDF 结构。

提示存在透明蒙版或内联图像

这是保护性中止。需要为该类 PDF 设计专门处理流程,不能简单忽略提示。

项目结构

remove-pdf-background-gray/
├─ SKILL.md
├─ README.md
├─ agents/
│  └─ openai.yaml
├─ scripts/
│  └─ remove_pdf_background_gray.py
└─ docs/
   └─ superpowers/
      ├─ specs/
      │  └─ 2026-06-18-readme-design.md
      └─ plans/
         └─ 2026-06-18-readme-implementation-plan.md
  • SKILL.md:Codex 的触发条件、工作流程和安全约束。
  • agents/openai.yaml:Skill 在 Codex 界面中的名称、简介和默认提示词。
  • scripts/remove_pdf_background_gray.py:确定性的 PDF 图像处理和验证脚本。
  • README.md:面向使用者和开发者的项目说明。

贡献与反馈

欢迎提交 Issue 或 Pull Request。反馈问题时,建议提供以下信息:

  • Python、pypdf、Pillow 和 NumPy 版本。
  • PDF 页数、是否含字体对象及 pdfimages -list 摘要。
  • 使用的 --low 与 --white-point 参数。
  • 可以公开的最小复现样本,或脱敏后的代表页。
  • 预期效果和实际效果的具体差异。

请勿上传包含个人隐私、合同机密或版权受限内容的原始 PDF。

联系作者

许可证

当前仓库尚未提供许可证文件。在明确添加许可证之前,代码默认保留全部权利;公开使用、修改或再分发前请先联系作者确认授权范围。

Plugins associés