Порівняння з 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