Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PDF 生成

Feature: pdf | 依赖: printpdf + allsorts

简介

PDF 文档生成工具。用户自行提供字体,支持 OTF/TTF 格式,支持中文、英文、数字排版。

使用 allsorts 进行字体子集化,仅将文档中实际用到的字形嵌入 PDF,大幅减小文件体积。

Builder 模式,链式调用,支持文本、表格、图片、图形。

快速开始

#![allow(unused)]
fn main() {
use afaster::{Pdf, TextStyle};

// 需要提供字体文件
let font_regular = std::fs::read("fonts/SourceHanSansSC-Regular.otf")?;
let font_bold = std::fs::read("fonts/SourceHanSansSC-Bold.otf")?;

let bytes = Pdf::new("发票")
    .font_regular(&font_regular)
    .font_bold(&font_bold)
    .text("增值税普通发票", TextStyle::title(), 60.0, 270.0)
    .text("购买方: 某某科技有限公司", TextStyle::body(), 15.0, 250.0)
    .text("金额: ¥12,493.00", TextStyle::body().bold(), 15.0, 230.0)
    .finish()?;
std::fs::write("invoice.pdf", bytes)?;
}

页面设置

#![allow(unused)]
fn main() {
use afaster::{Pdf, A4, A5, LETTER, LEGAL};

let pdf = Pdf::new("文档")
    .page_size(A4)     // 默认 210×297mm
    .page_size(A5)     // 148×210mm
    .page_size(LETTER) // 215.9×279.4mm
    .page_size(LEGAL)  // 215.9×355.6mm
    .page_size((Mm(200.0), Mm(300.0))); // 自定义
}

文本

#![allow(unused)]
fn main() {
use afaster::{TextStyle, PdfColor, Align};

// 预设样式
Pdf::new("doc")
    .text("标题", TextStyle::title(), x, y)       // 24pt 居中加粗
    .text("副标题", TextStyle::subtitle(), x, y)   // 16pt 加粗
    .text("正文", TextStyle::body(), x, y)          // 12pt
    .text("小字", TextStyle::small(), x, y)         // 9pt 灰色

    // 自定义样式
    .text("红色加粗", TextStyle::body()
        .color(PdfColor::red())
        .bold()
        .size(14.0), x, y)
    .text("居中", TextStyle::body()
        .align(Align::Center), x, y)
    .text("右对齐", TextStyle::body()
        .align(Align::Right), x, y)
}

TextStyle 方法

方法说明默认值
size(f64)字体大小 (pt)12.0
line_height(f64)行高 (pt)20.0
color(PdfColor)文字颜色黑色
bold()使用粗体字体false
align(Align)对齐方式Left

PdfColor

#![allow(unused)]
fn main() {
PdfColor::black()                         // 黑色
PdfColor::white()                         // 白色
PdfColor::red()                           // 红色(发票常用)
PdfColor::grey(0.5)                       // 灰度
PdfColor::Rgb { r: 0.2, g: 0.4, b: 0.8 } // 自定义 RGB (0.0~1.0)
PdfColor::Cmyk { c: 0.0, m: 0.23, y: 0.0, k: 0.0 } // CMYK
}

Align

#![allow(unused)]
fn main() {
Align::Left    // 左对齐(默认)
Align::Center  // 居中
Align::Right   // 右对齐
}

表格

#![allow(unused)]
fn main() {
// 默认样式(带表头背景、斑马纹、边框)
Pdf::new("报表")
    .table(
        &["产品", "数量", "金额"],
        &[
            &["笔记本", "2", "¥11998"],
            &["鼠标", "5", "¥495"],
        ],
    )

    // 简洁风格(无背景色)
    .table_with_style(
        &["姓名", "部门"],
        &[&["张三", "技术部"]],
        TableStyle::minimal(),
        15.0, 200.0,  // x, y 坐标
    )

    // 自定义列宽
    .table_with_widths(
        &["名称", "描述", "价格"],
        &[&["商品A", "描述文字", "99.00"]],
        &[50.0, 80.0, 30.0],  // 列宽 mm
    )
}

TableStyle

#![allow(unused)]
fn main() {
TableStyle::default()   // 默认:带背景色和边框
TableStyle::minimal()   // 简洁:无背景色,浅灰边框

TableStyle::default()
    .font_size(9.0)                    // 字体大小
}

图片

支持 PNG / JPG / BMP 格式。

#![allow(unused)]
fn main() {
let img_bytes = std::fs::read("logo.png")?;

Pdf::new("文档")
    .image(&img_bytes, 15.0, 250.0)                    // 原始尺寸
    .image_sized(&img_bytes, 15.0, 200.0, 30.0, 30.0) // 指定宽高 (mm)
}

图形

#![allow(unused)]
fn main() {
Pdf::new("文档")
    // 矩形 (x, y, w, h, 填充色, 边框色)
    .rect(15.0, 200.0, 80.0, 40.0,
        Some(PdfColor::grey(0.9)),
        Some(PdfColor::black()))

    // 直线 (点坐标, 颜色, 线宽)
    .line(&[(15.0, 180.0), (195.0, 180.0)],
        PdfColor::black(), 0.5)

    // 折线
    .line(&[(15.0, 160.0), (100.0, 170.0), (195.0, 160.0)],
        PdfColor::red(), 0.8)
}

完整发票示例

#![allow(unused)]
fn main() {
use afaster::{Pdf, TextStyle, TableStyle, PdfColor};

let bytes = Pdf::new("增值税普通发票")
    .text("增值税普通发票", TextStyle::title().size(22.0), 55.0, 275.0)
    .text("发票代码: 044001900111", TextStyle::body().size(10.0), 15.0, 258.0)
    .text("发票号码: 12345678", TextStyle::body().size(10.0), 130.0, 258.0)
    .line(&[(15.0, 243.0), (195.0, 243.0)], PdfColor::black(), 0.5)
    .text("购买方: 某某科技有限公司", TextStyle::body().size(10.0), 15.0, 233.0)
    .table_with_style(
        &["货物名称", "数量", "单价", "金额", "税率", "税额"],
        &[
            &["笔记本电脑", "2", "5999.00", "11998.00", "13%", "1559.74"],
            &["无线鼠标", "5", "99.00", "495.00", "13%", "64.35"],
        ],
        TableStyle::minimal().font_size(9.0),
        15.0, 140.0,
    )
    .text("价税合计: ¥14,117.09",
        TextStyle::body().bold().size(14.0).color(PdfColor::red()),
        150.0, 100.0)
    .finish()?;
}

字体

字体由用户通过 font_regular() / font_bold() 提供,支持 OTF 和 TTF 格式。

推荐使用思源黑体(Source Han Sans SC),SIL Open Font License,可商用:

字体用途
SourceHanSansSC-Regular.otf正文
SourceHanSansSC-Bold.otf加粗

覆盖范围:中文(简体)、英文、数字、常用标点。

#![allow(unused)]
fn main() {
let font_regular = std::fs::read("fonts/SourceHanSansSC-Regular.otf")?;
let font_bold = std::fs::read("fonts/SourceHanSansSC-Bold.otf")?;

let bytes = Pdf::new("文档")
    .font_regular(&font_regular)
    .font_bold(&font_bold)
    .text("内容", TextStyle::body(), 15.0, 250.0)
    .finish()?;
}

注意: font_regular 是必须的。如果未提供 font_bold,将自动使用 regular 字体代替。

使用 allsorts 进行字体子集化,仅嵌入文档中实际用到的字形,大幅减小 PDF 体积。

坐标系

PDF 坐标原点在左下角,x 向右,y 向上,单位 mm。

A4 页面常用坐标参考:

(0,297) ───────────────── (210,297)
  │                           │
  │     标题 y≈270            │
  │     正文 y≈250            │
  │     表格 y≈100~200        │
  │     页脚 y≈20             │
  │                           │
(0,0) ──────────────────── (210,0)

错误码

code含义
51701字体加载/解析失败
51702字体子集化失败
51703图片处理失败