PhoenixKitCatalogue.Catalogue.PdfEngines (PhoenixKitCatalogue v0.19.1)

Copy Markdown View Source

Engine chain for PDF text extraction: pdfium (in-app, precompiled NIF) first, poppler (pdfinfo/pdftotext system binaries) as the fallback when installed.

The chain exists so a host needs NO system packages for PDF search to work: ex_pdfium ships Chrome's PDF engine as a precompiled binary fetched during mix deps.get. Hosts that already have poppler keep it as a safety net for files pdfium cannot open. Benchmarked 2026-08-16 on the tim-dev corpus: pdfium word recall vs pdftotext -layout was 98.4–100% per document (dev_docs has the numbers).

open_best/1 tries each engine in order and commits to the first one that can open the document and report a page count — per-page failures after that point are the worker's business (it keeps partial results). When every engine refuses, the per-engine reasons are returned together so the stored error message names them all.

Summary

Types

An opened document, bound to the engine that opened it.

Functions

Releases engine resources: the pdfium document handle is closed eagerly instead of waiting for BEAM GC to collect the NIF resource. No-op for poppler.

Extracts one page's raw text (1-based page_number) with the engine that opened the document.

Opens path with the first engine that accepts it.

Types

engine()

@type engine() :: %{name: String.t(), page_count: non_neg_integer(), state: term()}

An opened document, bound to the engine that opened it.

Functions

close(arg1)

@spec close(engine()) :: :ok

Releases engine resources: the pdfium document handle is closed eagerly instead of waiting for BEAM GC to collect the NIF resource. No-op for poppler.

extract_page(map, page_number)

@spec extract_page(engine(), pos_integer()) :: {:ok, String.t()} | {:error, term()}

Extracts one page's raw text (1-based page_number) with the engine that opened the document.

open_best(path)

@spec open_best(String.t()) :: {:ok, engine()} | {:error, [{String.t(), term()}]}

Opens path with the first engine that accepts it.

Returns {:ok, engine} or {:error, attempts} where attempts is a [{engine_name, reason}] list covering every engine tried (including unavailable ones, so "poppler: not installed" shows up in the stored failure message rather than silently narrowing the chain).