The default call uses %ExPdfInspector.PdfOptions{} and runs the complete
pipeline. Build option structs explicitly when you need lower latency, selected
pages, a password, or different Markdown output.
Processing modes
Set ExPdfInspector.PdfOptions.mode to one of:
| Mode | Detection | Layout analysis | Markdown extraction |
|---|---|---|---|
:detect_only | yes | no | no |
:analyze | yes | yes | no |
:full | yes | yes | yes |
For routing decisions where Markdown is not yet needed:
options = %ExPdfInspector.PdfOptions{mode: :detect_only}
{:ok, result} = ExPdfInspector.process_pdf("document.pdf", options)The dedicated detect_pdf/1 and detect_pdf_bytes/1 functions are convenient
shortcuts for detection without extraction.
Detection strategies
ExPdfInspector.DetectionOptions.strategy controls which pages are inspected:
| Strategy | Behavior |
|---|---|
:early_exit | Stops after enough evidence is available. |
:full | Inspects every page. |
{:sample, count} | Inspects a sample of at most count pages. |
{:pages, pages} | Inspects only the specified page indexes. |
The wrapper defaults to {:sample, 8}. Use :full when accurate classification
of mixed documents matters more than minimizing inspection work:
alias ExPdfInspector.{DetectionOptions, PdfOptions}
options = %PdfOptions{
mode: :detect_only,
detection: %DetectionOptions{
strategy: :full,
min_text_ops_per_page: 3,
text_page_ratio_threshold: 0.6
}
}min_text_ops_per_page is the minimum number of PDF text operations required
for a page to count as text-based. text_page_ratio_threshold is the minimum
ratio of text pages used during classification.
Page selection and encrypted PDFs
page_filter limits extraction to zero-based page indexes:
%ExPdfInspector.PdfOptions{page_filter: [0, 4, 9]}Set password to open a password-protected PDF:
%ExPdfInspector.PdfOptions{password: "document-password"}If no valid password is supplied, processing returns an error with the
:encrypted code. Error codes are stable library-defined atoms suitable for
pattern matching, while error messages remain strings.
Markdown profiles
ExPdfInspector.MarkdownOptions.profile accepts:
:fidelity— preserves more of the source document's detected structure;:compact— favors simpler, more token-efficient output.
options = %ExPdfInspector.PdfOptions{
markdown: %ExPdfInspector.MarkdownOptions{profile: :compact}
}Fine-grained fields control detection and output:
| Field | Default | Purpose |
|---|---|---|
detect_headers | true | Detect heading levels. |
detect_lists | true | Detect list structures. |
detect_code | true | Detect code blocks. |
base_font_size | nil | Override the inferred body font size. |
remove_page_numbers | true | Remove detected page numbers. |
format_urls | true | Format detected URLs as Markdown links. |
fix_hyphenation | true | Rejoin words split across lines. |
detect_bold | true | Preserve detected bold text. |
detect_italic | true | Preserve detected italic text. |
detect_underline | true | Preserve detected underlined text. |
include_images | false | Include image placeholders. |
include_links | true | Include links. |
include_page_numbers | false | Include page-number markers in output. |
strip_headers_footers | true | Remove recurring headers and footers. |
For standalone conversion, to_markdown/2 accepts plain text and Markdown
options:
ExPdfInspector.to_markdown(
"TITLE\n\nDocument body",
%ExPdfInspector.MarkdownOptions{profile: :compact}
)The to_markdown_from_items/2 and
to_markdown_from_items_with_rects/3 functions are useful when positioned
items have already been extracted or produced by another pipeline.
Concurrency and deployment
The Rust functions are scheduled as dirty CPU NIFs. Callers can use them from regular Elixir processes without blocking a normal BEAM scheduler, but each document still consumes CPU and memory. Bound concurrency when processing large batches or untrusted documents.
The NIF is native code. Build releases on a platform compatible with the target runtime, or compile the dependency in the target build environment.