Inspects PDFs and extracts their content through the pdf-inspector crate.
The functions accept either a file path or the PDF contents as a binary. The result identifies the document type, the pages that need OCR, and, when requested, the extracted Markdown.
{:ok, result} = ExPdfInspector.process_pdf("document.pdf")
result.pdf_type
#=> :text_based
result.markdown
#=> "# Document title..."
When reading or processing fails, the function returns {:error, error}.
The error map contains the :code and :message fields. Error codes are
stable library-defined atoms, so callers can safely pattern match on them.
Summary
Types
An error returned while reading or processing a PDF.
A stable code identifying an error returned by the PDF library.
The type of a positioned item extracted from a PDF.
Information about the layout complexity.
The reasons why a page needs OCR.
Markdown extracted from one page.
The result of extracting Markdown by page.
The result of inspecting or processing a PDF.
The type identified for a PDF.
A rectangle associated with an element on a page.
A text item or another element positioned on a page.
Functions
Detects the type of a PDF without extracting Markdown.
Detects the type of a PDF provided as a binary without extracting Markdown.
Extracts Markdown for each page from a PDF file.
Extracts Markdown for each page from a PDF provided as a binary.
Extracts plain text from every page of a PDF.
Extracts text together with its position, font, and style information.
Processes the PDF at path.
Processes a PDF provided as a binary.
Converts plain text to Markdown using the provided options.
Converts positioned items to Markdown.
Converts positioned items to Markdown while considering geometric rectangles.
Types
@type error() :: %{code: error_code(), message: String.t()}
An error returned while reading or processing a PDF.
@type error_code() ::
:io_error | :not_a_pdf | :invalid_structure | :parse_error | :encrypted
A stable code identifying an error returned by the PDF library.
@type item_type() :: :text | :image | :form_field | {:link, String.t()}
The type of a positioned item extracted from a PDF.
@type layout() :: %{ is_complex: boolean(), pages_with_tables: [non_neg_integer()], pages_with_columns: [non_neg_integer()] }
Information about the layout complexity.
@type ocr_reasons() :: %{page: non_neg_integer(), reasons: [String.t()]}
The reasons why a page needs OCR.
@type page_markdown() :: %{ page: non_neg_integer(), markdown: String.t(), needs_ocr: boolean(), ocr_reason: String.t() | nil }
Markdown extracted from one page.
@type pages_result() :: %{ pages: [page_markdown()], pages_with_tables: [non_neg_integer()], pages_with_columns: [non_neg_integer()], pages_needing_ocr: [non_neg_integer()], ocr_reasons_by_page: [ocr_reasons()], is_complex: boolean() }
The result of extracting Markdown by page.
@type pdf_result() :: %{ pdf_type: pdf_type(), markdown: String.t() | nil, page_count: non_neg_integer(), processing_time_ms: non_neg_integer(), pages_needing_ocr: [non_neg_integer()], ocr_reasons_by_page: [ocr_reasons()], title: String.t() | nil, confidence: float(), layout: layout(), has_encoding_issues: boolean() }
The result of inspecting or processing a PDF.
@type pdf_type() :: :text_based | :scanned | :image_based | :mixed
The type identified for a PDF.
@type rect() :: %{ x: float(), y: float(), width: float(), height: float(), page: non_neg_integer() }
A rectangle associated with an element on a page.
@type result(value) :: {:ok, value} | {:error, error()}
@type text_item() :: %{ text: String.t(), x: float(), y: float(), width: float(), height: float(), font: String.t(), font_size: float(), page: non_neg_integer(), is_bold: boolean(), is_italic: boolean(), is_underline: boolean(), is_strikeout: boolean(), item_type: item_type(), mcid: integer() | nil }
A text item or another element positioned on a page.
Functions
@spec detect_pdf(String.t()) :: result(pdf_result())
Detects the type of a PDF without extracting Markdown.
{:ok, result} = ExPdfInspector.detect_pdf("document.pdf")
result.pdf_type
#=> :text_based
@spec detect_pdf_bytes(binary()) :: result(pdf_result())
Detects the type of a PDF provided as a binary without extracting Markdown.
bytes = File.read!("document.pdf")
{:ok, %{markdown: nil}} = ExPdfInspector.detect_pdf_bytes(bytes)
@spec extract_pages_markdown(String.t(), [non_neg_integer()] | nil) :: result(pages_result())
Extracts Markdown for each page from a PDF file.
Pass nil to extract every page, or pass a list of zero-based page indexes:
{:ok, result} = ExPdfInspector.extract_pages_markdown("document.pdf", [0, 2])
Enum.map(result.pages, & &1.page)
#=> [0, 2]
@spec extract_pages_markdown_bytes(binary(), [non_neg_integer()] | nil) :: result(pages_result())
Extracts Markdown for each page from a PDF provided as a binary.
bytes = File.read!("document.pdf")
{:ok, result} = ExPdfInspector.extract_pages_markdown_bytes(bytes, nil)
length(result.pages)
#=> 3
Extracts plain text from every page of a PDF.
{:ok, text} = ExPdfInspector.extract_text("document.pdf")
String.contains?(text, "Introduction")
#=> true
Extracts text together with its position, font, and style information.
{:ok, [item | _]} = ExPdfInspector.extract_text_with_positions("document.pdf")
{item.text, item.page, item.font_size}
#=> {"Title", 1, 24.0}
@spec process_pdf(String.t()) :: result(pdf_result())
Processes the PDF at path.
Without options, it detects and analyzes the document and extracts Markdown.
{:ok, result} = ExPdfInspector.process_pdf("document.pdf")
result.page_count
#=> 3Pass PdfOptions to control the processing steps:
options = %ExPdfInspector.PdfOptions{mode: :detect_only}
{:ok, result} = ExPdfInspector.process_pdf("document.pdf", options)
result.markdown
#=> nil
@spec process_pdf(String.t(), ExPdfInspector.PdfOptions.t()) :: result(pdf_result())
@spec process_pdf_bytes(binary()) :: result(pdf_result())
Processes a PDF provided as a binary.
bytes = File.read!("document.pdf")
{:ok, result} = ExPdfInspector.process_pdf_bytes(bytes)Processing options can also be provided:
options = %ExPdfInspector.PdfOptions{page_filter: [0]}
{:ok, result} = ExPdfInspector.process_pdf_bytes(bytes, options)
@spec process_pdf_bytes(binary(), ExPdfInspector.PdfOptions.t()) :: result(pdf_result())
@spec to_markdown(String.t(), ExPdfInspector.MarkdownOptions.t()) :: String.t()
Converts plain text to Markdown using the provided options.
options = %ExPdfInspector.MarkdownOptions{profile: :compact}
ExPdfInspector.to_markdown("TITLEContent", options)
#=> "TITLEContent "
@spec to_markdown_from_items([text_item()], ExPdfInspector.MarkdownOptions.t()) :: String.t()
Converts positioned items to Markdown.
item = %{
text: "Hello", x: 10.0, y: 20.0, width: 30.0, height: 12.0,
font: "Helvetica", font_size: 12.0, page: 0,
is_bold: false, is_italic: false, is_underline: false,
is_strikeout: false, item_type: :text, mcid: nil
}
ExPdfInspector.to_markdown_from_items([item], %ExPdfInspector.MarkdownOptions{})
#=> "Hello"
@spec to_markdown_from_items_with_rects( [text_item()], ExPdfInspector.MarkdownOptions.t(), [rect()] ) :: String.t()
Converts positioned items to Markdown while considering geometric rectangles.
Rectangles help identify visual elements such as underlines:
rect = %{x: 10.0, y: 20.0, width: 80.0, height: 1.0, page: 0}
ExPdfInspector.to_markdown_from_items_with_rects(items, options, [rect])