A faster Tesseract alternative: OCR PDFs to markdown on CPU with Indra OCR Datalab's Indra OCR, a 1M-parameter OCR model that runs on CPU via ONNX Runtime without PyTorch or a GPU, converts PDFs and images into markdown, text, or JSON with bounding boxes and reading order, and handles handwriting and 80+ languages. The project's own benchmarks put its overall score at 61.3, ahead of PaddleOCR's PP-StructureV3 pipeline at 58.4, with a text score of 46.7 versus 35.8 for PaddleOCR's PP-OCR and 19.3 for Tesseract. It ships as a pip-installable CLI and Python library with an auto mode that reads existing PDF text layers and OCRs only missing pages, plus a local viewer for side-by-side comparison with Tesseract. Tesseract is still the default OCR engine in a lot of pipelines, mostly because it is free, local and needs no GPU. Indra OCR from Datalab keeps all three of those properties and adds layout, reading order and handwriting. This post shows how to install it, convert PDFs to markdown or JSON, and use it from Python. datalab-to/indra https://github.com/datalab-to/indra describes Indra OCR as a 1M-parameter OCR model that runs on CPU. It turns PDFs and images into markdown, text, or JSON with boxes, and reads handwriting, 80+ languages and pages at any angle. It runs on ONNX Runtime, with no PyTorch and no GPU. --math , ahead of PaddleOCR's full PP-StructureV3 pipeline at 58.4. Its text score of 46.7 is ahead of PaddleOCR's PP-OCR text models 35.8 and Tesseract 19.3 . These are the project's own benchmarks, so treat them as a reason to test on your documents, not as a guarantee. You need Python 3.10 or newer. The README lists testing on Linux x86 64 and aarch64 and macOS on Apple silicon. pip install indra-ocr The first run downloads the models from Hugging Face and caches them. To use a local copy, set INDRA OCR MODEL DIR or pass --model-dir , which is what you want on an air-gapped server. indra-ocr paper.pdf markdown to stdout indra-ocr .pdf --out results/ one .md per input, all cores indra-ocr scan.png --format json lines, boxes, layout blocks, confidences 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 indra-ocr paper.pdf --math write math as LaTeX The default --mode auto is the part that saves time on mixed archives: it reads the PDF text layer where it passes the checks and only OCRs what is missing. Use --mode ocr when a text layer is present but garbage, which happens a lot with old scans. Page headers and footers are left out of the markdown unless you pass --keep-furniture . The CLI keeps going past files it cannot read and exits with 1 if any failed, so it is safe to point at a big folder. indra-ocr-viewer --port 8765 Open http://localhost:8765 http://localhost:8765 and drop in a PDF or image. Each page shows its lines, layout blocks and reading order drawn over the page, with the rendered markdown, the lines with their confidences and the JSON. Files stay on your machine. Install pip install "indra-ocr tesseract " plus a Tesseract binary and the viewer can compare the two side by side, which is the fastest way to decide whether to switch. python import indra ocr conv = indra ocr.load threads=4 mode="auto" | "ocr" | "text" for i, page in conv.convert "paper.pdf" : print page.source, page.timings "total ms" print page.markdown headings, lists, tables as HTML page.blocks {"label", "bbox", "text"} in reading order page.lines Line box, text, conf in reading order For batches, convert many runs one single-threaded worker per core and returns results in input order. Keep the if name == " main ": guard on macOS and Windows: python import indra ocr if name == " main ": for path, result in indra ocr.convert many "a.pdf", "b.pdf" , cores=None : if isinstance result, indra ocr.InputError : continue unreadable or locked file for i, page in result: print path, i, page.source Every block carries a label Text , Section-Header , Table , Caption , Footnote , Form and more and a bounding box, so feeding clean chunks to an LLM or a search index is a filter, not a regex project. The builds collected on the Indra page https://dedupedai.com/use-cases/datalab-to-indra/?utm source=devto&utm medium=article&utm campaign=howto indra are mostly about replacing Tesseract in existing tools: If you run Paperless-ngx at home, those two plugins are the quickest real-world win. Indra is built for speed on CPUs. For very long documents, Baidu's Unlimited OCR https://dedupedai.com/use-cases/baidu-unlimited-ocr/?utm source=devto&utm medium=article&utm campaign=howto indra is an open OCR model aimed at parsing documents of any length within a finite context window, and it is worth comparing on that kind of input. The Indra README itself points to Datalab's larger Chandra model for the hardest handwriting, math, complex tables and degraded scans. Source repo: datalab-to/indra https://github.com/datalab-to/indra . Want the setup commands for 50 AI repos people actually ship with? Get the free AI Repos That Actually Ship pack: https://dedupedai.com/ship-pack/?utm source=devto&utm medium=article&utm campaign=shippack https://dedupedai.com/ship-pack/?utm source=devto&utm medium=article&utm campaign=shippack