lmocr 0.1.1

Convert PDFs and images to Markdown using OpenRouter multimodal LLMs
lmocr-0.1.1 is not a library.

lmocr

lmocr is a Rust CLI that converts PDFs and images to Markdown using an OpenRouter multimodal model.

The tool is optimized for real OCR work, not toy demos:

  • input types: PDFs, single images (PNG, JPEG, WebP, GIF, TIFF, BMP), and folders of images treated as multi-page documents
  • per-page processing with retries and resumable caching
  • continuity-aware stitching across page boundaries
  • deterministic cleanup for running headers, footers, and page numbers
  • blank-page detection to avoid hallucinated content
  • extracted-text fast path (pdftotext) for text-based PDFs

Install

# needed for PDF inputs only (macOS); image inputs have no external dependencies
brew install poppler

# from crates.io
cargo install lmocr

# or from a checkout
cargo install --path . --locked

Setup

# configure once
lmocr auth

# or set per-run
export OPENROUTER_API_KEY=sk-or-v1-...

Usage

lmocr /path/to/file.pdf -o out.md
lmocr /path/to/file.pdf -p 10-12 --exclude headers,footers,page-numbers
lmocr /path/to/file.pdf --preset audiobook
lmocr screenshot.png -o out.md
lmocr ./scanned_pages/ -o out.md   # folder of images = multi-page document

Run lmocr -h for the full option list.

Presets

Preset Description
markdown Default. Faithful transcription — preserves all structure, tables as HTML, poetry in <pre> blocks.
audiobook Linearized for text-to-speech. Strips tables, images, headers, footers, page numbers, and footnotes. Expands abbreviations and merges hyphenated line breaks.
search Keyword-dense output for search indexing. Keeps headings, lists, and data tables. Removes decorative filler.

Note: --exclude flags are redundant with audiobook since it already strips those elements.

Custom instructions

The -i / --instruction flag appends custom rules to the OCR prompt:

lmocr doc.pdf -i "Translate all text to French"
lmocr doc.pdf -i "Number headings with outline format (1, 1.1, 1.1.1)"
lmocr doc.pdf -i "Omit all image descriptions"

How it works

  • Text-based PDFs use a pdftotext fast path — no vision API call, much cheaper and faster.
  • Scanned / image-heavy PDFs render each page as a PNG and send it to the vision model.
  • This is automatic based on extracted-text coverage. No flag needed.
  • Images are sent directly to the vision model. TIFF/BMP are transcoded to PNG for upload; a folder of images is processed as one multi-page document (sorted lexicographically) with full cross-page stitching.

Configuration

# API key is stored by `lmocr auth` at:
#   macOS: ~/Library/Application Support/ai.lmocr.lmocr/config.toml
#   Linux: ~/.config/lmocr/config.toml

# Or set per-session:
export OPENROUTER_API_KEY=sk-or-v1-...

Cache lives at .lmocr/cache/ relative to the current directory. To clear it:

rm -rf .lmocr/cache
# or skip cache for a single run:
lmocr doc.pdf --no-cache

The cache key includes: source file, page number, DPI, model, preset, excludes, prompt version, custom instruction, and previous-page context. Changing any of these invalidates the cached result for that page.

Reliability Notes

  • --max-retries means retries after the first attempt (total attempts = retries + 1).
  • Retry loop uses linear backoff.
  • Image OCR retries now include automatic lower-DPI fallbacks (300 -> 240 -> 200 -> 180 -> 150) before failing a page.
  • Continuity logic merges split sentences and de-hyphenates page-break fragments.
  • Boundary artifact stripping removes common leaked seam headers when they interrupt sentence flow, including default mode.

Development

Run cargo test before contributing. Maintainer regression evals are documented in project/EVAL.md.

License

MIT

AI training

The author reserves rights to this work under applicable text-and-data-mining provisions and asks that it not be used as AI training data.