Primeros pasos con PDF Oxide ®
PDF Oxide ofrece bindings idiomáticos para R que extraen texto, Markdown y HTML de PDF a gran velocidad: 0,8 ms de media en la extracción de texto y 100 % de aciertos sobre 3830 PDF, todo respaldado por el mismo núcleo Rust que el resto de bindings. El paquete de R envuelve la C ABI de pdf_oxide a través de la interfaz .Call de R; los handles de documento son punteros externos de R que libera el recolector de basura, y los índices de página empiezan en 0 para coincidir con el motor subyacente.
Instalación
El paquete de R enlaza con la cdylib que incluye las features por defecto. Compila la biblioteca nativa y luego instala el paquete indicándole dónde están la cabecera y la cdylib:
# 1. compila la biblioteca nativa (conjunto de features del binding)
cargo build --release --lib \
--features ocr,rendering,signatures,barcodes,tsa-client,system-fonts
# 2. instala el paquete de R
PDF_OXIDE_INCLUDE_DIR="$PWD/include" PDF_OXIDE_LIB_DIR="$PWD/target/release" \
R CMD INSTALL r/
En tiempo de ejecución, haz que el enlazador pueda localizar la cdylib:
LD_LIBRARY_PATH="$PWD/target/release" Rscript your_script.R
Abrir un PDF
Abre un archivo con pdf_open() y luego inspecciona sus metadatos. pdf_version() devuelve una lista con nombres con major y minor.
library(pdfoxide)
doc <- pdf_open("research-paper.pdf")
pdf_page_count(doc) # número de páginas
v <- pdf_version(doc)
cat("PDF version:", paste(v$major, v$minor, sep = "."), "\n")
pdf_is_encrypted(doc) # lógico
Extracción de texto
Extrae el texto en orden de lectura de una sola página (índice basado en 0) con pdf_extract_text().
library(pdfoxide)
doc <- pdf_open("report.pdf")
text <- pdf_extract_text(doc, 0) # índice de página basado en 0
cat(text)
Recorre todas las páginas con pdf_page_count():
doc <- pdf_open("book.pdf")
for (page in seq_len(pdf_page_count(doc)) - 1L) { # índices basados en 0
cat("--- Page", page + 1L, "---\n")
cat(pdf_extract_text(doc, page), "\n")
}
Markdown y HTML
Convierte una sola página a Markdown o HTML, o convierte el documento completo de una vez.
library(pdfoxide)
doc <- pdf_open("paper.pdf")
md <- pdf_to_markdown(doc, 0) # una página como Markdown
html <- pdf_to_html(doc, 0) # una página como HTML
all_md <- pdf_to_markdown_all(doc) # documento completo
all_text <- pdf_to_plain_text_all(doc) # documento completo, texto plano
cat(all_md)
Palabras, caracteres y líneas
La extracción de elementos devuelve listas de registros con cajas delimitadoras posicionales. Cada bbox es una lista con nombres que contiene x, y, width y height.
library(pdfoxide)
doc <- pdf_open("paper.pdf")
# Palabras posicionadas — cada una tiene $text, $bbox, $font_name, $font_size, $bold
words <- pdf_extract_words(doc, 0)
for (w in head(words, 10)) {
cat(sprintf("'%s' at (%.1f, %.1f) font=%s bold=%s\n",
w$text, w$bbox$x, w$bbox$y, w$font_name, w$bold))
}
# Líneas en orden de lectura — cada una tiene $text, $bbox, $word_count
lines <- pdf_extract_text_lines(doc, 0)
for (ln in head(lines, 5)) {
cat(sprintf("[%d words] %s\n", ln$word_count, ln$text))
}
# Caracteres posicionados — $character es el codepoint Unicode (entero)
chars <- pdf_extract_chars(doc, 0)
for (ch in head(chars, 10)) {
cat(sprintf("'%s' at (%.1f, %.1f) size=%.1f\n",
intToUtf8(ch$character), ch$bbox$x, ch$bbox$y, ch$font_size))
}
Tablas
pdf_extract_tables() devuelve las tablas detectadas. Cada registro de tabla incluye row_count, col_count, has_header y una matriz de caracteres cells indexada en base 1 como tbl$cells[row, col].
library(pdfoxide)
doc <- pdf_open("statement.pdf")
tables <- pdf_extract_tables(doc, 0)
for (tbl in tables) {
cat(sprintf("Table: %d rows x %d cols (header=%s)\n",
tbl$row_count, tbl$col_count, tbl$has_header))
for (r in seq_len(tbl$row_count)) {
cat(paste(tbl$cells[r, ], collapse = " | "), "\n")
}
}
Búsqueda
Busca en una sola página con pdf_search(), o en el documento completo con pdf_search_all(). Ambas aceptan un parámetro opcional case_sensitive (por defecto FALSE) y devuelven registros con text, page y bbox.
library(pdfoxide)
doc <- pdf_open("manual.pdf")
# Documento completo
hits <- pdf_search_all(doc, "configuration")
for (h in hits) {
cat(sprintf("Page %d: '%s' at (%.0f, %.0f)\n",
h$page, h$text, h$bbox$x, h$bbox$y))
}
# Una sola página, distinguiendo mayúsculas y minúsculas
page_hits <- pdf_search(doc, 0, "Configuration", case_sensitive = TRUE)
Abrir desde bytes
Abre un PDF que tienes en memoria —práctico al leer desde S3, HTTP o una base de datos— con pdf_open_from_bytes(), que recibe un vector raw.
library(pdfoxide)
bytes <- readBin("report.pdf", "raw", file.info("report.pdf")$size)
doc <- pdf_open_from_bytes(bytes)
cat(pdf_extract_text(doc, 0))
PDF protegidos con contraseña
Abre un documento cifrado con pdf_open_with_password(), o llama a pdf_authenticate() después de abrirlo (devuelve TRUE si tiene éxito y FALSE si la contraseña es incorrecta).
library(pdfoxide)
doc <- pdf_open_with_password("confidential.pdf", "secret")
cat(pdf_extract_text(doc, 0))
Crear PDF
Las funciones constructoras crean un pdfoxide_pdf a partir de Markdown, HTML o texto plano. Guárdalo en una ruta con pdf_save(), o serialízalo a un vector raw con pdf_to_bytes() (que puede volver a abrirse con pdf_open_from_bytes()).
library(pdfoxide)
pdf <- pdf_from_markdown("# Hello World\n\nThis is a PDF.\n")
pdf_save(pdf, "output.pdf")
pdf_from_html("<h1>Invoice</h1><p>Amount due: $42.00</p>") |>
pdf_save("invoice.pdf")
pdf_from_text("Plain text document.\n\nSecond paragraph.") |>
pdf_save("notes.pdf")
# Ida y vuelta a través de bytes
bytes <- pdf_to_bytes(pdf_from_markdown("# In memory\n\nbody\n"))
doc <- pdf_open_from_bytes(bytes)
cat(pdf_extract_text(doc, 0))
Siguientes pasos
- Primeros pasos con Python – usar PDF Oxide desde Python
- Primeros pasos con Rust – el crate de Rust subyacente
- Extracción de texto – opciones y recetas detalladas de extracción
- Creación de PDF – creación avanzada con constructores, cifrado y metadatos