Skip to main content
scanlayer

scanlayer

Scanned image or photographed document → searchable PDF, or raw OCR text/JSON/TSV/hOCR.

Turn a scanned image or photographed document into a searchable PDF, or export the raw OCR result as plain text, JSON, TSV, or hOCR. Use it as a command-line tool or as a Python library; both are the same engine underneath.

Python 3.9+ Platforms License: MIT


What it does

A scanned invoice, a phone photo of a letter, a stack of photographed pages: scanlayer runs it through Tesseract OCR and gives you back either:

  • a searchable PDF: the original page image, with an invisible, precisely positioned text layer over it, so you can select and search text exactly where it visually appears, or
  • the raw OCR result as txt, json, tsv, or hocr: text, per-word confidence, and bounding boxes, no PDF built at all.

Along the way it automatically straightens rotated/skewed pages, corrects uneven lighting, denoises and sharpens for OCR accuracy without touching what you actually see in the output, reconstructs correct reading order on genuine multi-column pages, and races several OCR configurations against each other to pick the most confident result.

Two interfaces, one engine scanlayer CLI and import scanlayer call the exact same pipeline
Five output formats Searchable pdf, or raw txt / json / tsv / hocr
Real column detection Two-column articles/letters read in correct order, not interleaved
Batch, merge, native PDF input Convert a folder in one call, merge pages into one PDF, or --dry-run a batch before spending time on OCR
One configuration surface configure(), a JSON/YAML profile, or CLI flags, documented precedence
Debug overlay --debug-image draws every word, color-coded by confidence

See the feature catalog for the complete list, and Roadmap & Limitations for what's deliberately out of scope or not built yet.

Requirements

  • Python 3.9+
  • Tesseract OCR (a separate, system-level install, see below)
  • poppler only if you feed scanlayer a native .pdf file directly
# Debian / Ubuntu
sudo apt install tesseract-ocr poppler-utils

# macOS (Homebrew)
brew install tesseract poppler

# Windows: Tesseract -> https://github.com/tesseract-ocr/tesseract/wiki
#          poppler    -> download a release, add its bin/ to PATH

Full detail, including how scanlayer locates the Tesseract binary automatically and how to bundle your own, is in Installation and Bundling Tesseract.

Install

pip install scanlayer

This installs the scanlayer console command and makes import scanlayer available anywhere on the machine.

Working on scanlayer itself, or want to run it straight from a checkout with no install at all?

git clone https://github.com/Hyacinthe-primus/scanlayer.git
cd scanlayer                        # the repo root, which contains requirements.txt
pip install -r requirements.txt
python -m scanlayer invoice.jpg -o invoice.pdf   # works with no install at all

See CONTRIBUTING.md for the full contributor setup (editable install and running the test suite).

Quick start

As a CLI:

scanlayer invoice.jpg -o invoice.pdf --lang fra+eng --dpi 300

As a library:

import scanlayer

result = scanlayer.convert("invoice.jpg", "invoice.pdf", lang="fra+eng", dpi=300)
print(f"{result.words_count} words, {result.mean_confidence:.1f}% confidence")

Every CLI flag and library keyword argument in this project are named to match each other (--langlang=, --dpidpi=, and so on), see Examples for every feature shown both ways, side by side, and CLI Reference / Library API for the complete details of each.

A few more common cases:

# Batch-convert a folder
scanlayer *.jpg -o ./converted/

# Merge several photographed pages into one searchable PDF
scanlayer page1.jpg page2.jpg page3.jpg -o report.pdf --merge

# Export raw OCR text/JSON instead of a PDF
scanlayer invoice.jpg -o invoice.json --format json

# See what OCR actually detected, color-coded by confidence
scanlayer invoice.jpg --debug-image

# Validate a batch before spending time on OCR: files exist,
# Tesseract reachable, output paths writable
scanlayer *.jpg -o ./converted/ --dry-run
import scanlayer

# Batch
result = scanlayer.convert_batch(["*.jpg"], "./converted/")

# Merge
scanlayer.convert_merge(["page1.jpg", "page2.jpg", "page3.jpg"], "report.pdf")

# Raw export
scanlayer.convert("invoice.jpg", "invoice.json", output_format="json")

Documentation

Installation Tesseract, poppler, and the two ways to install scanlayer itself
Examples Every feature, CLI and library side by side
CLI Reference Every flag and exit code
Library API convert(), convert_batch(), convert_merge(), exceptions, and the full low-level pipeline API
Feature Catalog Everything scanlayer does, by pipeline stage
Configuration configure(), config files, precedence, every tunable
Output Formats The pdf/txt/json/tsv/hocr schemas
Multi-Page & Merge Batching, merging, native PDF input
Debug Visualization Reading the --debug-image confidence overlay
Bundling Tesseract Shipping your own Tesseract binary
Troubleshooting Common errors and fixes
Roadmap & Limitations What's missing and what's deliberately out of scope

The site is published from the gh-pages branch at https://Hyacinthe-primus.github.io/scanlayer/. To browse it locally, open index.html in a gh-pages worktree (e.g. git worktree add <path> gh-pages); it has no build step or server-side dependency.

Repository layout

.
├── .github/           # FUNDING.yml
├── scanlayer/         # library source
│   ├── __init__.py
│   ├── __main__.py    # enables `python -m scanlayer`
│   ├── main.py        # public API: convert()/convert_batch()/convert_merge()
│   ├── config.py
│   ├── cli/           # argparse CLI: parser.py, run.py, dry_run.py
│   ├── fonts/         # bundled DejaVu Sans for the PDF text layer
│   ├── preprocessing/
│   ├── ocr/
│   ├── layout/
│   ├── pdf/
│   └── utils/
├── tests/             # pytest suite
├── pyproject.toml
├── requirements.txt
├── README.md
├── CONTRIBUTING.md
├── SECURITY.md
└── LICENSE.md

Contributing

Bug reports, fixes, and feature discussions are welcome: see CONTRIBUTING.md for how to set up a development environment and what to include in a pull request. There is a tests/ directory (now including utils/validators.py and the --dry-run flag, with cross-platform coverage for Tesseract discovery on Windows/macOS/Linux) and it runs with pytest, but no CI yet; see Roadmap & Limitations and the Adding tests section of the contributing guide for where coverage is thinnest.

License

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scanlayer-1.0.1.tar.gz (438.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scanlayer-1.0.1-py3-none-any.whl (432.6 kB view details)

Uploaded Python 3

File details

Details for the file scanlayer-1.0.1.tar.gz.

File metadata

  • Download URL: scanlayer-1.0.1.tar.gz
  • Upload date:
  • Size: 438.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for scanlayer-1.0.1.tar.gz
Algorithm Hash digest
SHA256 e0bcb3e094007ccdcb953f3d75d316036df8e972b3bbd1a290837ab6f96c6879
MD5 c1690ed6215e4049a0974fd387284498
BLAKE2b-256 b3a32466f5f9dafe8ea139c5115b02139d76a1188ddf3dfb39dd91ff48fb4676

See more details on using hashes here.

Provenance

The following attestation bundles were made for scanlayer-1.0.1.tar.gz:

Publisher: pypi-publish.yml on Hyacinthe-primus/scanlayer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file scanlayer-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: scanlayer-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 432.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for scanlayer-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d05488a94d029009cd827426b83d7dbf23c93ed2ae9ec72db6396b0cc3057892
MD5 b3140f2210ad534b52c0756f3ffcf5d1
BLAKE2b-256 c2b1f96d5af2d5ae5cae9682500508f1070208b8b9d1055a75295525ee926983

See more details on using hashes here.

Provenance

The following attestation bundles were made for scanlayer-1.0.1-py3-none-any.whl:

Publisher: pypi-publish.yml on Hyacinthe-primus/scanlayer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.0.2

2 files

This release

1.0.1 This release

2 files

1.0.0

2 files

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