从 mPDF 迁移到 NextPDF
快速概览
标题为“快速概览”的章节本指南将帮助你把基于 mPDF 的代码迁移到 NextPDF core。mPDF 的核心操作是 WriteHTML(),可直接映射到 Document::writeHtml()。真正费工的是构造函数 config 数组的映射(mPDF 将所有设置都放在传给 new Mpdf([...]) 的单个关联数组中),以及字体处理差异。NextPDF 与 mPDF 是相互独立的引擎,因此迁移后的文档与 mPDF 输出 兼容,但不会逐字节相同。本指南涵盖动词映射、config 数组映射、字体差异、CSS 支持差异、行为差异,以及一套安全的迁移顺序。
哪些 HTML/CSS 功能已经验证(Verified),以 CSS 支持对照表 为准。本指南描述的是行为,并不主张与 mPDF 在视觉上等价。
composer require nextpdf/core:^3过渡期间请保留 mpdf/mpdf 的安装。在最终切换之后再移除它(见 安全迁移顺序 一节)。
概念总览
标题为“概念总览”的章节mPDF 的 Mpdf 对象是一个庞大的单一 facade(外观):通过一个构造函数数组完成配置,再由 WriteHTML() 加上分页操作(AddPage、SetHTMLHeader、SetHTMLFooter)来驱动。NextPDF 把设置拆分到不可变的 NextPDF\Core\Config 值对象中,并以 Document::writeHtml() 驱动内容。它没有构造函数层面的「mode」字符串。NextPDF 会解析你传入的 HTML,再以 save()、output() 或 getPdfData() 输出文档。
字体方面:mPDF 随附一个字体目录,并配有一份 fontdata 映射表和一组「核心字体」回退集。NextPDF 通过单一字体目录加 CSS font-family 匹配来 resolve(解析)字体,并 一律 对嵌入字体做子集化(ISO 32000-2 §9,iso32000_2_sec9#x1.x45.p7)。字体的 matching/fallback(匹配/回退)由各引擎自行定义(CSS Fonts 4 §5.5,css_fonts_4#x1.x5.x5.x1.p13),因此字形替换结果可能不同。这是主要可见的差异,详见 字体处理差异 一节。
API 接口
标题为“API 接口”的章节NextPDF 的 HTML API 请参见 Html 模块 参考文档。主要入口包括:Document::createStandalone()、Document::writeHtml(string $html): static、Document::writeHtmlCell(...)、Document::addPage()、Document::output(?string, OutputDestination)、Document::save(string $path): void、Document::getPdfData(): string,以及 NextPDF\Core\Config 值对象。
API 动词映射
标题为“API 动词映射”的章节下方的 mPDF 公开方法名称已逐一对照上游公开仓库(mpdf/mpdf 的 development)确认;请参见仓库内的 _source-sidecar-upstream-api.md 来源 sidecar 文件。未复刻任何上游文档文本。
| mPDF | NextPDF | 说明 |
|---|---|---|
new Mpdf([...]) | Document::createStandalone($config) | mPDF 的 config 数组映射到 NextPDF\Core\Config;见 config 映射 一节。长生命周期 worker 请使用 DocumentFactory。 |
$mpdf->WriteHTML($html) | $doc->writeHtml($html) | 直接映射。mPDF 的第二个 $mode 参数(用于区分完整文档、仅 CSS、单一元素)在 NextPDF 没有对应项,请改传完整 HTML。 |
$mpdf->WriteFixedPosHTML(...) | $doc->writeHtmlCell(...) | 带定位/尺寸的 HTML 区域;映射 x/y/width/height 等参数。 |
$mpdf->AddPage(...) | $doc->addPage() | mPDF 那种逐次调用中的 orientation/format/页边距覆盖,在 NextPDF 中不是参数;请改在调用之间调整文档模型。 |
$mpdf->SetHTMLHeader($html) / SetHTMLFooter($html) | 通过 Layout API 设置 header/footer(页眉/页脚) | mPDF 的运行时 HTML 页眉映射到 NextPDF 的 header/footer 机制,而不是映射到正文顶端的内联 HTML。 |
$mpdf->Output($name, $dest) | $doc->output($name, OutputDestination::…) | mPDF 的目标字符(I/D/F/S)映射到 OutputDestination 枚举(Inline/Download/file);文件输出改用 save(),字符串输出改用 getPdfData()。 |
$mpdf->Output('','S') | $doc->getPdfData() | 返回字节。 |
$mpdf->Output($path,'F') | $doc->save($path) | 写入文件路径。 |
$mpdf->SetTitle($t) | $doc->setTitle($t) | 写入 ISO 32000-2 §14 的 info 字典/XMP(iso32000_2_sec14#x1.x5.p5)。 |
$mpdf->SetProtection($perms,...) | $doc->setEncryption(...)(Security API,安全性 API) | 权限依赖阅读器配合,并非访问控制,见 安全性说明 一节。 |
代码范例 — 快速开始
标题为“代码范例 — 快速开始”的章节<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// mPDF:// $mpdf = new \Mpdf\Mpdf();// $mpdf->WriteHTML('<h1>Invoice</h1>');// $mpdf->Output('out.pdf', \Mpdf\Output\Destination::FILE);
// NextPDF — default page is A4 portrait:$doc = Document::createStandalone();$doc->setTitle('Invoice');$doc->addPage();$doc->writeHtml('<h1>Invoice</h1>');$doc->save(__DIR__ . '/out.pdf');
echo "Wrote out.pdf\n";代码范例 — 正式环境
标题为“代码范例 — 正式环境”的章节这与 examples/04-text-and-fonts.php 一致,是本指南字体处理概念的可运行示例。它使用明确的页面尺寸、页边距,以及一段会触发字体选择的正文内容。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\OutputDestination;use NextPDF\Core\Config;use NextPDF\Core\Document;use NextPDF\ValueObjects\Margin;use NextPDF\ValueObjects\PageSize;
// Equivalent of: new Mpdf(['format'=>'A4','margin_left'=>20, ...]).// Margin constructor order is (top, right, bottom, left) — NOT L,R,T,B.$config = new Config( pageSize: new PageSize(595.276, 841.890, 'A4'), margins: new Margin(16.0, 20.0, 16.0, 20.0), // top,right,bottom,left in points fontsDirectory: __DIR__ . '/fonts',);
$doc = Document::createStandalone($config);$doc->setTitle('Quarterly Report');$doc->addPage();
$html = <<<'HTML'<h1 style="font-family:'DejaVu Sans';color:#1E3A8A;">Quarterly Report</h1><p>Body text resolves through CSS font-family matching against the configuredfonts directory. mPDF's fontdata map has no direct analogue — register thefamily via CSS and the fonts directory instead.</p>HTML;
$doc->writeHtml($html);
// Equivalent of $mpdf->Output('report.pdf', Destination::DOWNLOAD):$doc->output('report.pdf', OutputDestination::Download);边界情况与陷阱
标题为“边界情况与陷阱”的章节$mode参数属于WriteHTML。 mPDF 的WriteHTML($html, $mode)(2 = 仅 CSS,1 = 元素)并无对等项。请把你的 CSS 内联到传入的 HTML 中;不存在「先写 CSS 再写正文」的流程。- 逐次
AddPage覆盖。 mPDF 允许AddPage()通过参数在文档中途变更 format/orientation。NextPDF 的addPage()不接受这类参数;尺寸变更应通过文档模型表达,而不是通过页面调用传参。 - 页眉/页脚 HTML。 mPDF 的运行时页眉是另外注册的 HTML 片段;请勿把它们粘进正文里。请把它们映射到 NextPDF 的 header/footer 机制。
- 字体名称。 mPDF 通过它的
fontdata/core-font 表来规范化字体名称。NextPDF 会把 CSS 的font-family与字体目录匹配;某个在 mPDF 中能默默解析的别名,可能需要明确的@font-face/family。 - 目标字符。 不接受
'I'/'D'/'F'/'S';请使用OutputDestination枚举,或save()/getPdfData()。
writeHtml() 是单次处理(ADR-001);峰值内存随文档大小变动,而不是随保留的 DOM 变动。本指南示例的预算:wall_ms: 2000, peak_mb: 128。对于长文档,请把内容分页到多个 addPage(),不要塞进一个巨大的字符串。这与 mPDF 的 $mode 分段做法是同一套建议,只是改用页面模型来表达。
安全性说明
标题为“安全性说明”的章节- 权限依赖阅读器配合。
SetProtection()→setEncryption()提供的是保密性,而非访问控制:ISO 权限位是否生效取决于阅读器是否配合。请勿把加密向用户描述成访问控制。 - 元数据。
SetTitle()与文档 info 会写入 ISO 32000-2 §14 的信息字典/XMP(iso32000_2_sec14#x1.x5.p5);切勿在那里保存任何秘密信息。 - NextPDF 不会运行文档内的脚本;这里没有任何 mPDF 指令会激活这类功能。
符合性
标题为“符合性”的章节| 陈述 | 规范 | 条款 | 参考 ID |
|---|---|---|---|
| 字体会写为 embedded/subset(嵌入/子集化)字体程序。 | ISO 32000-2 | §9 | |
| 页面的 format/margins(格式/页边距)映射到页面边界框。 | ISO 32000-2 | §7 | |
| 标题/保护元数据会写入 info 字典/XMP 中。 | ISO 32000-2 | §14 | |
| 字体匹配/回退由各引擎自行定义。 | CSS Fonts 4(CSS 字体规范) | §5.5 |
NextPDF 产生的是 ISO 32000-2 内容;它并不主张与 mPDF 在视觉上完全一致。只要 renderer(渲染器)发生变更,就需要重新复核输出。
商业情境
标题为“商业情境”的章节不适用。core 已涵盖这里描述的 mPDF 迁移路径。
另请参阅
标题为“另请参阅”的章节迁移细节(R6 必备章节)
标题为“迁移细节(R6 必备章节)”的章节这份指南适合谁
标题为“这份指南适合谁”的章节适用于在服务器端使用 mpdf/mpdf 做 HTML 转 PDF 的团队。如果你的接口是 new Mpdf([...]) + WriteHTML + Output(以及可选的 header/footer),那么 动词映射 与 config 映射 就已经涵盖。
范围内:Mpdf 构造函数 config 数组、WriteHTML/Output/AddPage、headers/footers、字体、保护、元数据。范围外:mPDF 的内部类,以及 QR/条码/水印的辅助接口(请把这些映射到对应的 NextPDF 模块,即 Barcode、Graphics;本文不涵盖)。
兼容性映射
标题为“兼容性映射”的章节这里说的是行为兼容,并非可直接替换的 shim(兼容层):不存在 Mpdf 类的兼容层。每一个调用点都需要改写。CSS 功能预期以 CSS 支持对照表 的 Verified 列为准。
建构式 config 数组映射
标题为“建构式 config 数组映射”的章节mPDF 的 config 键已对照上游公开仓库(mpdf/mpdf 的 development)确认。未复刻任何上游文档文本。
| mPDF config 键 | NextPDF | 说明 |
|---|---|---|
mode | (无对等项) | mPDF 的 mode 字符串('utf-8'、'c'、'+aCJK' 等)选择 font/script(字体/书写系统)行为。NextPDF 始终使用 Unicode;CJK 由字体选择处理,而不是由某个 mode 处理。请删除这个键。 |
format | Config->pageSize(PageSize VO) | 命名格式会转换为明确的点(point)尺寸;数组 [w,h] 映射到一个 PageSize。 |
orientation | 对调 PageSize 的 width/height | 没有方向标志;横向 = 宽 > 高。 |
default_font_size | CSS 基准 font-size | 通过你的基准样式表设置,而不是通过构造函数的键。 |
default_font | CSS font-family/已注册字体 | 通过 CSS/字体注册来设置默认字族。 |
margin_left / margin_right / margin_top / margin_bottom | Config->margins(Margin VO),以点为单位 | 单一 Margin 值对象;它的构造函数顺序是 Margin(top, right, bottom, left)(请对照 src/ValueObjects/Margin.php 确认),而不是 mPDF 的键顺序。 |
margin_header / margin_footer | 通过 Layout API 设置 header/footer 偏移 | 请映射到 NextPDF 的 header/footer 设置,而不是构造函数的键。 |
字体处理差异
标题为“字体处理差异”的章节- 单一字体目录。 mPDF 的字体目录列表 +
fontdata映射表 + 核心字体回退,全部统一为Config->fontsDirectory加 CSSfont-family匹配。 - 一律子集化。 NextPDF 一律对嵌入字体做子集化(ISO 32000-2 §9,
iso32000_2_sec9#x1.x45.p7);mPDF 的子集化标志并无对等项,也不需要。 - 匹配由各引擎自行定义。 字体的 matching/fallback 因引擎而异(CSS Fonts 4 §5.5,
css_fonts_4#x1.x5.x5.x1.p13);某个 mPDF 字体别名可能需要明确的@font-face或精确的字族名称。迁移后请重新建立字形渲染基准;替换差异是预期内的,并非缺陷。
行为差异
标题为“行为差异”的章节- 字体替换(见上文)——主要可见的差异。
WriteHTML上没有$mode——请传入含内联 CSS 的完整 HTML。- 没有逐次
AddPage的 format 覆盖——尺寸变更通过文档表达。 - 权限依赖阅读器配合(见 安全性说明 一节)。
- 独立的版面引擎——在密集内容上,断行/分页会有所不同;请重新建立视觉差异基准。
这些是有记录的行为差异,而非任一引擎的缺陷。
不支持/没有直接对等项
标题为“不支持/没有直接对等项”的章节mode构造函数字符串——未建模(始终使用 Unicode)。- 逐
AddPage()的 format/orientation/页边距参数——在 NextPDF 中不是参数。 - mPDF 的
fontdata映射表——由字体目录加 CSS 匹配取代。 - mPDF 的
'I'/'D'/'F'/'S'目标字符——由OutputDestination枚举加上save()/getPdfData()取代。
安全迁移顺序
标题为“安全迁移顺序”的章节- 把
nextpdf/core与mpdf/mpdf并存安装(暂时保留 mPDF)。 - 挑一份低风险的文档。把
new Mpdf([...])通过 config 映射 转换,并把WriteHTML/Output通过 动词映射 转换。 - 把该文档用到的字体注册到
Config->fontsDirectory,并为任何 mPDF 别名加上明确的@font-face/family 声明。 - 对同一份输入产生两份 PDF;做视觉差异比对。差异(字体替换、断行)对独立引擎而言是预期行为——请逐份文档确认接受。
- 把任何 header/footer HTML 映射到 NextPDF 的 header/footer 机制。
- 逐份文档重复,最低风险的先做;保留 mPDF 安装直到最后一次切换。
- 在最终切换之后,把
mpdf/mpdf从composer.json移除。
测试迁移
标题为“测试迁移”的章节- 在改动代码之前,先快照代表性文档的 mPDF 输出(作为 golden 参考;字节会有所不同)。
- 对逐份迁移的文档,用你自己的验收检查来断言(视觉差异比对 + 文本截取)。NextPDF 的字体/HTML 行为由
examples/04-text-and-fonts.php与examples/08-html-basic.php加上内核tests/的 Html/Font 测试套件实际验证。迁移验收因文档而异,由你自行负责。 - 为每一份迁移的文档加上一个回归测试。
佐证/可追溯性
标题为“佐证/可追溯性”的章节本页每一项 NextPDF 行为陈述,都有仓库内的测试、示例、源码签名或 ADR 支持;若属 PDF 格式特性,则由 front-matter(前置数据)citations: 中 RAG 固定的 ISO 32000-2 / CSS 条款,以及 符合性 表佐证。mPDF 的行为仅以「独立引擎——预期会有记录在案的差异」来陈述;不会主张任何仓库内产物无法证明的对等性。
| NextPDF 行为主张 | 仓库内佐证(路径) |
|---|---|
WriteHTML() 直接映射到 Document::writeHtml(string $html): static。 | src/Core/Concerns/HasTextOutput.php(writeHtml());examples/08-html-basic.php。 |
WriteFixedPosHTML(...) 映射到 writeHtmlCell(...)。 | src/Core/Concerns/HasTextOutput.php(writeHtmlCell())。 |
createStandalone() 的默认页面为 A4 纵向(595.276 × 841.890 pt)。 | src/Core/Config.php(默认 PageSize);tests/Unit/Core/DocumentCreateStandaloneAndConfigWithersEdgeCaseTest.php。 |
Margin 的构造函数顺序是 (top, right, bottom, left)。 | src/ValueObjects/Margin.php(属性提升顺序)。 |
输出目的地是 NextPDF\Contracts\OutputDestination 枚举;不接受 'I'/'D'/'F'/'S'。 | src/Contracts/OutputDestination.php(枚举项 Inline/Download/File/String);tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php。 |
Output('','S') → getPdfData();Output($path,'F') → save($path)。 | src/Core/Concerns/HasOutput.php(getPdfData()、save()、output())。 |
SetProtection() 映射到 setEncryption(...);权限依赖阅读器配合。 | src/Core/Concerns/HasSecurity.php(setEncryption());ISO 32000-2 §14(前置数据 citations:)。 |
SetTitle() → setTitle();元数据会写入 info 字典/XMP 中。 | src/Core/Concerns/HasMetadata.php(setTitle());tests/Unit/Core/Concerns/DocumentInfoMetadataSetterBaselineTest.php;ISO 32000-2 §14(前置数据 citations:)。 |
| 字体始终以子集化程序的形式嵌入。 | tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php;examples/04-text-and-fonts.php;ISO 32000-2 §9(前置数据 citations:)。 |
| 字体匹配/回退由各引擎自行定义(替换差异)。 | CSS Fonts 4 §5.5(front-matter citations: + 符合性 一节)。 |
writeHtml() 是单次处理;尖峰内存随文档大小变动。 | docs/architecture/adr/ADR-001-stream-based-rendering-pipeline.md。 |
两个包都会保留安装直到最终切换,因此单个调用点的回滚,就是将该调用点还原到 mPDF 路径。最终切换之后,回滚就是从版本控制还原 mpdf/mpdf 与先前代码。不涉及任何数据迁移。
性能考量
标题为“性能考量”的章节见 性能 一节。单次处理模型移除了 mPDF 那种保留缓冲区带来的成本。新增的逐文档成本是急切(eager)字体解析(步骤 3),可通过字体目录缓存降低。
常见陷阱
标题为“常见陷阱”的章节- 保留
mode键并期望它带来 CJK 行为(应删除它;CJK 由字体选择决定)。 - 传入
WriteHTML($html, 2)(仅 CSS 模式)——请改用内联 CSS。 - 把 header/footer HTML 粘进正文里。
- 在没有明确字族的情况下,期望某个 mPDF 别名获得相同字体。
- 期望输出 byte/pixel-identical(逐字节/逐像素相同)(独立引擎 — 本指南从未主张可直接替换或 100% 兼容)。
- 把 CSS 支持对照表当成仅供参考——它是已验证功能的权威依据。