Skip to content

Сравнение с PDF-библиотеками для Rust

PDF Oxide в сравнении с самыми популярными PDF-крейтами для Rust: lopdf, printpdf, pdf-rs и pdf_extract. Каждый из них рассчитан на свой уровень абстракции и свой набор сценариев использования.

Кратко

PDF Oxide lopdf printpdf pdf-rs pdf_extract
Уровень API Высокоуровневый Низкоуровневый Среднеуровневый (создание) Низкоуровневый (чтение) Среднеуровневый (чтение)
Чтение PDF Да Да Нет Да Да
Запись PDF Да Да Да Нет Нет
Извлечение текста Да (высокоуровневое) Вручную Нет Вручную Да (базовое)
Извлечение изображений Да (высокоуровневое) Вручную Нет Вручную Нет
Поля форм Чтение + запись Вручную Нет Только чтение Нет
Создание PDF Да Да Да Нет Нет
Ввод из Markdown/HTML Да Нет Нет Нет Нет
Редактирование существующих PDF Да Да (низкоуровневое) Нет Нет Нет
Аннотации Чтение + запись Вручную Нет Только чтение Нет
Шифрование Чтение + запись Нет Нет Нет Нет
Проверка PDF/A Да Нет Нет Нет Нет
Рендеринг Да (tiny-skia) Нет Нет Частично Нет
Привязки для Python Да Нет Нет Нет Нет
Лицензия MIT MIT MIT MIT Apache-2.0

Все библиотеки распространяются под либеральными лицензиями. Различия — в охвате возможностей и уровне абстракции.

Сравнение производительности

Бенчмарк на полном корпусе (3830 PDF)

Тестирование проводилось на полном корпусе из 3830 PDF — это три независимых, общедоступных набора тестов, охватывающих соответствие спецификации PDF (veraPDF, 2907 файлов), реальные пограничные случаи рендеринга в браузере (Mozilla pdf.js, 897 файлов) и стресс-тесты на безопасность и устойчивость, включая некорректные структуры и повреждения, сгенерированные фаззингом (DARPA SafeDocs, 26 файлов). См. подробности о полном корпусе.

Библиотека Среднее p99 Доля успеха Извлечение текста Примечания
PDF Oxide 0,8 мс 9 мс 100% Встроенное, промышленного уровня Unicode, CJK, порядок чтения
oxidize_pdf 13,5 мс 11 мс 99,1% Базовое Максимальный выброс 48 с
unpdf 2,8 мс 10 мс 95,1% Базовое 185 сбоев на полном корпусе
pdf_extract 4,08 мс 37 мс 91,5% Базовое Пропускает сложные макеты
lopdf 0,3 мс 2 мс 80,2% Нет встроенного извлечения Сбоит на 20% PDF

lopdf работает быстрее на тех PDF, которые он способен разобрать, — но он сбоит на 20% корпуса и не предоставляет извлечения текста. Декодирование шрифтов, разрешение CMap и анализ интервалов пришлось бы реализовывать самостоятельно.

pdf_extract предоставляет базовое извлечение текста, но имеет долю успеха 91,5% и с трудом справляется со сложными макетами, текстом CJK и тегированными PDF. oxidize_pdf обладает достойной надёжностью (99,1%), но в 17 раз медленнее pdf_oxide по среднему времени извлечения, с выбросом до 48 секунд в худшем случае. unpdf обрабатывает весь корпус, но сбоит на 185 PDF.

PDF Oxide — единственный крейт Rust, сочетающий 100% надёжность с извлечением текста промышленного уровня.

Сравнение дизайна API

PDF Oxide: высокоуровневый, ориентированный на задачи

PDF Oxide предоставляет специально созданные методы для типовых задач. Вы работаете с текстом, изображениями и полями форм, а не с объектами и словарями 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);
}

Создание PDF столь же просто:

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: низкоуровневые манипуляции объектами

lopdf даёт прямой доступ к объектам PDF, потокам и таблице перекрёстных ссылок. Чтобы пользоваться им эффективно, нужно понимать спецификацию PDF. Встроенного извлечения текста нет — вы сами обходите словари и декодируете потоки.

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 — подходящий инструмент, когда нужно напрямую манипулировать структурой PDF: объединять документы, переписывать потоки объектов или создавать специализированные обработчики PDF.

printpdf: только создание PDF

printpdf — библиотека только для создания. Она не умеет читать или разбирать существующие PDF. Она предоставляет типизированный API для построения PDF-документов с нуля — с текстом, изображениями и векторной графикой.

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 — подходящий инструмент, когда вам нужно только генерировать новые PDF и хочется чистый, сфокусированный API для создания.

pdf-rs: низкоуровневое чтение PDF

pdf-rs разбирает структуру PDF в типы Rust, но предоставляет минимум высокоуровневой функциональности. Вы получаете типизированный доступ к объектам PDF, но декодирование текста, разрешение шрифтов и разбор потоков содержимого по-прежнему ложатся на вас.

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 — подходящий инструмент, когда нужен типобезопасный парсер PDF для анализа, проверки или построения собственного рендерера.

Сравнение возможностей по задачам

Извлечение текста

Библиотека Встроено Качество Необходимые усилия
PDF Oxide Да Промышленного уровня (Unicode, CJK, порядок чтения) Один вызов метода
pdf_extract Да Базовое (пропускает сложные макеты) Один вызов метода
lopdf Нет Сотни строк собственного кода
printpdf Нет Невозможно (только запись)
pdf-rs Нет Требуется значительный объём собственного кода

PDF Oxide обрабатывает декодирование CMap/ToUnicode, интервалы на основе метрик шрифта, порядок чтения по дереву структуры и восстановление лигатур. Реализация эквивалентной функциональности поверх lopdf или pdf-rs потребует тысяч строк кода и глубокого знания спецификации PDF.

Создание PDF

Библиотека Подход Ввод из Markdown/HTML Таблицы Штрихкоды
PDF Oxide Высоко- + низкоуровневый Да Да Да
lopdf Построение из «сырых» объектов Нет Нет Нет
printpdf Типизированный API слоёв Нет Нет Нет
pdf-rs — (только чтение)

Шифрование

Библиотека Чтение зашифрованных Запись зашифрованных Алгоритмы
PDF Oxide Да Да RC4-40, RC4-128, AES-128, AES-256
lopdf Нет Нет
printpdf Нет Нет
pdf-rs Частично Нет Только RC4

Соответствие стандартам

Библиотека PDF/A PDF/X PDF/UA
PDF Oxide Проверка + конвертация Проверка Проверка
lopdf Нет Нет Нет
printpdf Частично (вывод PDF/A-1b) Нет Нет
pdf-rs Нет Нет Нет

Объём зависимостей

Библиотека Зависимости Время компиляции Размер бинарника
PDF Oxide ~40 (ядро) ~30 с ~4 МБ
lopdf ~15 ~10 с ~1 МБ
printpdf ~20 ~15 с ~2 МБ
pdf-rs ~25 ~20 с ~2 МБ

У PDF Oxide больше зависимостей, потому что он включает разбор шрифтов, декодирование изображений, интерпретацию потоков содержимого и шифрование — возможности, которые другие библиотеки оставляют на усмотрение пользователя или вовсе опускают. Со всеми опциональными возможностями (rendering, barcodes, office) их число вырастает до ~100.

Комбинирование библиотек

Поскольку все они под либеральными лицензиями, их можно сочетать в одном проекте:

[dependencies]
pdf_oxide = "0.3"
lopdf = "0.32"        # Optional: raw object access for edge cases

Типичные схемы:

  • PDF Oxide + lopdf: используйте PDF Oxide для извлечения и создания, прибегая к lopdf для пограничных случаев, требующих манипуляций с «сырыми» объектами.
  • PDF Oxide + printpdf: используйте PDF Oxide для чтения, а printpdf — для специализированных сценариев создания.

Матрица сценариев использования

«Мне нужно извлекать текст из PDF»

Крейт Подходит? Примечания
PDF Oxide Да Лучшее качество извлечения, 100% успеха, порядок чтения, метаданные шрифтов
pdf_extract Частично Базовое извлечение, 91,5% успеха
lopdf Нет Нет извлечения текста
printpdf Нет Не умеет читать PDF
pdf-rs Частично Базовый разбор, нет высокоуровневого извлечения текста

«Мне нужно создавать PDF»

Крейт Подходит? Примечания
PDF Oxide Да Высокоуровневый (Markdown/HTML) и низкоуровневый API
lopdf Частично Низкоуровневое построение объектов
printpdf Да Чистый API создания, без чтения
pdf-rs Нет Только чтение

«Мне нужно редактировать существующие PDF»

Крейт Подходит? Примечания
PDF Oxide Да DOM-подобное редактирование, аннотации, формы
lopdf Частично Низкоуровневые манипуляции объектами
printpdf Нет Не умеет читать PDF
pdf-rs Нет Только чтение

«Мне нужен полный цикл (извлечение + создание + редактирование)»

Крейт Подходит? Примечания
PDF Oxide Да Единственный крейт, охватывающий все три
lopdf + printpdf Частично Два крейта, нет извлечения текста
pdf-rs + printpdf Частично Два крейта, нет редактирования

Когда что выбирать

Выбирайте PDF Oxide, если вам нужно более одной возможности работы с PDF (извлечение + создание или извлечение + редактирование) и вы хотите одну хорошо протестированную зависимость со 100% надёжностью.

Выбирайте lopdf, если вам нужны низкоуровневые манипуляции структурой PDF и вы готовы работать напрямую со спецификацией PDF. Хорош для объединения, разделения и пакетной обработки PDF.

Выбирайте printpdf, если вы только создаёте PDF и никогда не читаете их. Самый чистый API для генерации отчётов и документов.

Выбирайте pdf-rs, если вам нужен соответствующий спецификации парсер для анализа PDF или вы строите собственный конвейер рендеринга.

Выбирайте pdf_extract, если вам нужно базовое извлечение текста и не требуются высокая надёжность или поддержка сложных макетов.

Связанные страницы