用Rust生成PDF文件的方法有哪些

最近在做一个Rust项目,需要生成PDF文件,但不太清楚有哪些可用的库或方法。想请教大家:

  1. Rust生态中有哪些成熟的PDF生成库?
  2. 这些库各自有什么优缺点?比如性能、功能完整性、易用性等方面
  3. 是否有推荐的最佳实践或示例代码?
  4. 如果需要支持中文等特殊字符,哪些库比较合适?
  5. 除了专门的PDF库,是否可以通过其他方式(如HTML转PDF)来实现?

希望能得到一些实际使用经验分享,谢谢!

2 回复

在Rust中生成PDF的常用方法:

  1. printpdf - 最流行的库,支持文本、图像、矢量图形
use printpdf::*;
// 创建文档、页面、图层
// 添加文本和图形
  1. lopdf - 底层PDF操作库
  • 直接操作PDF对象
  • 适合需要精细控制的场景
  1. pdf-writer - 纯写入库
  • 无依赖,轻量级
  • 只生成不解析
  1. wkhtmltopdf的Rust绑定
  • 通过HTML转PDF
  • 适合已有HTML内容的情况
  1. 组合方案
  • 先用其他库生成内容
  • 再用PDF库输出

建议

  • 新手用printpdf,文档完善
  • 需要高性能用lopdf
  • 从HTML转换用wkhtmltopdf

记得在Cargo.toml添加相应依赖,根据需求选择合适的库。


在Rust中生成PDF文件,主要有以下几种方法:

1. printpdf 库(推荐)

最流行的Rust PDF生成库,功能完善:

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

fn create_pdf() -> Result<(), Box<dyn std::error::Error>> {
    let (doc, page1, layer1) = PdfDocument::new("PDF_Document_title", Mm(210.0), Mm(297.0), "Layer 1");
    let current_layer = doc.get_page(page1).get_layer(layer1);
    
    // 添加文本
    let font = doc.add_builtin_font(BuiltinFont::Helvetica)?;
    current_layer.use_text("Hello PDF!", 48.0, Mm(20.0), Mm(270.0), &font);
    
    // 添加图形
    current_layer.set_outline_color(Color::Rgb(Rgb::new(1.0, 0.0, 0.0, None)));
    current_layer.set_line_width(2.0);
    current_layer.add_line(Mm(50.0), Mm(50.0), Mm(150.0), Mm(150.0));
    
    doc.save(&mut BufWriter::new(File::create("test.pdf")?))?;
    Ok(())
}

2. lopdf 库

轻量级PDF处理库,支持生成和修改:

use lopdf::{Document, Object, ObjectId};
use std::collections::BTreeMap;

fn create_lopdf_pdf() -> Result<(), Box<dyn std::error::Error>> {
    let mut doc = Document::with_version("1.5");
    
    // 创建页面
    let pages_id = doc.new_object_id();
    let font_id = doc.add_object(dictionary! {
        "Type" => "Font",
        "Subtype" => "Type1",
        "BaseFont" => "Helvetica",
    });
    
    let content = "BT /F1 24 Tf 100 700 Td (Hello World) Tj ET";
    let content_id = doc.add_object(content.as_bytes().to_vec());
    
    let page_id = doc.add_object(dictionary! {
        "Type" => "Page",
        "Parent" => pages_id,
        "Contents" => content_id,
        "Resources" => dictionary! {
            "Font" => dictionary! {
                "F1" => font_id,
            },
        },
        "MediaBox" => vec![0.into(), 0.into(), 595.into(), 842.into()],
    });
    
    doc.save("test_lopdf.pdf")?;
    Ok(())
}

3. pdf-writer 库

专注于PDF生成的底层库:

use pdf_writer::{Content, Finish, Name, Pdf, Rect, Ref, Str};

fn create_pdf_writer() -> Result<(), Box<dyn std::error::Error>> {
    let mut pdf = Pdf::new();
    
    let catalog_id = Ref::new(1);
    let page_tree_id = Ref::new(2);
    let page_id = Ref::new(3);
    let content_id = Ref::new(4);
    let font_id = Ref::new(5);
    
    pdf.catalog(catalog_id)
        .pages(page_tree_id)
        .finish();
    
    pdf.pages(page_tree_id)
        .kids([page_id])
        .count(1)
        .finish();
    
    pdf.page(page_id)
        .parent(page_tree_id)
        .contents(content_id)
        .media_box(Rect::new(0.0, 0.0, 595.0, 842.0))
        .resources()
        .fonts()
        .pair(Name(b"F1"), font_id)
        .finish()
        .finish();
    
    // 写入内容流
    let mut content = Content::new();
    content.begin_text();
    content.set_font(Name(b"F1"), 24.0);
    content.next_line(100.0, 700.0);
    content.show(Str(b"Hello PDF Writer"));
    content.end_text();
    
    pdf.stream(content_id, &content.finish());
    
    pdf.font(font_id)
        .type_(Name(b"Font"))
        .subtype(Name(b"Type1"))
        .base_font(Name(b"Helvetica"))
        .finish();
    
    std::fs::write("test_pdf_writer.pdf", pdf.finish())?;
    Ok(())
}

4. 其他选择

  • rust-pdf:另一个PDF生成库
  • wkhtmltopdf:通过调用外部工具转换HTML为PDF
  • WeasyPrint:类似wkhtmltopdf的替代方案

选择建议

  • printpdf:适合大多数应用场景,API友好
  • lopdf:需要同时读写PDF文件时使用
  • pdf-writer:对性能要求高或需要精细控制时使用

在Cargo.toml中添加相应依赖即可开始使用这些库。

回到顶部