Skip to main content

RoaScan (roascan) — C++17 & ONNX Multi-Page OCR + MCP Server for AI Agents

RoaScan (roascan) is a local, CPU-first multi-page OCR and optical document restoration engine powered by a clean-room C++17 native core (roascan_core) and ONNX Runtime (PP-OCRv5 Latin / PP-OCRv4 English).

Designed as an Agent-First local OCR tool (Antigravity, Claude Code, Claude Desktop, Cursor, Windsurf, OpenHands) and document restoration library that runs on CPU without requiring GPU hardware, Tesseract, or Ghostscript.


Key Capabilities & Architectural Scope

  1. Multi-Page Scanned Input (Lazy Streaming & Disk-Spooling):
    • Native ingestion of multi-page .pdf (rasterized page-by-page on demand), .tiff/.tif, .png, .jpg, and .bmp.
    • In Markdown/text mode (set_retain_images(False)), page bitmaps are discarded immediately after recognition (0 bytes retained in engine._pages).
    • In Searchable PDF mode (set_retain_images(True)), restored page images are spooled as compressed PNGs to an exclusive temporary directory (_spool_dir) and automatically cleaned up on engine.close(), keeping 0 bytes of raw uncompressed bitmaps in engine._pages RAM.
  2. Dual High-Value Output:
    • Restored Searchable PDF (.pdf): Preserves physical page dimensions in PDF points (72 pt/inch, e.g. 595.28 x 841.89 pt for A4) and document-level metadata (title, author), applies C++17 Sauvola 64-bit integral background whitening, 1px anti-aliased ink preservation, coarse-to-fine deskew (0.1° precision), and orthogonal 90° / 180° / 270° orientation recovery with an invisible selectable text overlay (Ctrl+F).
    • Structured Semantic Markdown (.md): Automatic reconstruction of #/## titles via typographic font-height clustering, **Key:** Value pairs, multi-column reading order (XY-Cut), C++ morphological table grid-line removal, and GitHub-Flavored Markdown tables (|---|---|).
  3. Built-in Model Context Protocol (MCP) Server: Ready-to-run stdio JSON-RPC 2.0 server (roascan --mcp or roascan-mcp) exposing 4 validated tools (roascan_to_markdown, roascan_to_searchable_pdf, roascan_process_document, roascan_inspect_pdf).
  4. Spanish & Latin Diacritic Restoration: Built-in Hunspell lexicon with /G and /S affix expansion (ELECTRONICA -> ELECTRÓNICA, REPUBLICA -> REPÚBLICA, Pena -> Peña).

Measured Footprint & Reproducible Performance

Metric Measured Value (Intel Core i7-7700 4C/8T, Windows x64, Python 3.12)
RoaScan Wheel Artifact Size ~15.0 MiB compressed (~17.0 MiB unpacked, including C++ DLL + ONNX weights + Hunspell lexicon)
Full Runtime Environment ~223 MiB on disk when including onnxruntime, numpy, Pillow, and PyMuPDF in a clean virtual environment
C++17 Coarse-to-Fine Deskew Kernel ~0.90–1.96 ms (median ~1.03 ms) on synthetic 300 DPI A4 binary page (-15°..+15° at 0.1° step with spatial subsampling)
End-to-End Single-Page OCR ~230–720 ms in-process (ocr_elapsed_ms after ONNX session init; ~1.1 s total cold CLI invocation including interpreter & session startup)
30-Page A4 PDF Memory Profile 0 bytes of raw page bitmaps retained in engine.extract_pages() in both Markdown and Searchable PDF modes

Platform Verification Status

  • Windows x64 (win_amd64): Precompiled roascan_core.dll bundled in wheel (py3-none-win_amd64); verified end-to-end. Requires standard Microsoft Visual C++ Redistributable (MSVCP140.dll / VCRUNTIME140.dll).
  • Linux & macOS (Experimental Source Build): Native compilation, functional OCR, MCP, and wheel builds pass GitHub Actions on both platforms. Desktop integration remains unverified there. sdist includes full C++17 sources and CMakeLists.txt (roascan-native/). Building a wheel from source (pip install . or python -m build --wheel) automatically invokes cmake via setup.py to compile libroascan_core.so / libroascan_core.dylib (requires cmake >= 3.16 and a C++17 compiler).

Repository Structure

├── pyproject.toml             # PEP 621 package definition
├── setup.py                   # CMake native builder & platform-tagged wheel packager
├── MANIFEST.in                # Complete source distribution (sdist) manifest
├── LICENSE                    # Full Apache-2.0 License
├── NOTICE                     # Provenance, SHA-256 hashes, and licensing notices
├── THIRD_PARTY_LICENSES.txt   # Full license texts for bundled third-party resources (MPL-1.1 / Apache-2.0)
├── SKILL.md                   # AI Agent discovery & usage specification
├── mcp_config.json            # Ready-to-use Model Context Protocol (MCP) config
├── roascan/                   # Python SDK, CLI, MCP Server, bundled DLL & ONNX models
│   ├── api.py                 # Stable high-level API & Bridge Contract (`run_ocr`, `RoaScanResult`)
│   └── desktop/               # Desktop capture, interactive region crop & native clipboard
├── roascan-native/            # C++17 Native Core (`roascan_core`) & CMake build
├── dotnet/                    # Experimental C# / .NET P/Invoke preprocessing bridge (`RoaScan.cs`)
├── examples/                  # End-to-end Python usage examples
└── tests/                     # Automated pytest suite (`test_functional_ocr.py`, `test_desktop_and_api.py`)

Installation (pip install)

# 1. Core library + CLI + MCP Server:
pip install roascan

# 2. With desktop tray companion & global shortcut extra:
pip install "roascan[desktop]"

# Verify installation, native C++ core, and ONNX models:
roascan --doctor

1. Python API (roascan.run_ocr)

Stable bridge contract supporting file paths, PIL images, or raw image bytes without network dependencies:

import roascan

# Run local OCR with automatic language correction & Markdown reconstruction
result = roascan.run_ocr("factura.png", language="es")

# Standard bridge contract attributes:
print(result.text)          # Reconstructed plain text
print(result.markdown)      # Structured Markdown with tables & headings
print(len(result.words))    # Detected words with bboxes & confidences
print(result.confidences)   # List of word confidence scores

# Copy recognized text directly to the Windows clipboard:
result.copy_to_clipboard()

# Save structured Markdown:
result.save_markdown("factura.md")

# Access as dictionary mapping:
data = result.to_dict()

2. CLI Usage (roascan)

# 1. OCR a file and copy text directly to clipboard:
roascan ocr factura.png --out factura.md --copy

# 2. Interactive desktop region capture (Tkinter overlay -> OCR -> clipboard):
roascan clip

# 3. Capture specific coordinates without interactive prompt:
roascan clip --bbox 100,100,700,500 --out recorte.md

# 4. Convert a scanned multi-page PDF into both Searchable PDF and Markdown:
roascan scan.pdf --pdf limpio.pdf --md out.md --lang es

# 5. Output unified, versioned JSON (includes ocr_elapsed_ms and total elapsed_ms):
roascan factura.pdf --json

# 6. Run environment & model health check:
roascan --doctor

3. Desktop Screen Capture & Tray Companion (roascan.desktop)

RoaScan includes an offline desktop companion (clean-room design: zero cloud, zero accounts, zero telemetry):

3.1. System Tray Companion (roascan tray / roascan-tray)

Starts a lightweight background companion in the Windows notification area with a global shortcut:

  • Default Global Shortcut: Ctrl+Shift+O (triggers interactive region crop -> OCR -> copies text to clipboard).
  • Tray Menu: "OCR región" (triggers capture), "Salir" (clean shutdown).
  • Anti-Reentrancy Lock: Prevents overlapping captures if the shortcut is pressed repeatedly.
# Launch background system tray companion (default hotkey Ctrl+Shift+O):
roascan tray
# or
roascan-tray
# or
python -m roascan.desktop

# Custom hotkey or tray-only mode:
roascan tray --hotkey "Ctrl+Alt+O"
roascan tray --no-hotkey  # tray menu only
roascan tray --ui-lang en # English interface

Windows Hotkey Note: Global shortcuts registered via pynput run in normal user mode and do not require administrative privileges. However, when an elevated administrator window (UAC) has active focus, Windows restricts non-elevated global keyhooks. To change the shortcut permanently without CLI flags, use roascan config set hotkey "Ctrl+Alt+O" or set ROASCAN_HOTKEY="Ctrl+Alt+O".

3.2. Result Inspection & Editing Panel (P5)

When a region or clip is recognized, RoaScan automatically opens a lightweight, non-blocking result window:

  • Editable Text Area: Review, edit, or format the recognized text before saving or copying.
  • Copy: Places the currently edited text onto the system clipboard.
  • Save: Exports the text as structured Markdown (.md) or plain text (.txt) to the configured save_dir (default: ~/Documents/RoaScan).
  • Close / Escape: Dismisses the panel cleanly while keeping the background tray companion alive.
  • Single Instance: Triggering another OCR updates the active panel and brings it to the front rather than stacking multiple windows.
# Open interactive result panel directly from CLI clip:
roascan clip --panel

3.3. User Preferences & Localization (P6)

RoaScan stores user preferences in standard platform directories (%LOCALAPPDATA%/roascan/config.json on Windows or ~/.config/roascan/config.json on Linux/macOS via platformdirs).

CLI Configuration Management:

# View active configuration and defaults:
roascan config show

# Get the path to config.json:
roascan config path

# Change preferences:
roascan config set hotkey "Ctrl+Shift+O"
roascan config set ui_lang "en"         # "es" or "en"
roascan config set ocr_lang "es"        # "es", "en", "latin"
roascan config set show_result_panel true
roascan config set copy_on_success true
roascan config set save_dir "D:/MisDocumentos/OCR"

Precedence Order:

CLI Flags > Environment Variables (e.g. ROASCAN_HOTKEY, ROASCAN_UI_LANG) > config.json > Default Values.

3.4. Programmatic Desktop Capture, Panel & Clipboard API

from roascan.desktop import (
    capture_region_and_ocr,
    show_result_panel,
    copy_to_clipboard,
    get_clipboard_text,
    load_config,
)

# 1. Capture screen region -> local OCR -> show result editor:
result = capture_region_and_ocr(interactive=True, copy_clipboard=True, language="es")
if result and result.text:
    show_result_panel(result.text, blocking=True)

# 2. Read or write native Windows clipboard without external dependencies:
copy_to_clipboard("Texto copiado desde RoaScan")
print("Clipboard actual:", get_clipboard_text())

4. Model Context Protocol (MCP) Server

Start the MCP server over stdio:

roascan --mcp
# or
roascan-mcp

Claude Desktop / Cursor / Antigravity mcp_config.json:

{
  "mcpServers": {
    "roascan": {
      "command": "roascan-mcp",
      "args": [],
      "env": {
        "PYTHONIOENCODING": "utf-8"
      }
    }
  }
}

3. Licensing & Third-Party Notices

  • RoaScan Source Code (C++17 & Python): Licensed under the Apache License 2.0 (see LICENSE).
  • Bundled Neural Models (roascan/models/*.onnx, *_dict.txt): Derived from PaddleOCR under Apache License 2.0. Exact bundled SHA-256 checksums and an example paddle2onnx export command are documented in NOTICE.
  • Bundled Spanish Orthographic Dictionary (roascan/models/es_ES.dic): Unmodified plain-text dictionary from RLA-ES v2.8, distributed under the elected Mozilla Public License Version 1.1 (MPL-1.1) option (see NOTICE and THIRD_PARTY_LICENSES.txt).
  • Runtime Dependency PyMuPDF (fitz): Not bundled or redistributed in RoaScan packages; installed from PyPI at runtime under AGPL-3.0 (or commercial license from Artifex Software, Inc.). See NOTICE for compliance details.

Metadata

Release files for roascan 2.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for roascan 2.0.1
File Size Uploaded Provenance Actions
roascan-2.0.1.tar.gz 16.2 MB With provenance Details for roascan-2.0.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for roascan 2.0.1
File Interpreter ABI Platform Actions
roascan-2.0.1-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for roascan-2.0.1-py3-none-win_amd64.whl

Total release size: 32.0 MB

Release files / roascan-2.0.1.tar.gz

Download URL roascan-2.0.1.tar.gz
Size 16.2 MB
Tags Source
SHA-256 checksum
How to use checksums
9360880593a260cbe0e0d549de333ef14f0e78987db47eb3875a5ce562fb0a4b
BLAKE2b-256 checksum
How to use checksums
a65e7c0427b12bb2498831476a01e8a46f2032d82aefa378603afa8e6ebbb23f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Release files / roascan-2.0.1-py3-none-win_amd64.whl

Download URL roascan-2.0.1-py3-none-win_amd64.whl
Size 15.8 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
358e1c5c432aafcfcedbc760f6a84d8f8b0e711adf6b940d4b2b477bb17fcccb
BLAKE2b-256 checksum
How to use checksums
9b4e4b358399ef75258c1f163c261310ac74ea55185d1406af3c3f3832706641
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Security for roascan 2.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for roascan-2.0.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.0.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page