Skip to main content

OCR Ingest

The ingest stage lives in crates/ocr and exposes one entry point:

pub fn extract_text(bytes: &[u8], on_progress: impl Fn(Progress)) -> Result<String, String>

It returns the document text (pages joined by newlines) or an error, and calls on_progress as it advances so the UI can show page-level progress.

Step 1 — probe for a native text layer​

extract_native_text_pages uses pdf-extract to pull the embedded text layer, one string per page. detects_native_text then decides whether that layer is real:

  • Only the first 3 pages (NATIVE_TEXT_PROBE_PAGES) are examined.
  • A PDF is text-bearing when the average number of non-whitespace characters across those pages is at least 50 (NATIVE_TEXT_MIN_CHARS_PER_PAGE).
  • An empty page list counts as scanned.

Probing a small prefix is fast and reliable: scanned documents almost never contain extractable text, and a late text layer (e.g. an appendix) can't trick the heuristic into treating a scanned document as native.

Step 2a — native extraction​

If the probe passes, the per-page strings are already the desired output. The pipeline reports extract progress per page and returns them joined by newlines. No rendering or OCR is performed.

Step 2b — render + OCR fallback​

If the probe fails, or native extraction errored (encrypted or exotic files), the pipeline falls back:

  1. Render — render_pdf_pages draws each page to an image with PDFium. Rendering is sequential because a PDFium document cannot be shared across threads. render progress is reported per page.
  2. OCR — each rendered page is passed to ocr_image, which runs the ocrs text-detection and text-recognition models over it and returns the recognized lines. OCR is CPU-heavy, so pages are processed in parallel with Rayon; results are reported in document order.

The OCR engine (ocr/src/ocr.rs)​

  • Two .rten models — text detection and text recognition — are embedded into the binary at compile time via include_bytes!.
  • A process-wide OcrEngine is constructed once (OnceLock) from those models.
  • ocr_image converts the image to RGB, prepares it, and extracts text in reading order.

The models are not committed to git; download them with crates/ocr/scripts/download-models.sh before building.

Progress reporting​

Each stage advances a Progress { stage, current, total } value, where stages are Detect, Extract, Render, and Ocr. The Tauri layer maps these to the event phase strings consumed by the frontend (see Import and Events).