Primeiros passos com o PDF Oxide (Clojure)
O PDF Oxide é o toolkit de PDF mais rápido com extração de texto embutida — média de 0,8ms e 100% de aprovação em 3.830 PDFs. O binding de Clojure é um wrapper idiomático e enxuto sobre o consolidado binding Java fyi.oxide:pdf-oxide, que é o dono da única ponte nativa via JNI. Ele não adiciona nenhum código nativo: chama as classes Java por interop e devolve valores amigáveis ao Clojure (java.util.List → vetor, java.util.Optional → valor ou nil).
Instalação
Adicione o binding Java ao seu deps.edn. O namespace Clojure (pdf_oxide.core) fica na sua árvore de código-fonte e faz o wrapping dele:
{:deps {fyi.oxide/pdf-oxide {:mvn/version "0.3.69"}}}
Os tipos de handle (Pdf, PdfDocument, DocumentEditor) são AutoCloseable, então use with-open para uma limpeza determinística.
Guia Rápido
Crie um PDF a partir de Markdown, abra-o de volta e extraia seu texto. Cada etapa retorna valores Clojure simples.
(require '[pdf-oxide.core :as pdf])
(with-open [p (pdf/from-markdown "# Hello\n\nbody\n")
d (pdf/open (pdf/save p))]
(println "pages: " (pdf/page-count d))
(println "producer:" (or (pdf/producer d) "(none)"))
(println (pdf/extract-text d 0)))
Abrindo um PDF
pdf/open aceita tanto um array de bytes quanto uma string com o caminho no sistema de arquivos, além de uma senha opcional para documentos criptografados.
(require '[pdf-oxide.core :as pdf])
;; A partir de um caminho
(with-open [d (pdf/open "research-paper.pdf")]
(println "pages:" (pdf/page-count d)))
;; A partir de bytes (ex.: baixados do S3 ou via HTTP)
(with-open [d (pdf/open pdf-bytes)]
(println (pdf/extract-text d 0)))
;; Documento criptografado
(with-open [d (pdf/open "confidential.pdf" "secret")]
(println (pdf/extract-text d 0)))
Você também pode autenticar depois de abrir:
(with-open [d (pdf/open "confidential.pdf")]
(when (pdf/authenticate d "secret")
(println (pdf/extract-text d 0))))
Extração de Texto
Extraia texto puro de qualquer página pelo seu índice começando em zero.
(require '[pdf-oxide.core :as pdf])
(with-open [d (pdf/open "report.pdf")]
;; Uma única página
(println (pdf/extract-text d 0))
;; Todas as páginas
(doseq [i (range (pdf/page-count d))]
(println "--- Page" (inc i) "---")
(println (pdf/extract-text d i))))
Elementos da Página
pdf/page retorna um PdfPage. A partir dele você pode obter palavras, linhas, caracteres, tabelas, imagens e anotações — cada um como um vetor Clojure. Os objetos de palavra/linha/caractere expõem .text e .bbox por interop.
(require '[pdf-oxide.core :as pdf])
(with-open [d (pdf/open "paper.pdf")]
(let [pg (pdf/page d 0)]
(println "page width:" (.width pg))
;; Palavras com suas bounding boxes
(doseq [w (take 8 (pdf/words pg))]
(println " " (.text w) "@" (.bbox w)))
;; Outros vetores de elementos
(println "lines: " (count (pdf/lines pg)))
(println "chars: " (count (pdf/chars pg)))
(println "tables: " (count (pdf/tables pg)))
(println "images: " (count (pdf/images pg)))
(println "annotations:" (count (pdf/annotations pg)))
;; Texto puro da página inteira, ou de uma região recortada (BBox)
(println (pdf/page-text pg))))
Para recortar a extração a uma região, passe um fyi.oxide.pdf.geometry.BBox:
(import '[fyi.oxide.pdf.geometry BBox])
(with-open [d (pdf/open "paper.pdf")]
(let [pg (pdf/page d 0)]
(println (pdf/page-text pg (BBox. 0.0 0.0 1000.0 1000.0)))))
Conversão para Markdown e HTML
Converta o documento inteiro ou uma única página para Markdown ou HTML.
(require '[pdf-oxide.core :as pdf])
(with-open [d (pdf/open "paper.pdf")]
;; Documento inteiro
(println (pdf/to-markdown d))
(println (pdf/to-html d))
;; Uma única página (começando em zero)
(println (pdf/to-markdown d 0))
(println (pdf/to-html d 0)))
Para uma estrutura mais rica, pdf/extract-structured retorna a árvore estruturada de elementos de uma página:
(with-open [d (pdf/open "paper.pdf")]
(println (pdf/extract-structured d 0)))
Busca
pdf/search varre o documento inteiro e retorna um vetor de objetos de correspondência. Cada correspondência expõe .text por interop.
(require '[pdf-oxide.core :as pdf])
(with-open [d (pdf/open "manual.pdf")]
(doseq [m (pdf/search d "configuration")]
(println (.text m))))
Renderização
Renderize uma página para um array de bytes PNG, opcionalmente em um DPI escolhido.
(require '[pdf-oxide.core :as pdf]
'[clojure.java.io :as io])
(with-open [d (pdf/open "paper.pdf")]
;; DPI padrão
(io/copy (pdf/render d 0) (io/file "page-0.png"))
;; DPI explícito
(io/copy (pdf/render d 0 150) (io/file "page-0@150.png")))
Criação
O tipo Pdf fornece funções de fábrica. pdf/save serializa um Pdf já construído para um array de bytes.
(require '[pdf-oxide.core :as pdf]
'[clojure.java.io :as io])
;; A partir de Markdown
(with-open [p (pdf/from-markdown "# Hello World\n\nThis is a PDF.")]
(io/copy (pdf/save p) (io/file "output.pdf")))
;; A partir de HTML
(with-open [p (pdf/from-html "<h1>Invoice</h1><p>Amount: $42</p>")]
(io/copy (pdf/save p) (io/file "invoice.pdf")))
Edição e Redação
pdf/editor abre um DocumentEditor (a partir de um array de bytes ou de um caminho) para edições estruturais. Limpe os metadados, marque regiões para redação e aplique-as de forma destrutiva, depois serialize com pdf/editor-save.
(require '[pdf-oxide.core :as pdf]
'[clojure.java.io :as io])
(import '[fyi.oxide.pdf.geometry BBox])
(with-open [ed (pdf/editor "form.pdf")]
(pdf/scrub-metadata ed)
(pdf/add-redaction ed 0 (BBox. 10.0 10.0 50.0 20.0))
(pdf/apply-redactions ed)
(io/copy (pdf/editor-save ed) (io/file "redacted.pdf")))
Metadados e Ciclo de Vida
pdf/producer e pdf/creator retornam os metadados do documento como um valor, ou nil quando ausentes (o java.util.Optional é desempacotado para você). Prefira with-open; pdf/close e pdf/open? são saídas de emergência para o gerenciamento manual do ciclo de vida.
(require '[pdf-oxide.core :as pdf])
(let [d (pdf/open "paper.pdf")]
(println "open? " (pdf/open? d))
(println "producer:" (or (pdf/producer d) "(none)"))
(println "creator: " (or (pdf/creator d) "(none)"))
(pdf/close d)
(println "open? " (pdf/open? d)))
Próximos Passos
- Primeiros passos com Java – o binding Java sobre o qual este wrapper é construído
- Extração de Texto – opções e receitas detalhadas de extração
- Criação de PDF – criação avançada com metadados e estilização
- Edição – modificando PDFs existentes, anotações e redação