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
- 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 bytesretained inengine._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 onengine.close(), keeping0 bytesof raw uncompressed bitmaps inengine._pagesRAM.
- Native ingestion of multi-page
- 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 ptfor 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 orthogonal90° / 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:** Valuepairs, multi-column reading order (XY-Cut), C++ morphological table grid-line removal, and GitHub-Flavored Markdown tables (|---|---|).
- Restored Searchable PDF (
- Built-in Model Context Protocol (MCP) Server: Ready-to-run stdio JSON-RPC 2.0 server (
roascan --mcporroascan-mcp) exposing 4 validated tools (roascan_to_markdown,roascan_to_searchable_pdf,roascan_process_document,roascan_inspect_pdf). - Spanish & Latin Diacritic Restoration: Built-in Hunspell lexicon with
/Gand/Saffix 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): Precompiledroascan_core.dllbundled 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.
sdistincludes full C++17 sources andCMakeLists.txt(roascan-native/). Building a wheel from source (pip install .orpython -m build --wheel) automatically invokescmakeviasetup.pyto compilelibroascan_core.so/libroascan_core.dylib(requirescmake >= 3.16and 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
pynputrun 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, useroascan config set hotkey "Ctrl+Alt+O"or setROASCAN_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 configuredsave_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 examplepaddle2onnxexport command are documented inNOTICE. - 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 (seeNOTICEandTHIRD_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.). SeeNOTICEfor 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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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 logRelease 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 logSecurity 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.
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 logA 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.