vs. Bibliotecas PDF para Rust
PDF Oxide comparado con las crates PDF para Rust más usadas: lopdf, printpdf, pdf-rs y pdf_extract. Cada una apunta a un nivel de abstracción distinto y a un conjunto diferente de casos de uso.
Resumen
| PDF Oxide | lopdf | printpdf | pdf-rs | pdf_extract | |
|---|---|---|---|---|---|
| Nivel de API | Alto nivel | Bajo nivel | Nivel intermedio (creación) | Bajo nivel (lectura) | Nivel intermedio (lectura) |
| Leer PDF | Sí | Sí | No | Sí | Sí |
| Escribir PDF | Sí | Sí | Sí | No | No |
| Extracción de texto | Sí (alto nivel) | Manual | No | Manual | Sí (básica) |
| 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 |
| Editar PDF 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 para 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 PDF)
Probado sobre el corpus completo de 3.830 PDF: tres suites de prueba independientes y de acceso público que cubren la conformidad con la especificación PDF (veraPDF, 2.907 archivos), casos límite de renderizado en navegadores del mundo real (Mozilla pdf.js, 897 archivos) y pruebas de estrés de seguridad y robustez, incluidas estructuras malformadas y corrupción generada por fuzzing (DARPA SafeDocs, 26 archivos). Consulta los detalles del corpus completo.
| Biblioteca | Media | p99 | Tasa de éxito | Extracción de texto | Notas |
|---|---|---|---|---|---|
| PDF Oxide | 0,8 ms | 9 ms | 100 % | Integrada, de nivel de producción | Unicode, CJK, orden de lectura |
| oxidize_pdf | 13,5 ms | 11 ms | 99,1 % | Básica | Valor atípico máximo de 48 s |
| unpdf | 2,8 ms | 10 ms | 95,1 % | Básica | 185 fallos en el corpus completo |
| pdf_extract | 4,08 ms | 37 ms | 91,5 % | Básica | Se le escapan los diseños complejos |
| lopdf | 0,3 ms | 2 ms | 80,2 % | Sin extracción integrada | Falla en el 20 % de los PDF |
lopdf es más rápida con los PDF que puede analizar, pero falla en el 20 % del corpus y no ofrece extracción de texto. Tendrías que implementar tú mismo la decodificación de fuentes, la resolución de CMap y el análisis de espaciado.
pdf_extract ofrece extracción de texto básica, pero tiene una tasa de éxito del 91,5 % y le cuesta con los diseños complejos, el texto CJK y los PDF etiquetados. oxidize_pdf tiene una fiabilidad decente (99,1 %), pero es 17 veces más lenta que pdf_oxide en el tiempo medio de extracción, con un valor atípico en el peor de los casos de 48 segundos. unpdf procesa el corpus completo, pero falla en 185 PDF.
PDF Oxide es la única crate de Rust que combina un 100 % de fiabilidad con extracción de texto de nivel de producción.
Comparación del diseño de la API
PDF Oxide: alto nivel, orientada a tareas
PDF Oxide ofrece métodos creados específicamente para tareas comunes. Trabajas con texto, imágenes y campos de formulario, no con objetos y diccionarios PDF.
use pdf_oxide::PdfDocument;
let mut doc = PdfDocument::open("report.pdf")?;
// Text extraction -- one call
let text = doc.extract_text(0)?;
println!("{}", text);
// Styled spans with font metadata
let spans = doc.extract_spans(0)?;
for span in &spans {
println!("'{}' font={} size={:.1}pt", span.text, span.font_name, span.font_size);
}
// Image extraction
let images = doc.extract_images(0)?;
for img in &images {
println!("{}x{} {:?}", img.width, img.height, img.format);
}
// Form fields
let fields = doc.extract_form_fields()?;
for field in &fields {
println!("{}: {:?}", field.name, field.value);
}
La creación de PDF es igual de sencilla:
use pdf_oxide::api::Pdf;
// From Markdown
let pdf = Pdf::from_markdown("# Report\n\n| A | B |\n|---|---|\n| 1 | 2 |")?;
pdf.save("report.pdf")?;
// From 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 los objetos PDF, los streams y la tabla de referencias cruzadas. Debes entender la especificación PDF para usarla con eficacia. No hay extracción de texto integrada: navegas por los diccionarios y decodificas los streams por tu cuenta.
use lopdf::Document;
let doc = Document::load("report.pdf")?;
// Get page dictionary
let page_id = doc.page_iter().next().unwrap();
let page = doc.get_dictionary(page_id)?;
// Get content stream -- manual work
let contents = page.get("Contents")?;
let stream = doc.get_object(contents.as_reference()?)?;
// To extract text you must:
// 1. Parse the content stream operators
// 2. Resolve font references from /Resources
// 3. Decode CMap/ToUnicode mappings
// 4. Apply text matrix transformations
// 5. Handle encoding differences
//
// lopdf does not provide any of this -- it is raw object access
println!("Page has {} objects", doc.objects.len());
lopdf es la herramienta adecuada cuando necesitas manipular la estructura del PDF directamente: combinar documentos, reescribir streams de objetos o construir procesadores de PDF especializados.
printpdf: solo creación de PDF
printpdf es una biblioteca solo de creación. No puede leer ni analizar PDF existentes. Ofrece 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);
// Add text -- requires manual font loading
let font = doc.add_builtin_font(BuiltinFont::Helvetica)?;
current_layer.use_text("Hello World", 24.0, Mm(10.0), Mm(280.0), &font);
// Save
doc.save(&mut std::io::BufWriter::new(
std::fs::File::create("output.pdf")?,
))?;
// Cannot read existing PDFs
// Cannot extract text, images, or form fields
printpdf es la herramienta adecuada cuando solo necesitas generar PDF nuevos y quieres una API de creación limpia y enfocada.
pdf-rs: lectura de PDF de bajo nivel
pdf-rs analiza la estructura del PDF en tipos de Rust, pero ofrece una funcionalidad de alto nivel mínima. Obtienes acceso tipado a los objetos PDF, pero aun así debes encargarte de la decodificación de texto, la resolución de fuentes y el análisis de streams de contenido.
use pdf::file::FileOptions;
let file = FileOptions::cached().open("report.pdf")?;
// Access page objects
let page = file.get_page(0)?;
let media_box = page.media_box()?;
println!("Page size: {:?}", media_box);
// Content stream access -- low-level
if let Some(ref contents) = page.contents {
// Returns raw operations -- you must interpret them
// No built-in text assembly, font decoding, or layout analysis
}
// Cannot write or modify PDFs
pdf-rs es la herramienta adecuada cuando necesitas un parser de PDF con seguridad de tipos para análisis, validación o para construir un renderizador propio.
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 (se le escapan los diseños complejos) | Una llamada a método |
| lopdf | No | N/D | Cientos de líneas de código propio |
| printpdf | No | N/D | No es posible (solo escritura) |
| pdf-rs | No | N/D | Requiere bastante código propio |
PDF Oxide se encarga de la decodificación CMap/ToUnicode, el espaciado basado en métricas de fuente, el orden de lectura por árbol de estructura y la reconstrucción de ligaduras. Implementar una funcionalidad equivalente sobre lopdf o pdf-rs requiere miles de líneas de código y un 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 de objetos en bruto | No | No | No |
| printpdf | API de capas tipada | No | No | No |
| pdf-rs | N/D (solo lectura) | N/D | N/D | N/D |
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) | ~30 s | ~4 MB |
| lopdf | ~15 | ~10 s | ~1 MB |
| printpdf | ~20 | ~15 s | ~2 MB |
| pdf-rs | ~25 | ~20 s | ~2 MB |
PDF Oxide tiene más dependencias porque incluye análisis de fuentes, decodificación de imágenes, interpretación de streams de contenido y cifrado: funciones que las demás bibliotecas dejan al usuario u omiten por completo. Con todas las funciones opcionales (rendering, barcodes, office), el número sube a ~100.
Combinar bibliotecas
Como todas tienen licencias permisivas, puedes combinarlas en un mismo proyecto:
[dependencies]
pdf_oxide = "0.3"
lopdf = "0.32" # Optional: raw object access for edge cases
Patrones habituales:
- PDF Oxide + lopdf: usa PDF Oxide para extracción y creación, y recurre a lopdf para los casos límite que requieren manipulación de objetos en bruto.
- PDF Oxide + printpdf: usa PDF Oxide para lectura y printpdf para flujos de creación especializados.
Matriz de casos de uso
«Necesito extraer texto de PDF»
| Crate | ¿Adecuada? | Notas |
|---|---|---|
| PDF Oxide | Sí | Mejor calidad de extracción, 100 % de tasa de éxito, orden de lectura, metadatos de fuente |
| pdf_extract | Parcial | Extracción básica, 91,5 % de tasa de éxito |
| lopdf | No | Sin extracción de texto |
| printpdf | No | No puede leer PDF |
| pdf-rs | Parcial | Análisis básico, sin extracción de texto de alto nivel |
«Necesito crear PDF»
| Crate | ¿Adecuada? | Notas |
|---|---|---|
| PDF Oxide | Sí | APIs de alto nivel (Markdown/HTML) y de 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 PDF existentes»
| Crate | ¿Adecuada? | Notas |
|---|---|---|
| PDF Oxide | Sí | Edición tipo DOM, anotaciones, formularios |
| lopdf | Parcial | Manipulación de objetos de bajo nivel |
| printpdf | No | No puede leer PDF |
| pdf-rs | No | Solo lectura |
«Necesito el ciclo de vida completo (extraer + crear + editar)»
| Crate | ¿Adecuada? | Notas |
|---|---|---|
| PDF Oxide | Sí | Única crate que cubre las tres |
| lopdf + printpdf | Parcial | Dos crates, sin extracción de texto |
| pdf-rs + printpdf | Parcial | Dos crates, sin edición |
Cuándo usar cada una
Elige PDF Oxide si necesitas más de una capacidad de PDF (extracción + creación, o extracción + edición) y quieres una única dependencia bien probada con un 100 % de fiabilidad.
Elige lopdf si necesitas manipulación de la estructura del PDF de bajo nivel y te sientes cómodo trabajando directamente con la especificación PDF. Buena para combinar, dividir y procesar PDF por lotes.
Elige printpdf si solo creas PDF y nunca necesitas leerlos. La API más limpia para generar informes y documentos.
Elige pdf-rs si necesitas un parser conforme a la especificación para análisis de 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 fiabilidad ni soporte para diseños complejos.
Páginas relacionadas
- Benchmarks de rendimiento – resultados del benchmark del corpus completo
- Primeros pasos con Rust – instalación y primera extracción
- Referencia de la API de Rust – API de Rust completa
- vs. Bibliotecas PDF para Python – comparación del ecosistema de Python