Open-source project
datalab-to/indra avatar
datalab-to/indra

Indra OCR turns scans into markdown on a CPU without PyTorch

Fast CPU OCR: line detection, CTC recognition, reading order, markdown

998 stars104 forksPythonApache-2.0

At a glance

What is it?
Indra OCR is a document OCR model that runs on ONNX Runtime and outputs markdown, text or JSON with boxes and reading order, and it reads the text layer of a digital PDF and only OCRs what is missing. The catch is the model weights, which are under a modified OpenRAIL-M licence with commercial conditions rather than a plain open source licence.
Who is it for?
Indra OCR suits a team that needs to turn scanned documents, forms or handwritten pages into structured markdown on ordinary CPU hardware, and it suits anyone who wants OCR without installing PyTorch or a GPU runtime, since the install is onnxruntime, OpenCV and pypdfium2.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A recogniser that ships as ONNX, not as a Python model

The technical bet of Indra OCR is that a document model does not need a GPU or a deep learning framework to be useful. The README states it plainly with the Small point: ONNX Runtime, no PyTorch, no GPU. The package metadata backs that up, since the runtime dependencies are numpy, opencv-python-headless, onnxruntime, pypdfium2 and huggingface_hub, with no torch anywhere in the list:

toml
dependencies = [
  "numpy",
  "opencv-python-headless",
  "onnxruntime",
  "pypdfium2",
  "huggingface_hub",
]

The model is described as a 1M-parameter OCR model that runs on CPU, and the numbers in the README are more precise: the main recogniser, rec.onnx for the Latin script, has about 1.25M parameters, and all the default models together come to 7.3M, with the optional math models extra. The default model download is about 76 MB, split as 30 MB of networks and 46 MB of language models for the lines the recogniser is unsure about. That is a small enough footprint to run on a server that has no accelerator at all. The package comes from PyPI:

shell
pip install indra-ocr

The pipeline is detection, recognition, reading order, markdown

The project description names the four stages: line detection, CTC recognition, reading order and markdown, and the package description in pyproject.toml repeats it as Fast CPU OCR for line detection, CTC recognition, reading order and markdown on ONNX Runtime. The output is not a wall of text. For every line and block the model produces a box, a label and a reading order, covering headings, lists, tables, captions, footnotes and page headers, and the CLI can emit that as JSON with lines, boxes, layout blocks, confidences and timings. The labels are what make the markdown useful rather than merely readable, because a heading stays a heading and a table stays a table instead of both being flattened into prose. The recognition step is CTC based, which is a reasonable fit for OCR since it does not require the model to know the character boundaries in advance, and the language models exist to disambiguate the lines the recogniser is not confident about.

A digital PDF is read, and only the missing parts are OCRed

The default mode is the reason this project is worth a look for anyone with a mixed document pipeline. The README describes Digital PDFs as reading the text layer in any script and OCRing only what is missing, and the CLI documents the three modes: auto reads the text layer where it passes the checks and OCRs elsewhere, which is the default, while ocr ignores the text layer and OCRs every page, and text is the third option. Forcing the OCR mode with --mode ocr is a real tool, since a PDF can carry a stale or badly encoded text layer that produces garbage output while the pixels underneath are perfectly readable. The checks the auto mode applies are not described in detail, and that is the one place the documentation is thin, because whether a given text layer passes those checks is what decides between a fast read and a full OCR pass.

Markdown out, JSON with boxes out, and a local viewer to check it

The command line is the primary interface and it is short, with the documented invocations listed as:

shell
indra-ocr paper.pdf                       # markdown to stdout
indra-ocr *.pdf --out results/            # one .md per input
indra-ocr scan.png --format json          # lines, boxes, layout blocks, confidences, timings
indra-ocr paper.pdf --format text         # plain text, one line per detected line
indra-ocr paper.pdf --mode ocr --timings  # ignore the text layer, OCR every page; timings on stderr
indra-ocr paper.pdf --keep-furniture      # keep page headers and footers in the markdown
indra-ocr *.pdf --out results/ --cores 8  # limit the cores (default: all usable cores)
indra-ocr paper.pdf --math                # write math as LaTeX (off by default; slower on math pages)

A single file to markdown on standard output, a glob of files with an output directory, and a JSON format for the structured output are the three shapes you need most, and the quickstart lists them together. There is also a viewer, indra-ocr-viewer, described as a local web viewer on http://localhost:8765, and a note that the first run downloads about 76 MB of models from Hugging Face. The optional Tesseract extra exists so the viewer can compare results side by side with Tesseract, which is a sensible debugging aid rather than a competitive feature. A details of the CLI worth knowing is that the default is to use all usable cores, and --cores 8 limits that, which matters on a shared machine where an OCR job that takes every core is an unwelcome neighbour.

The numbers in the README are claims to check, not guarantees

The README publishes specific accuracy and speed figures and it is worth reading them as claims rather than as a property of your workload. The accuracy figure is 66.7 on OmniParseBench, rising to 71.4 with the --math flag, against 58.4 for PaddleOCR's full PP-StructureV3 pipeline, with the text score given as 46.7 against 35.8 for PaddleOCR's PP-OCR text models and 19.3 for Tesseract. On speed, the README says about 44 pages per second on 32 CPU cores, 15 times Tesseract and 10 times PaddleOCR's PP-OCR text models on the same machine type and pages, and about 210 ms per page on four cores. The benchmarks section and the OmniParseBench repository are linked. The honest reading is that these are benchmark numbers on a particular machine and a particular page set, and that a document population of handwritten forms or low-contrast scans is a different workload from a benchmark corpus.

Handwriting is supported and is also the stated weak point

The README advertises handwriting support, reading handwritten pages and forms, and gives a figure for it: 25.2 percent on the OmniParseBench handwriting tests, with a link to a limitations section in the same document. That is a much lower number than the headline accuracy, and the honesty is a point in the project's favour. The same bullet describes Real-world scans, including sideways, upside down, tilted up to 45 degrees, and light text on dark ground, so the orientation handling is a real feature rather than a claim. The 80+ language list covers Latin-script languages, Russian and the Cyrillic languages, Greek, Chinese, Japanese, Korean, Arabic, Persian, Urdu, Hebrew, Hindi and the Indic languages, Thai, Khmer and more, and the README notes that each line goes to the recogniser for its script.

Apache 2.0 for the code, OpenRAIL-M for the weights

The licensing has two halves and the difference is not a formality. The code is Apache 2.0, with the licence file at the root of the repository and the licence identifier set in pyproject.toml, and the model weights use a modified OpenRAIL-M licence, with the badge in the README header naming the model licence separately from the code licence. The commercial section spells out the conditions: the weights are free for research, personal use, and startups under 20M in funding or revenue, and cannot be used competitively with the API, and the pricing page is where you go to remove the OpenRAIL requirements or to get a broader commercial licence. The model weights live on HuggingFace at datalab-to/indra-ocr while the code lives in this repository, so a deployment has to satisfy two licences at once. The same company also runs a managed platform with a different model called Chandra, and a batch service, which is the commercial context behind the restriction.

Where the project is a research tool and not a production dependency

The practical boundaries are clear from the README itself. The first is the model licence, which is the hard stop for anything commercial. The second is the release velocity: the recent tags are v1.1.0, v1.1.1 and v1.1.2, all within a single day on 2026-10-19 and 2026-10-20, and the last push to the repository was on 2026-10-22, so the project is moving fast enough that a pinned version and a pinned model snapshot are the only sensible deployment posture. The third is the platform coverage, which the README states as tested on Linux on x86_64 and aarch64 with Python 3.10 to 3.13, and macOS on Apple silicon, with Python 3.10 or newer required, which leaves Windows untested as far as the documentation says. The repository layout supports a normal workflow, with a bench/ directory, a tests/ directory, an indra_ocr/ package, an examples/ directory with a quickstart notebook and an OCR image script, and a CHANGELOG.md and EXAMPLES.md at the root.

Editorial conclusion

Indra OCR suits a team that needs to turn scanned documents, forms or handwritten pages into structured markdown on ordinary CPU hardware, and it suits anyone who wants OCR without installing PyTorch or a GPU runtime, since the install is onnxruntime, OpenCV and pypdfium2. It does not suit a commercial product that would compete with Datalab's own API, because the model weights carry a modified OpenRAIL-M licence limited to research, personal use and startups under 20M in funding or revenue. Before adopting, read the weights licence on HuggingFace separately from the Apache 2.0 code licence, check that the accuracy claims match your own document types, and note that the newest tagged release v1.1.2 is dated 2026-10-20, and the last push was on 2026-10-22.

Frequently asked questions

How do I install Indra OCR and run it on a PDF?

Install it with `pip install indra-ocr`, then run `indra-ocr paper.pdf` to get markdown on standard output. The first run downloads about 76 MB of models from Hugging Face, and the local viewer is available as `indra-ocr-viewer` on http://localhost:8765.

Does Indra OCR need a GPU or PyTorch?

No. The README lists ONNX Runtime, no PyTorch, no GPU, and the package dependencies are numpy, opencv-python-headless, onnxruntime, pypdfium2 and huggingface_hub. The model is around 1.25M parameters for the main Latin script recogniser, with 7.3M across all the default models.

What licence applies to the Indra OCR code and the model weights?

The code is Apache 2.0. The model weights use a modified OpenRAIL-M licence, which the README says is free for research, personal use, and startups under $20M in funding or revenue, and cannot be used competitively with the API, with broader commercial licensing available from Datalab's pricing page.

How does Indra OCR handle a PDF that already has a text layer?

In the default auto mode it reads the text layer where it passes the checks and OCRs elsewhere. The ocr mode ignores the text layer and OCRs every page, and the README also documents a text mode. The README does not describe in detail what the checks on the text layer are.

What output formats does the Indra OCR CLI produce?

The format option takes md, text or json, with markdown as the default, and JSON carrying lines, boxes, layout blocks, confidences and timings. The --out option writes one file per input, as .md, .txt or .jsonl, and the --keep-furniture option keeps page headers and footers in the markdown.

Official sources

  1. datalab-to/indra on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/datalab-to-indra.svg)](https://hysenlabs.com/projects/datalab-to-indra)

Was this useful?