Сравнение с 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, если вам нужно базовое извлечение текста и не требуются высокая надёжность или поддержка сложных макетов.
Связанные страницы
- Бенчмарки производительности – результаты бенчмарка на полном корпусе
- Начало работы с Rust – установка и первое извлечение
- Справочник по Rust API – полный Rust API
- Сравнение с PDF-библиотеками для Python – сравнение экосистемы Python