Nekoyazuma/scry

GitHub: Nekoyazuma/scry

scry 是一个 Linux 命令行 OCR 工具,通过拖拽选取图片区域并将识别结果自动复制到剪贴板与 stdout。

Stars: 2 | Forks: 0

# scry

SCRY Demo

## 🎥 视频教程 第一次接触 SCRY? 在 YouTube 上观看完整的 2 分钟演示: https://youtu.be/a3_iOsLBzW4 **看透像素之外。** scry 是一个小巧的 Linux 命令行工具,它允许你拖拽选择 图像的某个区域,对其运行 OCR,并将提取的文本放到你的 剪贴板上——所有操作只需一条命令。 ``` python -m scry screenshot.png ``` 在文本周围拖拽出一个选框,松开鼠标,提取的文本就已经 在你的剪贴板上了,让你连伸手去复制的时间都不用。 ## 功能 - 通过一个小型的 Tkinter 窗口,从任何图像文件中**点击并拖拽选择文本** - 通过 [Tesseract](https://github.com/tesseract-ocr/tesseract) 进行 **OCR**, 并对微小的裁剪区域进行自动放大以获得更好的准确率 - **剪贴板集成** —— 提取的文本会自动复制 - **stdout 输出** —— 提取的文本也会被打印出来,因此 scry 可以与 管道和脚本组合使用 - 完成时显示**桌面通知**(可选,可跳过) - 通过 Tesseract 语言代码支持**多语言 OCR** (`eng`、`eng+fra` 等) - 为脚本编排提供干净、可预测的退出代码 - 没有配置文件,没有后台进程,没有持久化状态 —— scry 每次调用只做一件事,然后退出 ## scry *不是*什么 为了设定正确的期望:scry 不会捕获你的屏幕(你需要 提供现有的图像文件),不会进行批量或多区域选择, 不会在选择窗口中进行缩放或平移,也不会作为 后台服务运行。完整列表请参阅[已知限制](#known-limitations)。 ## 安装说明 scry 尚未在 PyPI 上发布。请从源码安装: ``` git clone https://github.com/Nekoyazuma/scry.git cd scry pip install -e . ``` 这会通过 `pip` 安装 scry 的 Python 依赖(`Pillow`、`pytesseract`、 `pyperclip`)。它**不会**安装 scry 依赖的 系统级工具——请参阅下文。 ### 系统依赖 scry 依赖于一些不通过 `pip` 分发的系统软件包: | 工具 | 用途 | 是否必需? | |---|---|---| | `tesseract-ocr`(`tesseract` 二进制文件) | OCR 引擎 | 是 | | Tkinter(`python3-tk` 或同等包) | 选择窗口 | 是 | | 剪贴板工具(X11 使用 `xclip`,Wayland 使用 `wl-clipboard`) | 复制提取的文本 | 是 | | `notify-send`(来自 `libnotify`) | 完成时显示桌面通知 | 否 —— 没有它 scry 也能正常工作 | **Debian / Ubuntu / Kali:** ``` sudo apt install tesseract-ocr python3-tk xclip libnotify-bin ``` *(如果你使用的是 Wayland,请将 `xclip` 替换为 `wl-clipboard`。)* **Arch Linux:** ``` sudo pacman -S tesseract tesseract-data-eng tk xclip libnotify ``` **Fedora:** ``` sudo dnf install tesseract python3-tkinter xclip libnotify ``` 如果缺少必需的工具,scry 会准确地告诉你应该为你的发行版 运行哪条命令,而不是直接抛出原始错误——请参阅 [故障排除](#troubleshooting)。 ### Python scry 需要 **Python 3.9 或更高版本**。除了确保 Python 和 `pip` 可用外, 没有单独的“Python 安装”步骤——上述 `pip install -e .` 命令会自动拉取 scry 的 Python 依赖。 ## 用法 基本形式: ``` python -m scry [options] ``` 对图像运行它,然后在想要的文本周围拖拽出一个选框: ``` python -m scry screenshot.png ``` 打开一个显示图像的窗口。点击并拖拽以选择一个区域; 松开鼠标以提取文本。按下 **Escape** 或关闭窗口, 即可取消而不提取任何内容。 ### CLI 选项 ``` usage: scry [-h] [-l LANG] [-v] [--no-notify] [--version] image See beyond the pixels. Drag-select text from an image, straight to your clipboard. positional arguments: image Path to the image to select text from. options: -h, --help show this help message and exit -l LANG, --lang LANG Tesseract language code(s), e.g. 'eng' or 'eng+fra' (default: eng). -v, --verbose Increase log verbosity to stderr (-v for INFO, -vv for DEBUG). --no-notify Skip the desktop notification after copying. --version show program's version number and exit ``` ### 示例 基本用法: ``` python -m scry diagram.png ``` 提取法语文本: ``` python -m scry receipt.png --lang fra ``` 提取混合的英语和法语文本: ``` python -m scry menu.png --lang eng+fra ``` 运行而不显示桌面通知(在脚本中或重复 调用 scry 时很有用): ``` python -m scry screenshot.png --no-notify ``` 查看底层发生了什么: ``` python -m scry screenshot.png -v # INFO-level logging python -m scry screenshot.png -vv # DEBUG-level logging, incl. tracebacks on internal errors ``` 由于提取的文本也会打印到 stdout,scry 可以与 常规的 shell 工具组合使用: ``` python -m scry error_dialog.png | grep -i "exception" python -m scry note.png > extracted.txt ``` (stderr 专用于日志记录,永远不会与 stdout 上的 提取文本混杂在一起,因此通过管道传递 stdout 始终是安全的。) ## scry 的工作原理 每次运行都遵循相同的固定 pipeline: ``` load image | v select a region (drag in the Tk window) | v crop to that region | v run OCR (Tesseract, via pytesseract) | v copy the extracted text to the clipboard | v print the extracted text to stdout | v show a desktop notification (unless --no-notify) ``` 一些值得了解的细节: - **空选择不是错误。** 如果你在没有 真正拖拽的情况下松开鼠标(拖拽范围小于 4×4 像素),或者按下了 Escape,或者 关闭了窗口,scry 会以退出代码 `1` 静默退出——什么都不会 被打印、复制或通知。 - **“未找到文本”同样不是错误。** 如果 OCR 成功运行 但在你的选择中什么也没找到,scry 仍然会以 `0` 退出,打印一个 空行,并显示“未找到文本”通知,而不是 “已复制到剪贴板”。 - **提取的文本总是会到达 stdout**,即使剪贴板 复制本身失败也是如此——因此你不会因为缺少 剪贴板工具而丢失结果。 - **剪贴板复制失败永远不会触发通知。** 相反,你会 在 stderr 上看到错误信息,并附上修复说明。 - **通知发送失败永远不会导致运行失败。** 桌面通知是 尽力而为的;如果没有安装 `notify-send`,scry 会 静默继续执行而不发送通知。 ### 退出代码 | 代码 | 含义 | |---|---| | `0` | 成功(包括“未找到文本”) | | `1` | 选择被用户取消 | | `2` | 图像路径缺失、无法读取,或不是有效的图像 | | `3` | OCR 引擎失败 | | `4` | 没有可用的剪贴板工具 | | `5` | 发生意外的内部错误 | ## 项目理念 scry 的构建宗旨是保持小巧。代码库始终遵循以下 几条规则: - **每次运行只做一件事。** 没有配置文件,没有 daemon,调用之间 没有持久化状态。 - **使用普通函数而非类。** scry 的大部分内部实现 (`crop()`、`ocr.extract_text()`、`clipboard.copy()`、`notify.send()`) 都是单一的函数,而不是仅仅为了包装单一实现而存在的类。 - **抽象是争取来的,而不是凭空预期的。** 唯一的例外是 `RegionSelector`,一个抽象基类——它已经支持了两个真实的 实现(真实的 Tkinter 窗口,以及测试中使用的假实现), 这正是 scry 在任何地方引入抽象之前所采用的实际标准。 - **每一次失败要么是预期之内的,要么就是 Bug。** scry 为其预期的 每种失败模式(图像损坏、选择取消、OCR 失败、剪贴板失败) 都定义了特定的异常和退出代码。 其他任何情况都被视为真正的 Bug:它会提供完整的 traceback (仅在指定 `-vv` 时可见),在 stderr 上输出干净的单行消息,并且 退出代码为 `5`——永远不会抛出原始且未处理的 traceback。 ## 测试 scry 在其各个模块中都有单元测试覆盖——包括异常层级结构、 CLI 解析、图像加载、区域/裁剪计算、OCR 和剪贴板 封装(带有特定于发行版的错误消息),以及桌面 通知。GUI 驱动的代码(实际的 Tkinter 窗口)在 不需要显示器即可测试其逻辑的地方进行了覆盖;打开真实窗口的验证 是通过手动完成的,而不是在自动化测试套件中进行。 运行测试套件: ``` pip install pytest pytest -v ``` 有些测试会根据你的环境有条件地运行: - OCR 往返测试只有在 `tesseract` 位于你的 `PATH` 中时 才会运行(否则将被跳过)。 - 涉及剪贴板、OCR 引擎或通知的测试会 mock 这些调用,因此不需要安装 `tesseract`、`xclip`、 `wl-clipboard` 或 `notify-send` 即可通过完整的测试套件。 ## 已知限制 - **OCR 准确率完全取决于 Tesseract 以及你的图像/裁剪 质量。** 模糊的屏幕截图、微小的文本、低对比度或异常的 字体都会导致结果变差——这是 底层 OCR 引擎的特性,除了对微小裁剪区域 应用自动放大之外,scry 无法进行其他补偿。 - **不支持多显示器跨屏。** 选择窗口会在 你的窗口管理器视为主/默认显示器的那台显示器上打开;scry 不会检测或针对特定的显示器。 - **选择窗口中无法缩放或平移** —— 非常大的图像会被 缩小以适应你的屏幕,你需要针对该缩放后的 视图进行选择。 - **拖拽后无法进行调整。** 如果拖拽失误,你必须重来; 没有调整大小的手柄。 - **仅支持鼠标选择。** 目前没有任何基于键盘的 选择方式。 - **每次运行只能选择一次。** scry 每次调用 提取一个区域;没有批量或多区域模式。 - **仅支持 Linux。** scry 是在 Linux(X11 和 XWayland)上开发和测试的;除了 `pyperclip`/`wl-clipboard` 所支持的之外,它没有在 Wayland 原生剪贴板工具上进行过测试,也不支持 Windows 或 macOS。 ## 故障排除 **“Tesseract is not installed. Install it with: ...”** `tesseract` 二进制文件不在你的 `PATH` 中。scry 会检测你的发行版 并打印出确切的安装命令——运行建议的 命令然后重试。 **“No clipboard tool available. Install it with: ...”** 同样的思路,只不过是针对剪贴板的:scry 会检测你是在 X11 还是 Wayland 上(通过 `$WAYLAND_DISPLAY`)以及你的发行版,并打印出确切的 安装命令。请注意,即使 发生这种情况,提取的文本仍会到达 stdout——你不会丢失它。 **没有出现桌面通知。** 如果没有安装 `notify-send`(来自 `libnotify`),这是预期的, 并且无害——通知是可选的,根据设计会静默失败。 如果你想确认是否发生了这种情况,请使用 `-vv` 运行(你将 看到一条 `DEBUG` 级别的日志,指出通知尝试已被跳过)。 **“A required system dependency is missing: No module named 'tkinter'”** 未安装 `python3-tk`(或你发行版的 Tkinter 软件包)。请使用上面 [系统依赖](#system-dependencies)中对应你发行版的 命令进行安装。 **窗口似乎没有打开,或者什么也没发生。** 确保你有一个正常工作的 X11 或 Wayland 会话——scry 需要 一个真实的显示器。尝试使用 `-vv` 运行,以在 scry 加载图像并打开选择窗口时, 在 stderr 上查看详细的日志记录。 **我收到了“Image file not found” / “Not a valid image file”。** 仔细检查你传递的路径,以及该文件是否实际上是 scry 基于 Pillow 的加载器可以解码的有效图像。这些消息意味着 scry 已经成功查看了该路径——问题出在它 在那里找到的内容上。 **我想了解更多关于哪里出错的细节。** 使用 `-vv` 重新运行。默认的日志记录在设计上是静默的(除非 发生了值得注意的情况,否则 stderr 是干净的);`-v` 会增加 `INFO` 级别的 详细信息,而 `-vv` 会增加完整的 `DEBUG` 详细信息,包括针对意外内部错误的 完整 traceback。 ## 许可证 scry 采用 [MIT 许可证](LICENSE)发布。
标签:OCR, Python, Tesseract, 剪贴板, 文本提取, 无后门, 逆向工具