NativeElixirPdfUtilities.Text (native_elixir_pdf_utilities v0.6.0)

View Source

Strict native extraction of embedded Unicode text from PDF documents.

Extraction resolves the PDF page tree, resources, content streams, Form XObjects, and the active font at every text operation. It succeeds only when every shown text string has a reliable Unicode mapping; it never guesses from an embedded font program or merges CMaps from unrelated fonts.

PDFs store positioned text operations, not semantic rows, columns, or tables. extract_spans/2 exposes those decoded operations for callers that need to interpret document-specific structure. extract/2 remains a string projection: layout: true reconstructs approximate visual lines, while layout: false projects text-show execution order.

Extraction does not perform OCR. Successfully decoded text can be recovered even when its rendering mode does not paint the text, but clipping paths, transparency, occlusion, and other causes of visual visibility are not evaluated.

Summary

Types

Options for reconstructed string extraction.

A six-value PDF affine matrix in [a, b, c, d, e, f] order.

A PDF text rendering mode from 0 through 7.

Options for positioned span extraction.

A page-preserving positioned-text extraction result.

Positioned text for one resolved PDF page.

A decoded text-showing operand and its positioned extraction context.

Functions

Extracts reliably decodable embedded text from a PDF binary.

Reads a PDF file and extracts reliably decodable embedded text from it.

Reads a PDF file and extracts its page-preserving positioned text spans.

Extracts positioned, reliably decoded text spans from a PDF binary.

Types

error_reason()

@type error_reason() ::
  :encrypted_pdf
  | :invalid_options
  | :invalid_path
  | :invalid_pdf_input
  | :no_extractable_text
  | :resource_limit_exceeded
  | :unsupported_pdf_feature
  | :unsupported_text_encoding
  | File.posix()

extract_option()

@type extract_option() :: {:layout, boolean()}

Options for reconstructed string extraction.

matrix()

@type matrix() :: [float()]

A six-value PDF affine matrix in [a, b, c, d, e, f] order.

render_mode()

@type render_mode() :: 0..7

A PDF text rendering mode from 0 through 7.

span_option()

@type span_option() :: {:order, :source | :visual}

Options for positioned span extraction.

text_document()

@type text_document() :: %{page_count: non_neg_integer(), pages: [text_page()]}

A page-preserving positioned-text extraction result.

text_page()

@type text_page() :: %{
  number: pos_integer(),
  media_box: [number()],
  rotation: 0 | 90 | 180 | 270,
  spans: [text_span()]
}

Positioned text for one resolved PDF page.

media_box is [left, bottom, right, top] in PDF default user-space units. rotation is the effective inherited page rotation normalized to 0, 90, 180, or 270 degrees. Every resolved page is returned, including pages whose spans list is empty.

text_span()

@type text_span() :: %{
  text: String.t(),
  source_index: non_neg_integer(),
  x: float(),
  y: float(),
  end_x: float(),
  end_y: float(),
  font_resource: String.t(),
  font_size: float(),
  text_matrix: matrix(),
  ctm: matrix(),
  render_mode: render_mode(),
  paints_text?: boolean(),
  adds_to_clip_path?: boolean(),
  joins_previous?: boolean()
}

A decoded text-showing operand and its positioned extraction context.

source_index is zero-based within a page and follows text-show execution order. Page content streams are traversed in /Contents order, and Form XObjects are traversed where their Do operator occurs. Reusing a Form therefore produces new spans with new indexes.

x, y, end_x, and end_y describe the text baseline in normalized display coordinates. The origin is the top-left of the rotated MediaBox, X increases rightward, Y increases downward, and page rotation and Form CTMs are applied. These points are not glyph bounding boxes. The end point uses the PDF font widths available to the extractor and can be approximate when a font omits explicit metrics.

text_matrix is the PDF text matrix at the start of the operand. ctm is the active PDF current transformation matrix, including Form transforms. Neither matrix includes the final MediaBox/page-rotation normalization represented by the baseline coordinates.

font_resource is the active PDF resource name, not a guaranteed font family or PostScript name. font_size is the Tf text-space size, not a calculated display-space height.

paints_text? and adds_to_clip_path? are derived only from render_mode. They describe the requested PDF text rendering operation; they do not claim that the text is visually visible or clipped. joins_previous? identifies a later string operand from the same TJ array, preserving the existing source-order string projection behavior.

Functions

extract(pdf_binary, opts \\ [])

@spec extract(binary(), [extract_option()]) ::
  {:ok, String.t()}
  | {:error,
     {error_reason(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Extracts reliably decodable embedded text from a PDF binary.

Set layout: true (the default) to group spans into approximate visual lines. With layout: false, spans retain their content-stream order. Extraction fails rather than returning partial text when a shown text operation cannot be decoded with the active font.

extract_file(path, opts \\ [])

@spec extract_file(String.t(), [extract_option()]) ::
  {:ok, String.t()}
  | {:error,
     {error_reason(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Reads a PDF file and extracts reliably decodable embedded text from it.

extract_file_spans(path, opts \\ [])

@spec extract_file_spans(String.t(), [span_option()]) ::
  {:ok, text_document()}
  | {:error,
     {error_reason(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Reads a PDF file and extracts its page-preserving positioned text spans.

This has the same ordering, geometry, preservation, and strict diagnostic behavior as extract_spans/2. File extraction errors include the source path.

extract_spans(pdf_binary, opts \\ [])

@spec extract_spans(binary(), [span_option()]) ::
  {:ok, text_document()}
  | {:error,
     {error_reason(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Extracts positioned, reliably decoded text spans from a PDF binary.

The result preserves every resolved page and every non-empty text operand that can be decoded, including rendering modes 3 (neither painted nor added to the clipping path) and 7 (added to the clipping path without painting). This preservation guarantee applies to decoded text operations, not to OCR, undecodable fonts, glyph outlines, semantic tables, or evaluated visual visibility.

Spans use source execution order by default. Set order: :visual to return a best-effort display ordering using the same line grouping as extract/2; source_index remains unchanged so source order can always be restored.

A valid PDF with no decodable text returns an :ok document containing empty page span lists. Extraction remains strict and returns a structured error rather than a partial document when a shown string cannot be decoded.