textsnap:在CPU上离线从图片、截图和网页中提取文字
textsnap 是一个单命令 Python 工具,使用量化 ONNX 模型从图片、截图和网页中提取纯文本——无需 GPU 或云端支持。
什么是 textsnap?
textsnap 是一个轻量级、离线的 OCR 工具,可将图片、截图和网页转换为纯文本——全部在 CPU 上运行,无需依赖云端。它使用量化的 0.9B PaddleOCR-VL-1.5 视觉语言模型(q4 ONNX)在标准笔记本电脑上解析完整页面。无需 CUDA,无需 M 系列专属技巧——只需普通的 CPU 核心。
为什么选择 textsnap?
大多数 OCR 工具要么需要 GPU,要么将数据发送到云端,要么设置繁琐。textsnap 解决了这三个问题:
- 在 CPU 上运行——模型量化为 q4 ONNX,使其在任何现代笔记本电脑上都能高效运行。
- 完全离线——首次运行后(约 890 MB 下载),所有内容都保留在本地。无需 API 密钥,无需配额,数据不会离开您的机器。
- 单命令——
pip install textsnap即可使用。该工具是一个单一的 Python 模块。 - 多种输入类型——剪贴板、本地图片文件、直接图片 URL 或完整网页 URL。
- Markdown 或纯文本输出——默认保留表格、标题和结构,或使用
--plaintext展平为纯文本。
快速开始
# 安装
pip install textsnap
# 提取内容
textsnap screenshot.png
textsnap https://example.com/article --plaintext
textsnap photo.jpg -o ~/notes/receipt.txt
首次运行会下载模型(约 890 MB)。之后每次运行都是离线的。
支持的内容来源
| 来源 | 示例 |
|---|---|
| 剪贴板 | textsnap(无参数) |
| 本地图片文件 | textsnap path/to/img.png |
| 直接图片 URL | textsnap https://example.com/x.png |
| 网页 URL | textsnap https://example.com/article |
本地文件支持 Pillow 能解码的任何格式:.png、.jpg、.jpeg、.webp、.bmp、.gif、.tiff 等。对于网页 URL,textsnap 使用 readability 提取主要内容,然后选择页面上最突出的图片进行 OCR。
安装
pip install textsnap
这会在您的 PATH 上安装两个等效命令:textsnap(标准名称)和 ocr(别名)。
从本地源代码安装:
pip install .
如需使用精确锁定的依赖版本进行可重现安装:
pip install -r requirements-lock.txt
pip install .
剪贴板说明: 从剪贴板读取图片依赖于 Pillow 的 ImageGrab。在 Linux 上可能需要安装 xclip 或 wl-clipboard。macOS 和 Windows 开箱即用。
使用方法
# 剪贴板(无参数)
textsnap
# 本地图片文件
textsnap path/to/screenshot.png
# 直接图片 URL
textsnap "https://example.com/diagram.png"
# 网页——OCR 页面上最突出的图片
textsnap "https://example.com/article"
# 将模型的 markdown 展平为纯文本
textsnap input.png --plaintext
# 自定义输出路径
textsnap input.png -o ./out/extracted.txt
# 为非常密集的页面提高 token 上限
textsnap dense-page.png --max-tokens 4096
# 使用本地模型目录而非下载
textsnap input.png --model-dir ~/models/paddleocr-vl
输出
输出为纯文本,UTF-8 编码。默认位置为当前工作目录下的 ./textsnaps/(如不存在则创建);可通过 -o 覆盖。文件名源自图片文件名主干(例如 receipt_ocr.txt),或 URL 输入的网页 slug。
textsnap 默认静默运行,遵循 Unix 风格:唯一打印到 stdout 的是写入文件的路径,因此可以干净地组合使用:
OUT=$(textsnap receipt.png) # 捕获路径
textsnap receipt.png | xargs cat # 打印识别出的文本
传递 -v 可将进度诊断信息(输入类型、图片大小、解码速度、token 数量)发送到 stderr;stdout 仍然只输出路径。
默认文件输出为模型的原生 markdown——它保留表格、标题和文档结构:
# 季度报告
| 地区 | 收入 |
| ------ | ------- |
| EMEA | $1.2M |
| APAC | $0.9M |
使用 --plaintext,markdown 被展平为纯文本:
季度报告
地区 收入
EMEA $1.2M
APAC $0.9M
参数
| 参数 | 描述 |
|---|---|
-o, --output |
输出 .txt 路径。默认:./textsnaps/<名称>_ocr.txt。 |
-v, --verbose |
将进度诊断信息打印到 stderr。默认关闭。 |
--plaintext |
将模型的原生 markdown 展平为纯文本。 |
--model-dir |
使用此目录中的 ONNX/配置文件,而非下载。 |
--max-tokens |
限制生成的 token 数量。默认 2048。对于非常密集的页面可提高此值。 |
--no-verify |
跳过下载模型文件的 SHA-256 验证(不推荐)。 |
--generate-checksums |
下载固定的模型文件,写入新的校验清单,然后退出。 |
安全性
textsnap 在首次运行时自动从 Hugging Face Hub 下载约 890 MB 的模型权重,因此它将这些文件视为不可信,直到验证通过:
- 固定模型版本。 下载固定到特定的仓库版本,因此移动或重新标记的
main无法静默替换权重。 - SHA-256 验证。 每个下载的文件在加载前都会进行哈希计算并与已知正确的摘要进行比对。不匹配会以清晰的错误信息中止运行,而不是执行未经验证的权重。摘要存储在
model_checksums.sha256中,并作为后备嵌入到脚本中,因此无论您是从源代码还是从 wheel 安装,验证都能正常工作。 - 固定依赖项。
requirements-lock.txt固定了精确的依赖版本以实现可重现安装;该文件记录了如何使用pip-compile --generate-hashes添加每个 wheel 的--hash条目,以实现完整的供应链固定。
在有意提升模型版本后重新生成校验清单:
textsnap --generate-checksums
要绕过验证(用于本地实验修改后的模型),请传递 --no-verify。
工作原理
- 加载。 从剪贴板、本地文件、直接图片 URL 或——对于网页 URL——页面主要内容中最突出的图片(通过 readability 和突出度启发式算法)。
- 预处理。 图片最长边限制为 640px,然后通过 PaddleOCR-VL 的 Qwen2-VL 风格智能调整大小和分块处理,生成视觉编码器期望的像素值张量和网格。
- 识别。 三个 ONNX 组件在 CPU 上运行:视觉编码器(q4)、token 嵌入模型(fp32)和自回归解码器(q4),带有预连接的 KV 缓存。贪婪解码,带有重复防护机制,可提前停止失控循环。
- 格式化。 默认输出原生 markdown;
--plaintext将其简化为纯文本。
没有图片被发送到任何地方。除缓存的模型外,运行之间不保留任何状态。
模型与缓存
PaddleOCR-VL-1.5 ONNX 组件在首次运行时下载到 ~/.cache/textsnap/:
onnx/vision_encoder_q4.onnx——视觉编码器 + 空间合并投影器onnx/decoder_q4.onnx——自回归解码器onnx/embedding.onnx——token 嵌入(fp32;不存在 q4 变体)tokenizer.json、config.json
总共约 890 MB。要使用您自己的副本,请将 --model-dir 指向包含相同 onnx/ 文件以及 tokenizer.json 和 config.json 的目录。
注意事项与限制
- 首次运行较慢——它会下载约 890 MB。之后,textsnap 完全离线。
- CPU 解码是顺序的。 密集的整页文档比短截图需要更长时间。textsnap 将线程数固定到您的物理核心数,并打印实时 tokens/sec 读数,以便慢速运行时能明显看到活动状态,而非卡死。
--max-tokens限制输出。 非常密集的页面可能会达到默认的 2048 token 上限并被截断;如果页面尾部缺失,请提高此值。- 网页输入仅 OCR 一张图片——主要内容中最突出的那张,而非整个渲染页面。
- 贪婪解码有时会在重复布局上循环;内置防护机制会检测并修剪这些情况。
许可证
本项目采用 MIT 许可证。模型为 PaddleOCR-VL-1.5,由 PaddlePaddle 以 Apache-2.0 许可证分发;textsnap 从 onnx-community/PaddleOCR-VL-1.5-ONNX 拉取 ONNX 导出。由 onnxruntime 和 huggingface_hub 提供支持。