Skip to content

(feat): Add “Copy text from screen” OCR action - #333

Merged
devmobasa merged 3 commits into
mainfrom
feat/ocr-copy-text-from-screen
Aug 12, 2026
Merged

(feat): Add “Copy text from screen” OCR action#333
devmobasa merged 3 commits into
mainfrom
feat/ocr-copy-text-from-screen

Conversation

@devmobasa

Copy link
Copy Markdown
Owner

Summary

Add an opt-in screen-region OCR action that recognizes text locally with Tesseract and copies it to the clipboard.

  • Select regions with pointer, touch, or stylus, including frozen and zoomed screen sources.
  • Run PNG encoding, recognition, and clipboard publication off the Wayland event loop.
  • Keep recognized text out of application state and logs; only privacy-safe outcomes reach the UI.
  • Expose the action through the command palette, configurable keybindings, and an optional toolbar button.
  • Add language configuration, configurator support, documentation, and optional package dependencies.
  • Keep OCR hidden for existing and new configurations unless explicitly enabled.

The implementation also extracts shared screen-image geometry used by OCR and the eyedropper, and prevents callback-thread launchers from stalling behind long broker operations.

Adds `Copy text from screen`: drag a region of the desktop image Wayscriber is
already displaying, recognize its text with a local Tesseract, and put the
result on the clipboard. It is a one-shot action rather than a drawing tool, so
the active tool, the drawing history, boards, and sessions are all untouched.

The region is cropped from the frozen or zoomed capture the renderer is showing,
never from annotations or Wayscriber chrome, and a freeze OCR creates is a
freeze OCR releases — a user-owned freeze or an active zoom survives untouched.
Recognition runs off the event loop through a capacity-one controller; a second
request reports busy rather than queueing a region the user has moved on from.

Recognized text never reaches application state, a log line, or a `Debug`
rendering: the worker owns encoding, the engine call, and the clipboard write in
one stack frame, and only a character count comes back.

Two shared seams come out of this rather than being copied:

- `state/screen_image.rs` now owns displayed-source resolution, the checked
  logical-to-image mapping, and the rectangle crop, for the eyedropper, the
  canvas renderer, and OCR alike.
- `clipboard_text.rs` holds the generic `wl-copy`/`wl-paste` commands that used
  to live in the color-picker module.

Input ownership is explicit throughout. A region records the device that started
it, so a hovering pen cannot drag a mouse-owned selection and a stray release
cannot submit one. Both screen-region modals now share one keyboard boundary
(engaged, including the capture wait) and one pen boundary (active, once the
selector is on screen), and a pen already down when a modal opens is disowned
until it lifts so it cannot resize the drawing tool behind the selector.

Discoverability is opt-in: the action is in the command palette and the
keybinding configurator with no default shortcut, since `O` is already the
orange quick color, and the `top.utility.ocr` toolbar button ships hidden like
Screenshot. `capture.ocr_languages` validates the Tesseract language argument
so an authored value can never carry a path, an option, or shell syntax into the
argument vector; the engine is invoked through the process broker under a new
`HelperKind::Tesseract` allowlist with an explicit argument vector and a
self-deleting temporary PNG.

Tesseract is packaged as an optional dependency (optdepends on Arch, recommends
on deb/rpm) because the feature is opt-in at every level.

Also fixes a latent bug in `ToolbarItemsConfig::set_visibility_setting`, which
rewrote an item to the end of its list even when the setting was unchanged. It
was invisible while only one item was hidden by default; a second one made a
batch reset report "changed" forever.
The gate built and tested that configuration but never linted it, so code
reachable only behind an optional feature could leave its callers dead without
it and still pass. Building alone does not promote that to an error.

Caught exactly that during OCR work: a predicate used only from `tablet-input`
code was dead in the default build, and only a manual clippy run found it.

Passes clean today, so it is a free tripwire.
@devmobasa
devmobasa merged commit 0439c75 into main Aug 12, 2026
2 checks passed
@devmobasa
devmobasa deleted the feat/ocr-copy-text-from-screen branch August 12, 2026 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant