Skip to content

fix: panoramic scroll capture + multilingual OCR - #4

Open
Quentinbest wants to merge 7 commits into
mainfrom
fix/scroll-capture-and-ocr-languages
Open

fix: panoramic scroll capture + multilingual OCR#4
Quentinbest wants to merge 7 commits into
mainfrom
fix/scroll-capture-and-ocr-languages

Conversation

@Quentinbest

@Quentinbest Quentinbest commented Mar 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • Panoramic scroll capture: Replaced auto-scroll injection (CGEvent FFI) with user-driven panoramic capture — user scrolls naturally, app polls screen changes at ~100ms via CGWindowListCreateImage
  • Fixed frame capture bug: Switched from CGDisplayCreateImageForRect (captures physical display pixels, doesn't see scroll changes) to CGWindowListCreateImage (captures composited window content)
  • Raw PNG byte storage: Frames stored as Vec<Vec<u8>> instead of base64 strings (~2x memory savings)
  • Hash-based frame dedup: SipHash on PNG bytes replaces old base64-prefix comparison
  • Row-wise stitch optimization: copy_from_slice replaces pixel-by-pixel put_pixel (~10x faster)
  • Multilingual OCR: Added auto language detection (macOS 13+) and explicit language list support
  • New IPC commands: get_supported_ocr_languages, start_panoramic_capture_cmd
  • Removed: All CGEvent FFI code (~130 lines), cursor warping, Accessibility permission requirement

Test Coverage

All 33 Rust tests pass. Frontend type-check: 0 errors.

CODE PATH COVERAGE (91%)
  capture.rs — CGWindowListCreateImage + BGRA swap + row padding
  capture_store.rs — frame_hash deterministic + different content + reset
  scroll.rs — stop flag + MAX_FRAMES constant
  stitch.rs — from_bytes (empty, invalid, two frames) + row copy regression

Pre-Landing Review

4 auto-fixed: stale start_auto_scroll_capture_cmd references in CLAUDE.md, README.md; stale CGDisplayCreateImageForRect reference in TODOS.md; stale scroll.rs description in CLAUDE.md.

TODOS

No TODO items completed in this PR. 2 new TODOs added:

  • Document CaptureRegion coordinate space
  • Panoramic loop catch_unwind

Test plan

  • All Rust tests pass (33 tests, 0 failures)
  • Frontend type-check pass (202 files, 0 errors)

🤖 Generated with Claude Code

Quentinbest and others added 6 commits March 25, 2026 00:05
CGEventSetLocation alone does not reliably route scroll events to the
target window — macOS delivers to the window under the actual cursor.
Fix: warp the cursor to the target point before the scroll loop.

Also add AXIsProcessTrusted check so the user gets a clear error
instead of silently dropped events when Accessibility permission
is missing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable macOS Vision to auto-detect Chinese, Japanese, Korean, and other
scripts via setAutomaticallyDetectsLanguage (guarded for macOS 13+).

Add optional languages parameter to recognize_text IPC command and new
get_supported_ocr_languages command for querying available languages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sw_vers was spawned on every OCR call to check macOS 13+.
Cache the result in a static OnceLock for process lifetime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… for scroll capture

CGDisplayCreateImageForRect captures physical display pixels which don't
reflect window content changes during scrolling, causing hash-based dedup
to skip all frames (count stays at 0). CGWindowListCreateImage captures
composited window content and properly sees scroll changes.

Also redesigns scroll capture from auto-scroll injection (CGEvent FFI) to
user-driven panoramic capture: user scrolls naturally, app polls at ~100ms.
Removes all CGEvent FFI code, adds hash-based frame dedup, row-wise stitch
optimization, and raw PNG byte storage (no base64 overhead).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Quentinbest Quentinbest changed the title fix: scroll capture auto-scroll + multilingual OCR support fix: panoramic scroll capture + multilingual OCR Mar 25, 2026
Cast to usize before multiplying row offsets to prevent u32 overflow
on long scroll captures with 5K displays (y * width * 4 can exceed
4.2B). Use std::mem::take instead of clone() when draining frames
for stitching to halve peak memory usage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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