Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

scry

SCRY Demo

πŸŽ₯ Video Tutorial

New to SCRY?

Watch the complete 2-minute walkthrough on YouTube: https://youtu.be/a3_iOsLBzW4

See beyond the pixels.

scry is a small Linux command-line utility that lets you drag-select a region of an image, runs OCR on it, and puts the extracted text on your clipboard β€” all from a single command.

python -m scry screenshot.png

Drag a box around some text, release the mouse, and the text is on your clipboard before you've had time to reach for it.


Features

  • Click-and-drag text selection from any image file, via a small Tkinter window
  • OCR via Tesseract, with automatic upscaling of small crops for better accuracy
  • Clipboard integration β€” extracted text is copied automatically
  • stdout output β€” extracted text is also printed, so scry composes with pipes and scripts
  • Desktop notifications on completion (optional, skippable)
  • Multi-language OCR support via Tesseract language codes (eng, eng+fra, etc.)
  • Clean, predictable exit codes for scripting
  • No configuration files, no background processes, no persistent state β€” scry does one thing per invocation and exits

What scry is not

To set expectations correctly: scry does not capture your screen (you give it an existing image file), does not do batch or multi-region selection, does not zoom or pan the selection window, and does not run as a background service. See Known Limitations for the full list.


Installation

scry is not yet published on PyPI. Install it from source:

git clone https://github.com/Nekoyazuma/scry.git
cd scry
pip install -e .

This installs scry's Python dependencies (Pillow, pytesseract, pyperclip) via pip. It does not install the system-level tools scry depends on β€” see below.

System dependencies

scry relies on a few system packages that aren't distributed through pip:

Tool Purpose Required?
tesseract-ocr (the tesseract binary) OCR engine Yes
Tkinter (python3-tk or equivalent) Selection window Yes
A clipboard tool (xclip for X11, wl-clipboard for Wayland) Copying extracted text Yes
notify-send (from libnotify) Desktop toast on completion No β€” scry works fine without it

Debian / Ubuntu / Kali:

sudo apt install tesseract-ocr python3-tk xclip libnotify-bin

(If you're on Wayland, swap xclip for wl-clipboard.)

Arch Linux:

sudo pacman -S tesseract tesseract-data-eng tk xclip libnotify

Fedora:

sudo dnf install tesseract python3-tkinter xclip libnotify

If a required tool is missing, scry tells you exactly which command to run for your distro instead of failing with a raw error β€” see Troubleshooting.

Python

scry requires Python 3.9 or later. There is no separate "Python installation" step beyond having Python and pip available β€” the pip install -e . command above pulls in scry's Python dependencies automatically.


Usage

The general form:

python -m scry <image> [options]

Run it against an image, then drag a box around the text you want:

python -m scry screenshot.png

A window opens showing the image. Click and drag to select a region; release the mouse to extract the text. Press Escape, or close the window, to cancel without extracting anything.

CLI options

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

Examples

Basic use:

python -m scry diagram.png

Extract French text:

python -m scry receipt.png --lang fra

Extract mixed English and French text:

python -m scry menu.png --lang eng+fra

Run without a desktop notification (useful in scripts or when calling scry repeatedly):

python -m scry screenshot.png --no-notify

See what's happening under the hood:

python -m scry screenshot.png -v      # INFO-level logging
python -m scry screenshot.png -vv     # DEBUG-level logging, incl. tracebacks on internal errors

Since the extracted text is also printed to stdout, scry composes with normal shell tools:

python -m scry error_dialog.png | grep -i "exception"
python -m scry note.png > extracted.txt

(stderr is reserved for logging and never mixes with the extracted text on stdout, so piping stdout is always safe.)


How scry works

Each run follows the same fixed 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)

A few specifics worth knowing:

  • Empty selections aren't errors. If you release the mouse without really dragging (a drag smaller than 4Γ—4 pixels), or press Escape, or close the window, scry exits quietly with exit code 1 β€” nothing is printed, copied, or notified.
  • "No text found" isn't an error either. If OCR runs successfully but finds nothing in your selection, scry still exits 0, prints an empty line, and shows a "No text found" notification instead of "Copied to clipboard".
  • The extracted text always reaches stdout, even if the clipboard copy itself fails β€” so you don't lose the result to a missing clipboard tool.
  • A failed clipboard copy never triggers a notification. You'll see the error on stderr instead, with instructions for fixing it.
  • A failed notification never fails the run. Desktop notifications are best-effort; if notify-send isn't installed, scry silently continues without one.

Exit codes

Code Meaning
0 Success (including "no text found")
1 Selection was cancelled by the user
2 The image path was missing, unreadable, or not a valid image
3 The OCR engine failed
4 No clipboard tool was available
5 An unexpected internal error occurred

Project philosophy

scry is built to stay small. A few rules the codebase follows throughout:

  • One job per run. No config files, no daemon, no persistent state between invocations.
  • Plain functions over classes. Most of scry's internals (crop(), ocr.extract_text(), clipboard.copy(), notify.send()) are single functions, not classes wrapped around a single implementation.
  • Abstractions are earned, not anticipated. The one exception is RegionSelector, an abstract base class β€” it already backs two real implementations (the real Tkinter window, and a fake used in tests), which is the actual bar scry uses before introducing an abstraction anywhere.
  • Every failure is either anticipated or a bug. scry defines a specific exception and exit code for every failure mode it expects (bad image, cancelled selection, OCR failure, clipboard failure). Anything else is treated as a genuine bug: it gets a full traceback (visible only with -vv), a clean one-line message on stderr, and exit code 5 β€” never a raw, unhandled traceback.

Testing

scry has unit test coverage across its modules β€” exception hierarchy, CLI parsing, image loading, region/crop math, the OCR and clipboard wrappers (with distro-specific error messages), and desktop notifications. GUI-driven code (the actual Tkinter window) is covered where its logic can be tested without a display; opening a real window is verified manually rather than in the automated suite.

Run the test suite:

pip install pytest
pytest -v

Some tests are conditional on your environment:

  • The OCR round-trip test only runs if tesseract is on your PATH (it's skipped otherwise).
  • Tests that touch the clipboard, OCR engine, or notifications mock those calls, so the full suite does not require tesseract, xclip, wl-clipboard, or notify-send to be installed to pass.

Known limitations

  • OCR accuracy depends entirely on Tesseract and your image/crop quality. Blurry screenshots, small text, low contrast, or unusual fonts will produce worse results β€” this is a property of the underlying OCR engine, not something scry can compensate for beyond the automatic upscaling it already applies to small crops.
  • No multi-monitor spanning. The selection window opens on whichever monitor your window manager treats as primary/default; scry does not detect or target a specific monitor.
  • No zoom or pan in the selection window β€” very large images are scaled down to fit your screen, and you select against that scaled view.
  • No post-drag adjustment. If your drag misses, you redo it; there are no resize handles.
  • Mouse-only selection. There is currently no keyboard-driven way to make a selection.
  • Single selection per run. scry extracts one region per invocation; there's no batch or multi-region mode.
  • Linux only. scry has been developed and tested on Linux (X11 and XWayland); it is not tested on Wayland-native clipboard tooling beyond what pyperclip/wl-clipboard support, and it does not target Windows or macOS.

Troubleshooting

"Tesseract is not installed. Install it with: ..." The tesseract binary isn't on your PATH. scry detects your distro and prints the exact command to install it β€” run the suggested command and try again.

"No clipboard tool available. Install it with: ..." Same idea, for the clipboard: scry detects whether you're on X11 or Wayland (via $WAYLAND_DISPLAY) and your distro, and prints the exact install command. Note that the extracted text still reaches stdout even when this happens β€” you don't lose it.

No desktop notification appears. If notify-send (from libnotify) isn't installed, this is expected and harmless β€” notifications are optional and fail silently by design. Run with -vv if you want to confirm this is what's happening (you'll see a DEBUG-level line noting the notification attempt was skipped).

"A required system dependency is missing: No module named 'tkinter'" python3-tk (or your distro's Tkinter package) isn't installed. Install it using the command for your distro under System dependencies above.

The window doesn't seem to open, or nothing happens. Make sure you have a working X11 or Wayland session β€” scry needs an actual display. Try running with -vv to see detailed logging on stderr as scry loads the image and opens the selection window.

I got "Image file not found" / "Not a valid image file". Double-check the path you passed, and that the file is actually a valid image scry's Pillow-based loader can decode. These messages mean scry successfully looked at the path β€” the problem is with what it found there.

I want more detail on what went wrong. Re-run with -vv. Default logging is quiet by design (stderr is otherwise clean unless something notable happens); -v adds INFO level detail, and -vv adds full DEBUG detail, including complete tracebacks for unexpected internal errors.


Contributing

scry is a small, deliberately minimal codebase. If you're interested in contributing, it's worth understanding the project's design philosophy first β€” see Project philosophy above. In short: contributions that keep scry small and add capability only where it's clearly needed are the best fit; contributions that add configuration surfaces, new abstractions, or speculative features ahead of an actual need are likely to be a harder sell.

Bug reports, fixes, and small, focused improvements are welcome via issues and pull requests.


License

scry is released under the MIT License.

Releases

Packages

Contributors

Languages