Генерация PDF отчётов на Rust с библиотекой printpdf
В современном веб-разработке создание PDF-документов остаётся востребованной задачей — от формирования счетов и отчётов до экспорта данных. Если ваш проект написан на Rust или вы используете его для бэкенда, библиотека printpdf станет надёжным инструментом для генерации PDF. В этой статье мы разберём возможности printpdf, покажем примеры кода и обсудим, как интегрировать её в образовательный проект.
Что такое printpdf?
printpdf — это чистая Rust-библиотека для создания PDF-документов без внешних зависимостей. Она позволяет:
- Создавать многостраничные документы с произвольным содержимым
- Добавлять текст с различными шрифтами (включая TrueType и OpenType)
- Рисовать линии, прямоугольники, эллипсы и сложные пути
- Встраивать изображения (JPEG, PNG)
- Работать с таблицами и сетками
- Управлять цветовыми пространствами (RGB, CMYK, Grayscale)
Главное преимущество — полная автономность: не требуется установка LaTeX, wkhtmltopdf или других систем. Это делает printpdf идеальным выбором для образовательного сайта pythonlib.ru, где важна простота развёртывания и воспроизводимость примеров.
Установка и первый документ
Добавьте зависимость в Cargo.toml:
[dependencies]
printpdf = "0.7"
Создадим простейший PDF с текстом:
use printpdf::*;
use std::fs::File;
use std::io::BufWriter;
fn main() {
// Создаём документ формата A4
let (doc, page1, layer1) = PdfDocument::new(
"Мой первый PDF",
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(
"Привет, PythonLib!",
24.0,
Mm(10.0),
Mm(280.0),
&font
);
// Сохраняем файл
let file = File::create("hello.pdf").unwrap();
let writer = BufWriter::new(file);
doc.save(&mut writer).unwrap();
println!("PDF создан: hello.pdf");
}
Этот код создаёт одностраничный PDF с надписью. Обратите внимание: use_text принимает координаты в миллиметрах, а размер шрифта — в пунктах.
Работа с графикой и цветом
printpdf поддерживает рисование примитивов. Создадим отчёт с линией и закрашенным прямоугольником:
use printpdf::*;
fn create_report() -> (PdfDocumentReference, PdfPageIndex, PdfLayerIndex) {
let (doc, page, layer) = PdfDocument::new(
"Отчёт",
Mm(210.0),
Mm(297.0),
"Data"
);
let layer = doc.get_page(page).get_layer(layer);
// Рисуем красную линию
let points = vec![
(Point::new(Mm(20.0), Mm(250.0)), false),
(Point::new(Mm(190.0), Mm(250.0)), false),
];
let line = Line {
points,
is_closed: false,
};
layer.set_color(Color::Rgb(Rgb::new(1.0, 0.0, 0.0)));
layer.add_line(line);
// Закрашенный синий прямоугольник
let rect = Polygon {
vertices: vec![
(Point::new(Mm(50.0), Mm(200.0)), false),
(Point::new(Mm(150.0), Mm(200.0)), false),
(Point::new(Mm(150.0), Mm(180.0)), false),
(Point::new(Mm(50.0), Mm(180.0)), false),
],
is_closed: true,
};
layer.set_color(Color::Rgb(Rgb::new(0.0, 0.0, 1.0)));
layer.add_polygon(rect);
(doc, page, layer)
}
Цвета задаются в диапазоне 0.0–1.0. Для CMYK используйте Color::Cmyk(Cmyk::new(0.0, 1.0, 0.0, 0.0)).
Встраивание изображений
Добавим логотип в отчёт:
use printpdf::*;
use std::fs::File;
fn add_image(doc: &mut PdfDocumentReference, page: PdfPageIndex, layer: PdfLayerIndex) {
let image = Image::from_reader(File::open("logo.png").unwrap()).unwrap();
// Масштабируем до 50x50 мм
let size = image.image.into_image_size();
image.add_to_layer(
doc.get_page(page).get_layer(layer