Mejor crate PDF para Rust en 2026
PDF Oxide frente a los crates PDF más usados en Rust: lopdf, printpdf, pdf-rs y pdf_extract. Cada uno cubre un nivel de abstracción distinto y un conjunto distinto de casos de uso — esta página te ayuda a elegir el correcto para tu proyecto.
Resumen
| PDF Oxide | lopdf | printpdf | pdf-rs | pdf_extract | |
|---|---|---|---|---|---|
| Nivel de API | Alto nivel | Bajo nivel | Nivel medio (creación) | Bajo nivel (lectura) | Nivel medio (lectura) |
| Leer PDFs | Sí | Sí | No | Sí | Sí |
| Escribir PDFs | Sí | Sí | Sí | No | No |
| Extracción de texto | Sí (alto nivel) | Manual | No | Manual | Sí (básico) |
| Extracción de imágenes | Sí (alto nivel) | Manual | No | Manual | No |
| Campos de formulario | Lectura + Escritura | Manual | No | Solo lectura | No |
| Creación de PDF | Sí | Sí | Sí | No | No |
| Entrada Markdown/HTML | Sí | No | No | No | No |
| Edición de PDFs existentes | Sí | Sí (bajo nivel) | No | No | No |
| Anotaciones | Lectura + Escritura | Manual | No | Solo lectura | No |
| Cifrado | Lectura + Escritura | No | No | No | No |
| Validación PDF/A | Sí | No | No | No | No |
| Renderizado | Sí (tiny-skia) | No | No | Parcial | No |
| Bindings de Python | Sí | No | No | No | No |
| Licencia | MIT | MIT | MIT | MIT | Apache-2.0 |
Todas las bibliotecas tienen licencias permisivas. Las diferencias están en el alcance y el nivel de abstracción.
Comparación de rendimiento
Benchmark del corpus completo (3,830 PDFs)
Probado en el corpus completo de 3,830 PDFs — tres suites de prueba independientes y públicamente disponibles que cubren conformidad con la especificación PDF (veraPDF, 2,907 archivos), casos extremos de renderizado en navegadores del mundo real (Mozilla pdf.js, 897 archivos) y pruebas de estrés de seguridad/robustez incluyendo estructuras malformadas y corrupción generada por fuzzing (DARPA SafeDocs, 26 archivos). Ver detalles completos del corpus.
| Biblioteca | Promedio | p99 | Tasa de éxito | Extracción de texto | Notas |
|---|---|---|---|---|---|
| PDF Oxide | 0.8ms | 9ms | 100% | Integrada, nivel de producción | Unicode, CJK, orden de lectura |
| oxidize_pdf | 13.5ms | 11ms | 99.1% | Básica | Outlier máximo de 48s |
| unpdf | 2.8ms | 10ms | 95.1% | Básica | 185 fallos en el corpus completo |
| pdf_extract | 4.08ms | 37ms | 91.5% | Básica | Falla en layouts complejos |
| lopdf | 0.3ms | 2ms | 80.2% | Sin extracción integrada | Falla en 20% de los PDFs |
lopdf es más rápido en los PDFs que puede parsear — pero falla en el 20% del corpus y no proporciona extracción de texto. Necesitarías construir la decodificación de fuentes, resolución de CMap y análisis de espaciado por tu cuenta.
pdf_extract proporciona extracción de texto básica pero tiene una tasa de éxito del 91.5% y tiene dificultades con layouts complejos, texto CJK y PDFs etiquetados. oxidize_pdf tiene una confiabilidad decente (99.1%) pero es 17× más lento que pdf_oxide en el tiempo promedio de extracción, con un outlier de peor caso de 48 segundos. unpdf procesa el corpus completo pero falla en 185 PDFs.
PDF Oxide es el único crate de Rust que combina 100% de confiabilidad con extracción de texto a nivel de producción.
Comparación del diseño de API
PDF Oxide: Alto nivel, orientado a tareas
PDF Oxide proporciona métodos diseñados específicamente para tareas comunes. Trabajas con texto, imágenes y campos de formulario — no con objetos PDF y diccionarios.
use pdf_oxide::PdfDocument;
let mut doc = PdfDocument::open("report.pdf")?;
// Extracción de texto -- una llamada
let text = doc.extract_text(0)?;
println!("{}", text);
// Spans con estilo y metadatos de fuente
let spans = doc.extract_spans(0)?;
for span in &spans {
println!("'{}' font={} size={:.1}pt", span.text, span.font_name, span.font_size);
}
// Extracción de imágenes
let images = doc.extract_images(0)?;
for img in &images {
println!("{}x{} {:?}", img.width, img.height, img.format);
}
// Campos de formulario
let fields = doc.extract_form_fields()?;
for field in &fields {
println!("{}: {:?}", field.name, field.value);
}
La creación de PDFs es igualmente sencilla:
use pdf_oxide::api::Pdf;
// Desde Markdown
let pdf = Pdf::from_markdown("# Report\n\n| A | B |\n|---|---|\n| 1 | 2 |")?;
pdf.save("report.pdf")?;
// Desde HTML
let pdf = Pdf::from_html("<h1>Report</h1><p>Content here.</p>")?;
pdf.save("report.pdf")?;
lopdf: Manipulación de objetos de bajo nivel
lopdf te da acceso directo a objetos PDF, streams y la tabla de referencias cruzadas. Debes entender la especificación PDF para usarlo efectivamente. No hay extracción de texto integrada — navegas diccionarios y decodificas streams tú mismo.
use lopdf::Document;
let doc = Document::load("report.pdf")?;
// Obtener diccionario de página
let page_id = doc.page_iter().next().unwrap();
let page = doc.get_dictionary(page_id)?;
// Obtener content stream -- trabajo manual
let contents = page.get("Contents")?;
let stream = doc.get_object(contents.as_reference()?)?;
// Para extraer texto debes:
// 1. Parsear los operadores del content stream
// 2. Resolver referencias de fuentes desde /Resources
// 3. Decodificar mapeos CMap/ToUnicode
// 4. Aplicar transformaciones de matriz de texto
// 5. Manejar diferencias de codificación
//
// lopdf no proporciona nada de esto -- es acceso a objetos puros
println!("Page has {} objects", doc.objects.len());
lopdf es la herramienta correcta cuando necesitas manipular la estructura PDF directamente: fusionar documentos, reescribir streams de objetos o construir procesadores PDF especializados.
printpdf: Solo creación de PDF
printpdf es una biblioteca exclusivamente para creación. No puede leer ni parsear PDFs existentes. Proporciona una API tipada para construir documentos PDF desde cero con texto, imágenes y gráficos vectoriales.
use printpdf::*;
let (doc, page1, layer1) = PdfDocument::new(
"Report", Mm(210.0), Mm(297.0), "Layer 1"
);
let current_layer = doc.get_page(page1).get_layer(layer1);
// Agregar texto -- requiere carga manual de fuentes
let font = doc.add_builtin_font(BuiltinFont::Helvetica)?;
current_layer.use_text("Hello World", 24.0, Mm(10.0), Mm(280.0), &font);
// Guardar
doc.save(&mut std::io::BufWriter::new(
std::fs::File::create("output.pdf")?,
))?;
// No puede leer PDFs existentes
// No puede extraer texto, imágenes o campos de formulario
printpdf es la herramienta correcta cuando solo necesitas generar nuevos PDFs y quieres una API de creación limpia y enfocada.
pdf-rs: Lectura de PDF de bajo nivel
pdf-rs parsea la estructura PDF en tipos de Rust pero proporciona funcionalidad de alto nivel mínima. Obtienes acceso tipado a objetos PDF pero aún debes manejar la decodificación de texto, resolución de fuentes y parseo del content stream.
use pdf::file::FileOptions;
let file = FileOptions::cached().open("report.pdf")?;
// Acceder a objetos de página
let page = file.get_page(0)?;
let media_box = page.media_box()?;
println!("Page size: {:?}", media_box);
// Acceso a content stream -- bajo nivel
if let Some(ref contents) = page.contents {
// Retorna operaciones crudas -- debes interpretarlas
// Sin ensamblaje de texto integrado, decodificación de fuentes o análisis de layout
}
// No puede escribir ni modificar PDFs
pdf-rs es la herramienta correcta cuando necesitas un parser PDF tipado para análisis, validación o construir tu propio pipeline de renderizado.
Comparación de funciones por tarea
Extracción de texto
| Biblioteca | Integrada | Calidad | Esfuerzo requerido |
|---|---|---|---|
| PDF Oxide | Sí | Nivel de producción (Unicode, CJK, orden de lectura) | Una llamada a método |
| pdf_extract | Sí | Básica (falla en layouts complejos) | Una llamada a método |
| lopdf | No | N/A | Cientos de líneas de código personalizado |
| printpdf | No | N/A | No es posible (solo escritura) |
| pdf-rs | No | N/A | Código personalizado significativo requerido |
PDF Oxide maneja decodificación CMap/ToUnicode, espaciado basado en métricas de fuente, orden de lectura del árbol de estructura y reconstrucción de ligaduras. Implementar funcionalidad equivalente sobre lopdf o pdf-rs requiere miles de líneas de código y conocimiento profundo de la especificación PDF.
Creación de PDF
| Biblioteca | Enfoque | Entrada Markdown/HTML | Tablas | Códigos de barras |
|---|---|---|---|---|
| PDF Oxide | Alto nivel + bajo nivel | Sí | Sí | Sí |
| lopdf | Construcción cruda de objetos | No | No | No |
| printpdf | API de capas tipada | No | No | No |
| pdf-rs | N/A (solo lectura) | N/A | N/A | N/A |
Cifrado
| Biblioteca | Leer cifrado | Escribir cifrado | Algoritmos |
|---|---|---|---|
| PDF Oxide | Sí | Sí | RC4-40, RC4-128, AES-128, AES-256 |
| lopdf | No | No | – |
| printpdf | No | No | – |
| pdf-rs | Parcial | No | Solo RC4 |
Conformidad
| Biblioteca | PDF/A | PDF/X | PDF/UA |
|---|---|---|---|
| PDF Oxide | Validar + Convertir | Validar | Validar |
| lopdf | No | No | No |
| printpdf | Parcial (salida PDF/A-1b) | No | No |
| pdf-rs | No | No | No |
Huella de dependencias
| Biblioteca | Dependencias | Tiempo de compilación | Tamaño del binario |
|---|---|---|---|
| PDF Oxide | ~40 (núcleo) | ~30s | ~4 MB |
| lopdf | ~15 | ~10s | ~1 MB |
| printpdf | ~20 | ~15s | ~2 MB |
| pdf-rs | ~25 | ~20s | ~2 MB |
PDF Oxide tiene más dependencias porque incluye parseo de fuentes, decodificación de imágenes, interpretación de content streams y cifrado — funciones que las otras bibliotecas dejan al usuario u omiten por completo. Con todas las funciones opcionales (rendering, barcodes, office), la cuenta sube a ~100.
Combinando bibliotecas
Dado que todas tienen licencias permisivas, puedes combinarlas en un solo proyecto:
[dependencies]
pdf_oxide = "0.3"
lopdf = "0.32" # Opcional: acceso a objetos crudos para casos extremos
Patrones comunes:
- PDF Oxide + lopdf: Usa PDF Oxide para extracción y creación, recurre a lopdf para casos extremos que requieren manipulación cruda de objetos.
- PDF Oxide + printpdf: Usa PDF Oxide para lectura y printpdf para flujos de trabajo de creación especializados.
Matriz de casos de uso
“Necesito extraer texto de PDFs”
| Crate | ¿Adecuado? | Notas |
|---|---|---|
| PDF Oxide | Sí | Mejor calidad de extracción, 100% tasa de éxito, orden de lectura, metadatos de fuente |
| pdf_extract | Parcial | Extracción básica, 91.5% tasa de éxito |
| lopdf | No | Sin extracción de texto |
| printpdf | No | No puede leer PDFs |
| pdf-rs | Parcial | Parseo básico, sin extracción de texto de alto nivel |
“Necesito crear PDFs”
| Crate | ¿Adecuado? | Notas |
|---|---|---|
| PDF Oxide | Sí | APIs de alto nivel (Markdown/HTML) y bajo nivel |
| lopdf | Parcial | Construcción de objetos de bajo nivel |
| printpdf | Sí | API de creación limpia, sin lectura |
| pdf-rs | No | Solo lectura |
“Necesito editar PDFs existentes”
| Crate | ¿Adecuado? | Notas |
|---|---|---|
| PDF Oxide | Sí | Edición tipo DOM, anotaciones, formularios |
| lopdf | Parcial | Manipulación de objetos de bajo nivel |
| printpdf | No | No puede leer PDFs |
| pdf-rs | No | Solo lectura |
“Necesito el ciclo de vida completo (extraer + crear + editar)”
| Crate | ¿Adecuado? | Notas |
|---|---|---|
| PDF Oxide | Sí | Único crate que cubre los tres |
| lopdf + printpdf | Parcial | Dos crates, sin extracción de texto |
| pdf-rs + printpdf | Parcial | Dos crates, sin edición |
Cuándo usar cada uno
Elige PDF Oxide si necesitas más de una capacidad PDF (extracción + creación, o extracción + edición) y quieres una única dependencia bien probada con 100% de confiabilidad.
Elige lopdf si necesitas manipulación de estructura PDF de bajo nivel y te sientes cómodo trabajando directamente con la especificación PDF. Bueno para fusionar, dividir y procesamiento por lotes de PDFs.
Elige printpdf si solo creas PDFs y nunca necesitas leerlos. La API más limpia para generación de informes y documentos.
Elige pdf-rs si necesitas un parser conforme a la especificación para análisis PDF o estás construyendo tu propio pipeline de renderizado.
Elige pdf_extract si necesitas extracción de texto básica y no requieres alta confiabilidad o soporte de layouts complejos.
Páginas relacionadas
- Benchmarks de rendimiento – resultados completos de benchmark del corpus
- Primeros pasos con Rust – instalación y primera extracción
- Referencia de API Rust – API completa de Rust
- vs Bibliotecas PDF para Python – comparación del ecosistema Python