You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Rust的Printpdf 0.5.3 crate实现PDF文本自动换行格式化?

解决Printpdf中文本自动换行问题的方案

你在开发求职信PDF生成工具时,遇到Printpdf无法自动处理长文本换行的问题,以下是两种可行的解决思路:

方案一:保留Printpdf,结合textwrap实现手动换行

Printpdf本身不支持文本自动布局,但可以借助textwrap库将长文本拆分为适配页面宽度的多行,再逐行写入PDF。

步骤1:添加依赖

在Cargo.toml中加入textwrap:

[dependencies]
printpdf = "0.5"
textwrap = "0.16" # 可使用最新稳定版

步骤2:修改代码实现换行

核心是计算页面可用宽度,用textwrap拆分文本后逐行写入:

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

fn main() {
    // 读取用户输入
    println!("Enter: Position");
    let mut position = String::new(); 
    io::stdin().read_line(&mut position).expect("failed to read"); 

    println!("Enter: Company Name");
    let mut coname = String::new(); 
    io::stdin().read_line(&mut coname).expect("failed to read"); 

    println!("Enter: Company Location");
    let mut location = String::new(); 
    io::stdin().read_line(&mut location).expect("failed to read"); 

    let sample = "This is some random Sample text, This text should eventaully be a user input. Currently, this text is not a user input. this text is supposed to be a text of long string data that will eventually be added to the document via user input";

    let (doc, page1, layer1) = PdfDocument::new("PDF_Document_title", Mm(216.0), Mm(279.0), "Layer 1");
    let current_layer = doc.get_page(page1).get_layer(layer1);

    let font = doc.add_external_font(File::open("./fonts/TNR-Regular.ttf").unwrap()).unwrap();

    // 写入抬头信息
    current_layer.use_text(position.trim(), 14.0, Mm(25.0), Mm(250.0), &font);
    current_layer.use_text(coname.trim(), 14.0, Mm(25.0), Mm(240.0), &font);
    current_layer.use_text(location.trim(), 14.0, Mm(25.0), Mm(230.0), &font);
    current_layer.use_text(" ", 14.0, Mm(25.0), Mm(220.0), &font);

    // 计算页面可用宽度(左右边距各25mm)
    let available_width_mm = 216.0 - 25.0 * 2.0;
    // 转换为每行可容纳字符数:按14pt字体估算,每个字符约占8pt宽度
    let char_per_line = (available_width_mm * 72.0 / 25.4 / 8.0) as usize;
    
    // 用textwrap拆分文本
    let wrapper = Wrapper::new(char_per_line);
    let wrapped_lines = wrapper.wrap(sample);

    // 逐行写入文本
    current_layer.begin_text_section();
    current_layer.set_font(&font, 14.0);
    let mut y_pos = 210.0;
    let line_height = 18.0; // 行高略大于字号保证可读性

    for line in wrapped_lines {
        current_layer.set_text_cursor(Mm(25.0), Mm(y_pos));
        current_layer.write_text(line, &font);
        y_pos -= line_height;
    }
    current_layer.end_text_section();

    doc.save(&mut BufWriter::new(File::create("test_working.pdf").unwrap())).unwrap();
}

说明:通过计算页面可用宽度拆分文本,逐行控制Y坐标写入实现换行。若需更精准的字符宽度计算,可调用Printpdf字体的get_glyph_width方法逐个字符计算宽度后调整换行位置。

方案二:更换高层PDF生成库

若不想手动处理布局细节,可选择支持自动文本排版的高层库,比如genpdf,它封装了文本换行、边距、对齐等功能,更适合快速开发。

步骤1:添加依赖

[dependencies]
genpdf = "0.2"
genpdf-printpdf = "0.2" # 基于printpdf后端,也可选择其他后端

步骤2:简化代码实现

use genpdf::{Document, Element, Fonts, SimplePageDecorator};
use std::fs::File;
use std::io;

fn main() {
    // 读取用户输入
    println!("Enter: Position");
    let mut position = String::new(); 
    io::stdin().read_line(&mut position).expect("failed to read"); 

    println!("Enter: Company Name");
    let mut coname = String::new(); 
    io::stdin().read_line(&mut coname).expect("failed to read"); 

    println!("Enter: Company Location");
    let mut location = String::new(); 
    io::stdin().read_line(&mut location).expect("failed to read"); 

    let sample = "This is some random Sample text, This text should eventaully be a user input. Currently, this text is not a user input. this text is supposed to be a text of long string data that will eventually be added to the document via user input";

    // 加载字体
    let mut fonts = Fonts::new();
    fonts.add_from_file("./fonts/TNR-Regular.ttf").unwrap();

    // 配置文档:页面尺寸、边距
    let mut doc = Document::new(fonts);
    doc.set_page_size(genpdf::PaperSize::Letter); // 对应216x279mm
    doc.set_margins(genpdf::Margins::mm(25.0));
    doc.set_page_decorator(SimplePageDecorator::new());

    // 添加内容,自动处理换行
    doc.push(Element::Paragraph(position.trim().to_string()));
    doc.push(Element::Paragraph(coname.trim().to_string()));
    doc.push(Element::Paragraph(location.trim().to_string()));
    doc.push(Element::Paragraph(String::new())); // 空行
    doc.push(Element::Paragraph(sample.to_string()));

    // 保存文档
    doc.save(&mut File::create("cover_letter.pdf").unwrap()).unwrap();
}

说明:genpdf会自动处理文本换行、行间距和页面布局,代码更简洁,后续扩展GUI功能时也更容易集成。

总结

  • 若想继续使用Printpdf,结合textwrap手动拆分换行是低成本解决方案;
  • 若追求开发效率和更丰富的排版功能,更换genpdf等高层库更适合,尤其后续要做跨平台GUI工具时,高层库的封装会减少很多重复工作。

内容的提问来源于stack exchange,提问作者THRASHER-Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:14:55