在 Rust 中使用 printpdf 库生成 PDF 报告
在现代编程世界中,Rust 越来越多地被用于创建高性能的服务器应用程序和命令行工具。其中一项常见的任务是生成 PDF 报告——无论是分析仪表板、发票还是文档。printpdf 库提供了一种轻量且可靠的方式,在纯 Rust 环境中创建 PDF 文档,无需依赖外部系统(例如 LaTeX 或 wkhtmltopdf)。
什么是 printpdf?
printpdf 是一个纯 Rust 库,用于从头生成 PDF 文档。它支持:
- 使用各种字体(包括嵌入的 TrueType/OpenType 字体)的文本。
- 矢量图形(线条、矩形、椭圆)。
- 带有透明度的图像(PNG、JPEG)。
- 通过手动定位实现的表格和复杂排版。
- 任意尺寸的页面(A4、Letter、自定义尺寸)。
该库不使用外部进程,因此非常适合嵌入到 Web 服务、CLI 工具或 Rust 桌面应用程序中。
安装
在 Cargo.toml 中添加:
[dependencies]printpdf = "0.7"您还需要 rusttype crate 来处理字体(它会作为依赖项自动引入)。
基本示例:创建简单报告
让我们编写一个程序,创建一个包含标题、文本和线条的 PDF。结果将保存到文件 report.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", );
// 获取字体(内置 Helvetica) let font = doc.add_builtin_font(BuiltinFont::Helvetica).unwrap();
// 开始在第一层上绘制 let current_layer = doc.get_page(page1).get_layer(layer1);
// 文本:标题 current_layer.use_text( "销售报告", 24.0, Mm(20.0), Mm(270.0), &font, );
// 文本:普通文本 current_layer.use_text( "报告日期:2025-03-15", 12.0, Mm(20.0), Mm(250.0), &font, );
// 绘制分隔线 current_layer.set_outline_color(Color::Rgb(Rgb::new(0.5, 0.5, 0.5))); current_layer.set_stroke_width(1.0); current_layer.add_line( Point::new(Mm(20.0), Mm(240.0)), Point::new(Mm(190.0), Mm(240.0)), );
// 保存到文件 let file = File::create("report.pdf").unwrap(); let writer = BufWriter::new(file); doc.save(&mut std::io::BufWriter::new(writer)).unwrap();
println!("PDF 报告已创建:report.pdf");}这段代码创建了一个包含标题、日期和灰色线条的单页 PDF。所有坐标均以毫米为单位指定(也可以使用点)。
添加数据表格
报告通常需要表格。printpdf 没有内置的表格结构,但可以轻松手动实现:
use printpdf::*;use std::fs::File;use std::io::BufWriter;
fn draw_table( layer: &PdfLayerReference, font: &IndirectFontRef, data: Vec<[&str; 3]>, start_x: Mm, start_y: Mm,) { let col_widths = [Mm(40.0), Mm(60.0), Mm(50.0)]; let row_height = Mm(10.0); let header_bg = Color::Rgb(Rgb::new(0.9, 0.9, 0.9));
for (row_idx, row_data) in data.iter().enumerate() { let y = start_y - row_height * (row_idx as f32);
// 标题行的背景 if row_idx == 0 { layer.set_fill_color(header_bg); layer.add_rectangle( start_x, y - row_height,