Генерация PDF в Rust: обзор библиотек и инструментов

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Генерация PDF в Rust: обзор библиотек и инструментов

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

Основные библиотеки для работы с PDF в Rust

Экосистема Rust предлагает несколько зрелых решений для генерации PDF. Рассмотрим наиболее популярные:

  • printpdf — низкоуровневая библиотека с поддержкой векторной графики, изображений и шрифтов.
  • genpdf — высокоуровневая библиотека для создания документов с простым API.
  • pdf_writer — быстрый и безопасный генератор PDF с минимальными зависимостями.
  • wkhtmltopdf — обёртка над утилитой wkhtmltopdf для конвертации HTML в PDF.

Библиотека printpdf

printpdf — одна из самых популярных библиотек для генерации PDF в Rust. Она предоставляет полный контроль над содержимым документа: текст, линии, прямоугольники, изображения и встроенные шрифты.

Установка

[dependencies]
printpdf = "0.7"

Пример: создание простого PDF с текстом

use printpdf::*;
use std::fs::File;
use std::io::BufWriter;

fn main() {
    // Создаём документ формата A4
    let (doc, page1, layer1) = PdfDocument::new(
        "Пример документа",
        Mm(210.0),
        Mm(297.0),
        "Layer 1"
    );

    // Получаем текущий шрифт (встроенный)
    let font = doc.add_builtin_font(BuiltinFont::Helvetica).unwrap();

    // Рисуем текст
    let current_layer = doc.get_page(page1).get_layer(layer1);
    current_layer.use_text(
        "Привет, мир PDF из Rust!",
        24.0,
        Mm(20.0),
        Mm(270.0),
        &font
    );

    // Сохраняем в файл
    let file = File::create("example.pdf").unwrap();
    let writer = BufWriter::new(file);
    doc.save(&mut std::io::BufWriter::new(writer)).unwrap();
}

Библиотека genpdf

genpdf предоставляет более высокоуровневый API, напоминающий работу с текстовыми процессорами. Поддерживает абзацы, таблицы, заголовки и автоматический перенос строк.

Установка

[dependencies]
genpdf = "0.2"

Пример: создание документа с заголовком и таблицей

use genpdf::{Document, SimplePageSettings};
use genpdf::elements::{Paragraph, Table, TableLayout};
use genpdf::fonts::FontFamily;

fn main() -> Result<(), Box> {
    // Загружаем шрифт (например, DejaVu Sans)
    let font_family = FontFamily::from_files(
        "/usr/share/fonts/truetype/dejavu/",
        "DejaVuSans",
        None
    )?;

    // Создаём документ
    let mut doc = Document::new(font_family, SimplePageSettings::a4());

    // Добавляем заголовок
    doc.push(Paragraph::new("Отчёт о продажах").aligned(genpdf::Alignment::Center));

    // Создаём таблицу
    let mut table = Table::new(TableLayout::new(vec![2, 3, 2]));
    table.row()
        .element(Paragraph::new("Товар"))
        .element(Paragraph::new("Количество"))
        .element(Paragraph::new("Цена"));
    table.row()
        .element(Paragraph::new("Ноутбук"))
        .element(Paragraph::new("10"))
        .element(Paragraph::new("50 000 руб."));
    table.row()
        .element(Paragraph::new("Мышь"))
        .element(Paragraph::new("50"))
        .element(Paragraph::new("1 500 руб."));

    doc.push(table);

    // Сохраняем
    doc.render_to_file("report.pdf")?;
    Ok(())
}

Библиотека pdf_writer

pdf_writer — минималистичная и быстрая библиотека, ориентированная на низкоуровневую работу с PDF-структурами. Идеальна для случаев, когда нужно генерировать PDF с минимальными накладными расходами.

Пример: создание пустой страницы

use pdf_writer::{PdfWriter, Writer, Rect};

fn main() {
    let mut writer = PdfWriter::new();
    let catalog = writer.catalog();
    let page_tree = writer.pages();
    let page = writer.page(MediaBox::new(0.0, 0.0, 595.0, 842.0));
    page.parent(page_tree);
    page_tree.add_page(page);
    catalog.pages(page_tree);
    writer.finish();
    std::fs::write("empty.pdf", writer.finish()).unwrap();
}

Конвертация HTML в PDF через wkhtml

Рекомендаций