# hyacinthe-primus/scanlayer architecture

> Architecture diagram of the GitHub repository hyacinthe-primus/scanlayer, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-09). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/hyacinthe-primus/scanlayer
- Repository: https://github.com/hyacinthe-primus/scanlayer

## Overview

scanlayer converts scanned images or photographed documents into searchable PDFs or raw OCR exports. Users enter through the CLI or Python API; the shared conversion engine validates and preprocesses pages, extracts and reorders OCR words, then writes the selected output. Batch conversion, merging, native-PDF input, configuration, dry-run checks, and debug overlays are also documented capabilities. The graph follows the sampled orchestration and SOURCE INDEX references; unsampled implementation details are represented only where the README documents them.

Main entry points: [`scanlayer/main.py`](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/main.py) (Conversion API), [`scanlayer/cli/run.py`](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/cli/run.py) (CLI commands), [`scanlayer/pdf/builder.py`](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/pdf/builder.py) (Searchable PDF), [`scanlayer/config.py`](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/config.py) (Runtime configuration)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_interfaces["User interfaces"]
  node_cli["CLI commands<br/>[run.py]"]
  node_cli_parser["Argument parser<br/>[parser.py]"]
  node_dry_run["Dry-run checks<br/>[dry_run.py]"]
end

subgraph group_pipeline["Conversion pipeline"]
  node_api["Conversion API<br/>[main.py]"]
  node_preprocess["Image enhancement<br/>[enhance.py]"]
  node_ocr["OCR engine<br/>[engine.py]"]
  node_columns["Column ordering<br/>[columns.py]"]
end

subgraph group_outputs["Output generation"]
  node_export["Raw OCR export<br/>[export.py]"]
  node_pdf["Searchable PDF<br/>[builder.py]"]
  node_pdf_fonts["PDF fonts<br/>[fonts.py]"]
  node_debug_image["Debug overlay<br/>[debug_image.py]"]
end

subgraph group_support["Configuration and diagnostics"]
  node_validation["Input validation<br/>[validators.py]"]
  node_config["Runtime configuration<br/>[config.py]"]
  node_logger["Logging and timing<br/>[logger.py]"]
end

node_cli_user(("CLI user"))
node_library_user(("Python caller"))
node_tesseract["Tesseract OCR"]
node_result["PDF or OCR files"]

node_cli_user -->|"runs"| node_cli
node_cli -->|"parses arguments"| node_cli_parser
node_cli -->|"applies settings"| node_config
node_cli -->|"dispatches checks"| node_dry_run
node_cli -->|"starts conversion"| node_api
node_library_user -->|"calls"| node_api
node_dry_run -->|"validates inputs"| node_validation
node_api -->|"checks prerequisites"| node_validation
node_api -->|"preprocesses pages"| node_preprocess
node_preprocess -->|"checks orientation"| node_tesseract
node_api -->|"extracts words"| node_ocr
node_ocr -->|"runs OCR"| node_tesseract
node_api -->|"orders words"| node_columns
node_api -->|"exports OCR data"| node_export
node_api -->|"builds PDF"| node_pdf
node_pdf -->|"uses fonts"| node_pdf_fonts
node_api -->|"writes overlay"| node_debug_image
node_api -->|"reads options"| node_config
node_api -->|"writes output"| node_result
node_export -->|"writes export"| node_result
node_pdf -->|"writes PDF"| node_result
node_config -->|"configures logging"| node_logger

click node_cli "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/cli/run.py"
click node_cli_parser "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/cli/parser.py"
click node_dry_run "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/cli/dry_run.py"
click node_api "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/main.py"
click node_validation "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/utils/validators.py"
click node_preprocess "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/preprocessing/enhance.py"
click node_ocr "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/ocr/engine.py"
click node_columns "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/layout/columns.py"
click node_export "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/ocr/export.py"
click node_pdf "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/pdf/builder.py"
click node_pdf_fonts "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/pdf/fonts.py"
click node_debug_image "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/utils/debug_image.py"
click node_config "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/config.py"
click node_logger "https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/utils/logger.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_cli,node_cli_parser,node_dry_run,node_cli_user toneBlue
class node_api,node_preprocess,node_ocr,node_columns toneAmber
class node_export,node_pdf,node_pdf_fonts,node_debug_image toneMint
class node_validation,node_config,node_logger toneRose
class node_library_user,node_tesseract,node_result toneIndigo
```

## Components

### User interfaces

- [CLI commands](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/cli/run.py): `scanlayer/cli/run.py`
- [Argument parser](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/cli/parser.py): `scanlayer/cli/parser.py`
- [Dry-run checks](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/cli/dry_run.py): `scanlayer/cli/dry_run.py`

### Conversion pipeline

- [Conversion API](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/main.py): `scanlayer/main.py`
- [Image enhancement](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/preprocessing/enhance.py): `scanlayer/preprocessing/enhance.py`
- [OCR engine](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/ocr/engine.py): `scanlayer/ocr/engine.py`
- [Column ordering](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/layout/columns.py): `scanlayer/layout/columns.py`

### Output generation

- [Raw OCR export](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/ocr/export.py): `scanlayer/ocr/export.py`
- [Searchable PDF](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/pdf/builder.py): `scanlayer/pdf/builder.py`
- [PDF fonts](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/pdf/fonts.py): `scanlayer/pdf/fonts.py`
- [Debug overlay](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/utils/debug_image.py): `scanlayer/utils/debug_image.py`

### Configuration and diagnostics

- [Input validation](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/utils/validators.py): `scanlayer/utils/validators.py`
- [Runtime configuration](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/config.py): `scanlayer/config.py`
- [Logging and timing](https://github.com/hyacinthe-primus/scanlayer/blob/main/scanlayer/utils/logger.py): `scanlayer/utils/logger.py`

### Other components

- **CLI user**
- **Python caller**
- **Tesseract OCR**
- **PDF or OCR files**

## Connections

- CLI user → CLI commands: runs (evidence: `README.md`)
- CLI commands → Argument parser: parses arguments (evidence: `scanlayer/cli/run.py`)
- CLI commands → Runtime configuration: applies settings (evidence: `scanlayer/cli/run.py`)
- CLI commands → Dry-run checks: dispatches checks (evidence: `scanlayer/cli/run.py`)
- CLI commands → Conversion API: starts conversion (evidence: `scanlayer/cli/run.py`)
- Python caller → Conversion API: calls (evidence: `README.md`)
- Dry-run checks → Input validation: validates inputs (evidence: `scanlayer/cli/dry_run.py`)
- Conversion API → Input validation: checks prerequisites (evidence: `scanlayer/main.py`)
- Conversion API → Image enhancement: preprocesses pages (evidence: `scanlayer/main.py`)
- Image enhancement → Tesseract OCR: checks orientation (evidence: `scanlayer/preprocessing/enhance.py`)
- Conversion API → OCR engine: extracts words (evidence: `scanlayer/main.py`)
- OCR engine → Tesseract OCR: runs OCR (evidence: `README.md`)
- Conversion API → Column ordering: orders words (evidence: `scanlayer/main.py`)
- Conversion API → Raw OCR export: exports OCR data (evidence: `scanlayer/main.py`)
- Conversion API → Searchable PDF: builds PDF (evidence: `scanlayer/main.py`)
- Searchable PDF → PDF fonts: uses fonts (evidence: `scanlayer/pdf/builder.py`)
- Conversion API → Debug overlay: writes overlay (evidence: `scanlayer/main.py`)
- Conversion API → Runtime configuration: reads options (evidence: `scanlayer/main.py`)
- Conversion API → PDF or OCR files: writes output (evidence: `README.md`)
- Raw OCR export → PDF or OCR files: writes export (evidence: `README.md`)
- Searchable PDF → PDF or OCR files: writes PDF (evidence: `scanlayer/pdf/builder.py`)
- Runtime configuration → Logging and timing: configures logging (evidence: `scanlayer/config.py`)
