# Changelog

All notable changes to DeepOCR are recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.1.0 — 2026-07-26

First release. `deepocr scan.pdf` writes `scan.ocr.pdf`: the original page image with an
invisible, selectable text layer on top — searchable in any PDF viewer, produced entirely on
your machine.

### Added

- **Searchable PDFs.** Recognized words are written in text render mode 3 over the page image,
  positioned on the words themselves, so selection, `Ctrl-F` and copy all land where they should.
  The font is a generated glyphless TrueType (~600 bytes) addressed through `Identity-H`, with an
  identity `ToUnicode` map so copied text comes back as the recognized text.
- **Inputs**: scanned PDFs, born-digital and mixed PDFs, PNG, JPEG, and multi-page TIFF (one page
  per frame). A scanned page is lifted out of the PDF without re-rendering; anything else is
  rasterized with `hayro` at `--dpi`.
- **Scans are preserved byte for byte.** A page that arrived as an encoded stream goes into the
  output unchanged, so a JPEG scan loses nothing to a round trip. Only pages that had to be
  rasterized are encoded, once.
- **`--deskew`** measures a page's tilt with a projection profile and rotates it back.
  **`--rotate auto`** recognizes a thumbnail four ways up and keeps the orientation that reads;
  the output page is built upright without resampling the scan.
- **`--optimize`** recompresses page images (with `--quality`), downsampling to `--dpi` where a
  scan is finer than that. It never makes a page larger — if recompression does not win, the
  original stream is kept.
- **`--pages`** limits which pages are recognized; every page of the input still reaches the
  output. **`--skip-text`** (default), **`--force`** and **`--redo`** decide what happens to pages
  that already carry text.
- **`--sidecar`** writes the plain text beside the PDF, pages separated by a form feed.
- **Batch**: `--recursive` walks a folder and mirrors its tree into `--output`. One unreadable
  file is reported and counted, not fatal; the run ends with a summary.
- **Offline by default.** Release binaries (Homebrew, GitHub Releases, the installers) carry the
  OCR models inside them — nothing is downloaded, and no document leaves the machine. A
  `cargo install` build fetches the models into a cache directory on first run, verifying them
  against pinned checksums; `--model` / `DEEPOCR_MODEL_DIR` override the location for air-gapped
  setups.
- **`deepocr-core`** is published alongside the binary, so the engine can be embedded elsewhere.

### Known limitations

- **Latin script only**, which is what `ocrs` reads today. Other scripts arrive with additional
  backends behind the same `OcrBackend` trait.
- **A page skipped by `--skip-text` keeps its image but not its text layer.** The output is
  rebuilt from page rasters, so an existing layer is not carried across; `--redo` recognizes such
  pages again. Adding the layer to the original page in place is planned.
- Output is a plain searchable PDF, **not PDF/A**.

### Notes

- No Ghostscript, no Python, no runtime dependencies — one binary. Every crate in the dependency
  graph is permissively licensed (MIT / Apache-2.0 / BSD / MPL / Zlib).
- The OCR models come from [ocrs-models](https://github.com/robertknight/ocrs-models) and are
  mirrored in this repository's `models-v1` release so that a pinned checksum stays valid.
