# ARCHITECTURE
## Overview
The `ocr` crate implements OCR **without Tesseract or any external OCR binary**. The pipeline is deterministic template matching over a built-in 5×7 bitmap font.
```
┌─────────────────────────────────────────────────────────┐
│ ocr (library) │
│ ┌─────────┐ ┌───────────┐ ┌─────────┐ ┌────────────┐ │
│ │ engine │ │ preprocess│ │ segment │ │ recognize │ │
│ │ (orche- │ │ (otsu │ │ (lines, │ │ (template │ │
│ │ strate) │ │ binarize)│ │ chars) │ │ matching) │ │
│ └─────────┘ └───────────┘ └─────────┘ └─────┬──────┘ │
│ ┌──────────────────────────────────────┘ │
│ │ font (glyphs), types, error │
└─────────┴──────────────────────────────────────────────┘
│ │
┌────────▼────────┐ ┌───────▼────────┐
│ ocr (binary) │ │ ocr-mcp │
│ clap CLI │ │ rmcp server │
└─────────────────┘ └───────────────┘
```
## Crate structure
### Library (`ocr`)
Core logic lives in modules under `src/`. The crate does not shell out to external OCR tools.
| `engine` | `OcrEngine`: load image, optional preprocess, run binarize → segment → recognize per line |
| `preprocess`| Grayscale, Otsu binarization, optional `preprocess` shortcut, small-component noise cleanup |
| `segment` | Horizontal projection (lines), vertical projection (character columns), gap stats for spaces |
| `recognize` | Normalize character crops to 5×7, score against glyph templates, small disambiguation rules |
| `font` | Glyph bitmap definitions and supported character set |
| `render` | Text → synthetic grayscale test images (used by tests and examples) |
| `types` | `OcrResult`, `OcrWord`, `BoundingBox` |
| `error` | `Error` enum (`thiserror`) |
### Binaries
| `ocr` | Thin CLI: open file, call engine, print text or JSON |
| `ocr-mcp` | MCP server: `ocr_image`, `ocr_base64` tools via rmcp (stdio) |
## Data flow
```
Image (path / bytes / memory)
│
▼
Optional preprocessing (grayscale + fixed threshold)
│
▼
Binarize (Otsu) → boolean grid
│
▼
Clean tiny connected components (noise)
│
▼
find_lines (horizontal projection; merge thin vertical gaps for i/j-style glyphs)
│
▼
Per line: find_chars (vertical projection) → gaps → insert word spaces (median-based threshold)
│
▼
Per segment: crop patch, normalize to template size, best template + targeted corrections (e.g. 3/j, x/k, '/t)
│
▼
OcrResult { text, words, confidence }
```
## Design decisions
1. **No subprocess / FFI OCR** - Keeps installs simple (no system Tesseract), reproducible behavior, and a fully Rust dependency graph for the recognition core.
2. **Template matching** - Fast and adequate for the bundled monospace-style font and test images; not a substitute for ML OCR on arbitrary fonts or handwriting.
3. **Builder-style `OcrEngine`** - `.language` is reserved for future use; recognition today is driven by the fixed glyph set (English-oriented).
4. **MCP errors as strings** - Tools return human-readable error lines so all clients can surface failures without relying on MCP error object support.
## Future expansion (see TODO.md)
- Richer glyph / language support
- Stronger segmentation or learned matchers
- Optional HTTP transport for MCP
- PDF and batch workflows