Extracting text

View Source

Use NativeElixirPdfUtilities.Text to read embedded text. It does not perform OCR on scanned pages.

Reconstructed strings

alias NativeElixirPdfUtilities.Text

{:ok, text} = Text.extract_file("invoice.pdf")

For a binary already in memory, use Text.extract(pdf).

OptionResult
layout: true, the defaultApproximate visual lines and spacing; text pages separated by "\f"
layout: falseText in drawing order; text pages separated by "\n"

Both omit pages with no painted text. A document with no extractable painted text returns :no_extractable_text. Extraction fails if shown text cannot be decoded reliably; it does not return a partial result.

Positioned text

Use spans when you need to interpret columns, rows, or other document-specific layout:

{:ok, document} = Text.extract_file_spans("invoice.pdf")

Enum.each(document.pages, fn page ->
  Enum.each(page.spans, fn span ->
    IO.inspect({page.number, span.text, span.x, span.y})
  end)
end)

For a binary, use Text.extract_spans(pdf). The result contains :page_count and :pages. Every page is retained, even if its :spans list is empty. Each page has :number, :media_box, :rotation, and :spans.

Span fields

FieldMeaning
:textDecoded text
:x, :yStart of the text baseline
:end_x, :end_yEnd of the baseline, based on text advance
:source_indexZero-based drawing-order index within the page
:font_resourcePDF font resource name, not necessarily a family name
:font_sizeFont size in PDF text space
:text_matrix, :ctmOriginal text and current transformation matrices
:render_modePDF text rendering mode, from 0 through 7
:paints_text?Whether the mode requests filled or stroked text
:adds_to_clip_path?Whether the mode adds text to the clipping path
:joins_previous?Whether this text continues the preceding showing operation

Coordinates start at the top-left of the rotated MediaBox. X increases right; Y increases down. They use PDF default user-space units, normally 1/72 inch. CropBox offsets and UserUnit scaling are not applied. Baselines are not glyph bounding boxes, and endpoints can be approximate when font widths are absent.

These coordinates differ from stamp coordinates. Use Info.page_sizes/1 for physical page dimensions.

Source and visual order

Span order defaults to :source. Request order: :visual for approximate line grouping:

{:ok, document} = Text.extract_spans(pdf, order: :visual)

source_index stays unchanged, so you can restore drawing order by sorting on it. It is an ordering key, not a persistent identifier across edited PDFs. Neither order identifies semantic table cells automatically.

Rendering modes and visibility

Spans include invisible text modes 3 and 7. String extraction excludes them. The :paints_text? flag describes the drawing mode, not guaranteed visibility: text may still be hidden by clipping, transparency, or other content.

Errors and limits

Unsupported font encodings, vertical Type0 CMaps, inherited usecmap mappings, and inline images can prevent extraction. Encrypted PDFs are not supported. Failures use the diagnostic tuple.

Extraction limits cap content, work, spans, and reconstructed spacing. Oversized numeric operands or font metrics return :invalid_pdf_input before execution. No partial text is returned on failure.