字体
TCPDF-Next 支持 TrueType、OpenType 及 Type1 字体,并提供自动子集化、CJK 渲染与双向文字排版功能。字体可通过 Document 上的 addFont() 方法载入,或直接使用 FontManager 进行管理。
支持的字体格式
| 格式 | 扩展名 | 说明 |
|---|---|---|
| TrueType | .ttf | 完整的字形轮廓支持,最常见的字体格式 |
| OpenType | .otf | 同时支持 CFF 与 TrueType 轮廓变体 |
| Type1 | .pfb + .afm | 传统 PostScript 字体,需搭配度量文件 |
核心字体
PDF 规范定义了 14 种标准字体(即「Base 14」),所有合规的 PDF 阅读器都必须支持。使用这些字体无需嵌入,能有效缩小文件大小。
| 字体家族 | 样式 |
|---|---|
| Helvetica | Regular、Bold、Italic、Bold Italic |
| Times | Regular、Bold、Italic、Bold Italic |
| Courier | Regular、Bold、Italic、Bold Italic |
| Symbol | Regular |
| ZapfDingbats | Regular |
use Yeeefang\TcpdfNext\Core\Document;
$pdf = Document::create()
->addPage()
->setFont('Helvetica', '', 12)
->cell(0, 10, 'Helvetica — PDF 的主力字体', newLine: true)
->setFont('Times', 'I', 12)
->cell(0, 10, 'Times Italic — 经典衬线字体', newLine: true)
->setFont('Courier', 'B', 12)
->cell(0, 10, 'Courier Bold — 等宽字体', newLine: true);自定义字体载入
addFont()
注册一个 TrueType 或 OpenType 字体文件,随后即可直接使用。
$pdf = Document::create()
->addFont('NotoSansTC', '', '/path/to/NotoSansTC-Regular.ttf')
->addPage()
->setFont('NotoSansTC', '', 12)
->cell(0, 10, '繁体中文文字', newLine: true);多样式字体家族
将同一字体家族的各样式变体以相同的家族名称注册。当你调用 setFont() 时带入样式字符串,TCPDF-Next 会自动选择对应的字体文件。
$pdf = Document::create()
->addFont('Roboto', '', '/fonts/Roboto-Regular.ttf')
->addFont('Roboto', 'B', '/fonts/Roboto-Bold.ttf')
->addFont('Roboto', 'I', '/fonts/Roboto-Italic.ttf')
->addFont('Roboto', 'BI', '/fonts/Roboto-BoldItalic.ttf')
->addPage()
->setFont('Roboto', '', 11)
->cell(0, 10, 'Regular weight', newLine: true)
->setFont('Roboto', 'B', 11)
->cell(0, 10, 'Bold weight', newLine: true)
->setFont('Roboto', 'I', 11)
->cell(0, 10, 'Italic style', newLine: true)
->setFont('Roboto', 'BI', 11)
->cell(0, 10, 'Bold Italic', newLine: true);字体子集化
默认情况下,TCPDF-Next 只会嵌入文档中实际出现的字形。FontSubsetter 会在 PDF 序列化过程中自动处理子集化。
// 字体子集化是自动进行的 — 只有使用到的字形会被嵌入
$pdf = Document::create()
->addPage()
->setFont('DejaVuSans', '', 12)
->cell(0, 10, 'Only these glyphs are embedded');
// 结果:更小的 PDF 文件大小为什么子集化很重要
一套完整的 CJK 字体可能超过 15 MB。如果你的文档只用到少数几个字符,子集化可以将嵌入的字体数据缩减至几 KB。对于网页传输和电子邮件附件来说,这是至关重要的优化。
停用子集化
在少数情况下(例如可编辑的表单字段,用户可能输入任意字符),你可能需要完整的字体。在注册字体时将 subset 参数设为 false 即可:
$pdf->addFont('NotoSans', '', '/fonts/NotoSans-Regular.ttf', subset: false);CJK 支持
中文、日文及韩文文字需要具备大量字形集合的字体。TCPDF-Next 通过 CjkValidator 验证 CJK 内容,并确保 PDF 输出中的编码正确无误。
$pdf = Document::create()
->addFont('NotoSansCJK', '', '/fonts/NotoSansCJKtc-Regular.otf')
->addPage()
->setFont('NotoSansCJK', '', 12)
->cell(0, 10, '中文:你好世界', newLine: true)
->cell(0, 10, '日本語:こんにちは世界', newLine: true)
->cell(0, 10, '한국어:안녕하세요 세계', newLine: true);CJK 字体一律会进行子集化(除非明确停用),因为文件大小的节省非常可观。
双向文字 (BiDi)
BiDiResolver 实现了 Unicode 双向算法,能正确渲染阿拉伯文、希伯来文等从右到左书写的文字,也支持 LTR/RTL 混合的内容。
$pdf = Document::create()
->addFont('NotoSansArabic', '', '/fonts/NotoSansArabic-Regular.ttf')
->addPage()
->setFont('NotoSansArabic', '', 14)
->cell(0, 10, 'مرحبا بالعالم', newLine: true) // 阿拉伯文
->write(10, 'Mixed: Hello مرحبا World'); // LTR + RTL 混合当文字中包含 RTL 字符时,BiDi 重排会自动应用,无需任何手动配置。
ToUnicode CMap
TCPDF-Next 会为每个嵌入的字体生成 ToUnicode CMap。这个映射表让 PDF 阅读器能在用户复制粘贴时提取正确的 Unicode 文字,也使搜索引擎能正确索引文档内容。它会在序列化过程中自动生成。
字体度量
FontInfo 与 FontMetrics 类公开了详细的排版度量数据。
$pdf->setFont('Helvetica', '', 12);
// 测量当前字体下特定字符串的宽度
$width = $pdf->getStringWidth('Hello, World!');
// 利用度量数据进行精准排版
$cellWidth = $pdf->getStringWidth('Total:') + 4; // 加上 4mm 的内距
$pdf->cell($cellWidth, 8, 'Total:');度量数据涵盖上升线(ascender)、下降线(descender)、行距(line gap)、大写高度(cap height)、x 字高(x-height)以及逐字形的前进宽度 — 全部取自字体内部的表格。
完整示例
use Yeeefang\TcpdfNext\Core\Document;
$pdf = Document::create()
// 注册字体
->addFont('Roboto', '', '/fonts/Roboto-Regular.ttf')
->addFont('Roboto', 'B', '/fonts/Roboto-Bold.ttf')
->addFont('NotoSansTC', '', '/fonts/NotoSansTC-Regular.ttf')
->addPage()
// 英文标题
->setFont('Roboto', 'B', 18)
->cell(0, 12, 'Multilingual Invoice', newLine: true)
->ln(3)
// 英文正文
->setFont('Roboto', '', 11)
->cell(0, 8, 'Customer: Acme Corporation', newLine: true)
->cell(0, 8, 'Date: 2026-02-16', newLine: true)
->ln(5)
// 中文区段
->setFont('NotoSansTC', '', 11)
->cell(0, 8, '客户名称:台湾科技有限公司', newLine: true)
->cell(0, 8, '发票日期:2026年2月16日', newLine: true)
->save('multilingual-invoice.pdf');