# DeepOCR

> Make any scan searchable — one command, local, no upload.

[![CI](https://github.com/deeplabua/deepocr/actions/workflows/ci.yml/badge.svg)](https://github.com/deeplabua/deepocr/actions/workflows/ci.yml)
[![Crates.io](https://img.shields.io/crates/v/deepocr.svg)](https://crates.io/crates/deepocr)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](#license)
[![Stars](https://img.shields.io/github/stars/deeplabua/deepocr?style=flat&logo=github&label=Star)](https://github.com/deeplabua/deepocr/stargazers)

`deepocr` adds a searchable text layer to a scanned PDF or image in a single command. Point it
at a scan — it OCRs each page and writes a new PDF with the original image preserved and an
**invisible, selectable text layer** on top, so you can search and copy text in any PDF viewer.
**Locally, without uploading your documents anywhere, and without Ghostscript or Python.**

A pure-Rust OCR tool built on [`ocrs`](https://github.com/robertknight/ocrs).

> **Status:** early development (v0.1). Handles **Latin-script** scans (English + Western
> European), outputs searchable PDF, with page-image optimization and batch processing. Install
> via Homebrew or crates.io.
>
> If DeepOCR is useful to you, please **[⭐ star the repo](https://github.com/deeplabua/deepocr)** — it genuinely helps. See [Support](#support) to chip in.

## Why

You have scanned PDFs — contracts, receipts, book pages, an archive — and you can't search or
copy the text. The usual fix is **OCRmyPDF** (excellent, but Python + Tesseract + **Ghostscript**
+ unpaper — a heavy install), or an **online OCR site** (upload your passport / contract / tax
form to a stranger's server). DeepOCR answers the one question directly: **make this scan
searchable, on your machine, one binary.**

Especially for the documents you'd never upload — IDs, medical records, legal, financial —
DeepOCR keeps everything local.

## Install

Homebrew (macOS / Linux) — ships the OCR model, works offline:

```sh
brew install deeplabua/tap/deepocr
```

From crates.io (fetches the OCR model on first run):

```sh
cargo install deepocr
```

Or download a prebuilt binary from the [releases page](https://github.com/deeplabua/deepocr/releases).

## Usage

Make a scanned PDF searchable (writes `scan.ocr.pdf`, original untouched):

```sh
deepocr scan.pdf
```

Also write the plain text, or OCR an image:

```sh
deepocr scan.pdf --sidecar scan.txt
deepocr photo.jpg              # → photo.ocr.pdf
```

Clean up the scan before OCR, and shrink the output:

```sh
deepocr scan.pdf --deskew --optimize
```

Batch a whole folder:

```sh
deepocr ./scans --recursive -o out/
```

The original file is never modified — DeepOCR writes a new `*.ocr.pdf`.

### Inputs

- **Scanned PDFs** (pages that are images) — the main case.
- **Images** — PNG, JPEG, TIFF (incl. multi-page TIFF).
- **Mixed / born-digital PDFs** — rendered with `hayro` and OCR'd where needed; pages that
  already have a text layer are skipped by default.

## How it works

For each page, DeepOCR gets the page raster (extracted directly for scanned PDFs, rendered via
`hayro` for others), optionally cleans it up (grayscale, DPI-normalize, deskew), runs `ocrs` to
recognize words with their positions, and writes a searchable PDF: the original page image plus
an invisible, positioned text layer (a glyphless font, PDF text render mode 3) aligned to the
words. `--optimize` recompresses the page images to shrink the result. No page ever leaves your
machine; no Ghostscript is involved.

## Scope

- **Latin script** (English + Western European) in v0.1 — that's what `ocrs` recognizes today.
  Other scripts/languages (CJK, etc.) are planned via pluggable backends.
- **Searchable PDF + plain text** output. Structured Markdown/JSON extraction for RAG is a
  sibling tool, **DeepDoc** (which reuses this OCR engine).
- **Not PDF/A** (yet) — a plain searchable PDF. Strict PDF/A is planned, done without Ghostscript.

## Library

The OCR + searchable-PDF engine is also a crate — depend on `deepocr-core` to embed it in your
own Rust service:

```toml
[dependencies]
deepocr-core = "0"
```

## Support

DeepOCR is free and open-source, built and maintained by one developer.

- **[⭐ Star the repo](https://github.com/deeplabua/deepocr)** — the cheapest way to help.
- **Chip in a tip** via the **Sponsor** button at the top of the repo, or directly through the
  [monobank jar](https://send.monobank.ua/jar/pjB5Tvmod). It supports a Ukrainian developer.
  Thank you 💙💛

## Part of DeepLab

DeepOCR is part of [DeepLab](https://deeplab.tools) — a line of tools for developers and product teams.

## License

Licensed under either of

- MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion
in this work by you, as defined in the Apache-2.0 license, shall be dual licensed as above,
without any additional terms or conditions.
