Skip to content
dsh.fish
Skill

remove-pdf-background-gray

Remove gray or off-white scan backgrounds from image-based PDF pages while preserving original image pixel dimensions, page geometry, and anti-aliased text edges. Use for requests such as PDF 去底灰, 扫描件底色变白, 去除纸张灰底, 保持原分辨率, or avoid jagged/binarized text in scanned PDFs.

Source
zjsthmjialin
stars
2 stars
License
MIT
Updated
Updated 13 days ago

Readme

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

[![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)

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

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

## DeepSeek Harness (DSH) 插件安装

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

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

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

- npm: https://www.npmjs.com/package/dsh-pdf-background-gray
- 插件源码:本仓库 `dsh-pdf-background-gray/` 目录

## 核心特点

- **保持原分辨率**:直接处理 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 目录:

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

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

```powershell
gh auth login
```

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

### 方法二:手动复制

把整个项目目录复制到:

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

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

## 在 Codex 中使用

可以显式调用 Skill:

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

也可以用自然语言触发:

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

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

## 直接运行脚本

### 环境要求

- Python 3.10 或更高版本
- `pypdf`
- `Pillow`
- `NumPy`

安装依赖:

```powershell
python -m pip install pypdf Pillow numpy
```

### 基本命令

在项目根目录运行:

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

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

### 调整参数

```powershell
python scripts/remove_pdf_background_gray.py `
  "C:\path\input.pdf" `
  "C:\path\output.pdf" `
  --low 235 `
  --white-point 250
```

| 参数 | 默认值 | 作用 |
| --- | ---: | --- |
| `--low` | `230` | 此值及以下保持不变;提高它可保护更多浅灰细节 |
| `--white-point` | `252` | 达到此值时映射为纯白;降低它会更积极地去除较深底灰 |

参数必须满足:

```text
0 <= low < white-point <= 255
```

调参建议:

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

## 技术原理

### 1. 直接处理嵌入图像

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

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

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

### 2. 只处理高光区间

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

映射使用 smoothstep 曲线:

```text
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 设计专门处理流程,不能简单忽略提示。

## 项目结构

```text
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。

## 联系作者

- Email:<zjsthm@gmail.com>

## 许可证

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

Install

# Skills are files: copy them into $DSH_HOME/skills/remove-pdf-background-gray (defaults to ~/.dsh/skills/remove-pdf-background-gray)

Profile: web

Source