Primeiros passos com o PDF Oxide (Elixir)
O PDF Oxide é a forma mais rápida de ler e gerar PDFs a partir de Elixir — extração de texto em 0,8ms na média e 100% de aprovação em 3.830 PDFs. É um NIF sobre o mesmo núcleo em Rust, que executa o trabalho intensivo de CPU em dirty CPU schedulers (ERL_NIF_DIRTY_JOB_CPU_BOUND), de modo que nunca bloqueia o scheduler da BEAM.
Os handles de Document e Pdf são recursos NIF liberados pelo GC. Funções que podem falhar retornam {:ok, value} ou {:error, code}, e os índices de página começam em 0.
Instalação
Adicione pdf_oxide às dependências do seu mix.exs:
def deps do
[
{:pdf_oxide, "~> 0.3"}
]
end
Em seguida, baixe e compile — o NIF é construído via elixir_make a partir da cdylib nativa:
mix deps.get
mix compile
Guia Rápido
Crie um PDF a partir de Markdown, serialize-o em bytes, depois abra-o e extraia o texto de volta.
{:ok, pdf} = PdfOxide.from_markdown("# Hello pdf_oxide\n\nThis is an **Elixir** binding.\n")
{:ok, bytes} = PdfOxide.to_bytes(pdf)
{:ok, doc} = PdfOxide.open_from_bytes(bytes)
{:ok, pages} = PdfOxide.page_count(doc)
IO.puts("pages: #{pages}")
%{major: maj, minor: min} = PdfOxide.version(doc)
IO.puts("version: #{maj}.#{min}")
{:ok, text} = PdfOxide.extract_text(doc, 0)
IO.puts(text)
Abrindo um PDF
Abra a partir de um caminho de arquivo, ou diretamente a partir de bytes na memória (útil quando você recebe dados via streaming do S3, HTTP ou de um banco de dados):
# A partir de um caminho
{:ok, doc} = PdfOxide.open("report.pdf")
# A partir de bytes já presentes na memória
{:ok, doc} = PdfOxide.open_from_bytes(pdf_bytes)
# Documentos criptografados
{:ok, doc} = PdfOxide.open_with_password("confidential.pdf", "secret")
# Inspeção
{:ok, count} = PdfOxide.page_count(doc)
encrypted? = PdfOxide.encrypted?(doc)
Feche um documento explicitamente quando terminar (close/1 é idempotente), ou deixe o GC liberá-lo:
:ok = PdfOxide.close(doc)
Extração de Texto
Extraia texto puro de uma única página pelo seu índice (começando em zero), ou puxe o documento inteiro de uma vez:
{:ok, doc} = PdfOxide.open("book.pdf")
# Uma única página
{:ok, text} = PdfOxide.extract_text(doc, 0)
# Texto puro, uma página
{:ok, pt} = PdfOxide.to_plain_text(doc, 0)
# Todas as páginas, concatenadas
{:ok, all} = PdfOxide.to_plain_text_all(doc)
IO.puts(all)
Conversão para Markdown e HTML
Converta uma página — ou o documento inteiro — para Markdown ou HTML:
{:ok, doc} = PdfOxide.open("paper.pdf")
{:ok, md} = PdfOxide.to_markdown(doc, 0)
{:ok, mdall} = PdfOxide.to_markdown_all(doc)
{:ok, html} = PdfOxide.to_html(doc, 0)
{:ok, htmlall} = PdfOxide.to_html_all(doc)
Palavras e Linhas
extract_words/2 retorna structs PdfOxide.Word estruturados, com uma bounding box e uma flag bold; extract_text_lines/2 os agrupa em linhas.
{:ok, doc} = PdfOxide.open("paper.pdf")
{:ok, words} = PdfOxide.extract_words(doc, 0)
for w <- Enum.take(words, 10) do
%PdfOxide.Bbox{x: x, y: y, width: width} = w.bbox
IO.puts("#{w.text} at (#{x}, #{y}) w=#{width} bold=#{w.bold}")
end
{:ok, lines} = PdfOxide.extract_text_lines(doc, 0)
for line <- lines do
IO.puts("#{line.word_count} words: #{line.text}")
end
Busca
Busque em uma única página, ou em todo o documento. O quarto argumento é case_sensitive. Cada resultado traz text, page e uma PdfOxide.Bbox.
{:ok, doc} = PdfOxide.open("manual.pdf")
# Uma página (índice de página 0), sem diferenciar maiúsculas de minúsculas
{:ok, results} = PdfOxide.search(doc, 0, "configuration", false)
for r <- results do
%PdfOxide.Bbox{x: x, y: y} = r.bbox
IO.puts("page #{r.page}: '#{r.text}' at (#{x}, #{y})")
end
# Todas as páginas
{:ok, all} = PdfOxide.search_all(doc, "configuration", false)
IO.puts("#{length(all)} matches")
Criação de PDF
As funções de fábrica do builder retornam um handle Pdf que você serializa com to_bytes/1 ou grava diretamente em disco com save/2:
{:ok, pdf} = PdfOxide.from_markdown("# Hello World\n\nThis is a PDF.")
:ok = PdfOxide.save(pdf, "output.pdf")
{:ok, pdf} = PdfOxide.from_html("<h1>Invoice</h1><p>Amount: $42</p>")
{:ok, bytes} = PdfOxide.to_bytes(pdf)
{:ok, pdf} = PdfOxide.from_text("Plain text content.")
:ok = PdfOxide.save(pdf, "notes.pdf")
Renderizando Páginas como Imagens
Com a feature de renderização, rasterize uma página em uma PdfOxide.RenderedImage e salve-a como PNG:
{:ok, doc} = PdfOxide.open("paper.pdf")
{:ok, img} = PdfOxide.render_page(doc, 0)
IO.puts("#{img.width}x#{img.height}, #{byte_size(img.data)} bytes")
:ok = PdfOxide.save(img, "page0.png")
# Fator de zoom, ou uma miniatura de tamanho fixo
{:ok, zoomed} = PdfOxide.render_page_zoom(doc, 0, 2.0)
{:ok, thumb} = PdfOxide.render_page_thumbnail(doc, 0, 128)
Tratamento de Erros
Funções que podem falhar retornam uma tupla com tag — use pattern matching para um fluxo de controle limpo:
case PdfOxide.open("/nonexistent/nope.pdf") do
{:ok, doc} ->
{:ok, text} = PdfOxide.extract_text(doc, 0)
IO.puts(text)
{:error, code} ->
IO.puts("could not open PDF: #{inspect(code)}")
end
Próximos Passos
- Primeiros passos com Rust — usando o PDF Oxide a partir de Rust
- Primeiros passos com Python — usando o PDF Oxide a partir de Python
- Extração de Texto — opções e receitas detalhadas de extração
- Criação de PDF — criação avançada com metadados e criptografia
- Edição — modificando PDFs existentes, anotações e campos de formulário