從 FPDF 遷移到 NextPDF
快速概覽
標題為「快速概覽」的區段本指南幫你把一份以 FPDF 為基礎的程式碼搬移到
NextPDF core。FPDF 是部署最廣的舊式 PHP 可攜式文件格式(PDF)函式庫之一,而它的繪圖介面——由一個手動 x/y
游標驅動的 AddPage、SetFont、Cell、MultiCell、Write、Text、Image、Output——
乾淨地對映到 NextPDF 自己的 cell/text API,因為 NextPDF 的低階繪圖方法遵循同樣的 FPDF/TCPDF 血統。不過 NextPDF 不 是一個可直接替換的 FPDF 複製品:它是一個現代 PDF 2.0 引擎,帶有嚴格型別、
字型子集化、簽章、PDF/A 與無障礙性(tagged PDF)。兩個真正的轉變是 單位模型(NextPDF 以 PDF 點工作;FPDF 預設為公釐)與 輸出動詞(一個有型別的 OutputDestination 列舉,取代 FPDF 的
'I'/'D'/'F'/'S' 字元)。
core 中沒有 FPDF 類別的相容層。請用
動詞對映 改寫每一處呼叫點。如果你想要為一份
TCPDF 6.x 程式碼做最小的初始改動,請改見
TCPDF 相容轉接器,它隨附一條近乎原始碼相容的可直接替換路徑;FPDF 沒有這樣的轉接器。
composer require nextpdf/core:^3遷移期間請保留 setasign/fpdf(或你的 fpdf/fpdf)的安裝。等到最終切換之後再移除它(見 安全遷移順序)。
概念總覽
標題為「概念總覽」的區段FPDF 與 NextPDF 共用同樣的心智模型:一份由頁面構成的文件、一個
游標(目前的 x/y 位置),以及在游標處繪製或推進游標的動詞。SetXY、Cell、Ln 與 MultiCell 在兩個函式庫中都會讀取並變更游標,所以大多數程序式 FPDF 程式碼能逐行翻譯。
這些差異是刻意的,不是意外:
- 單位。 FPDF 的建構式(
new FPDF($orientation, $unit, $size))預設為公釐。NextPDF 以 PDF 點工作(1 pt = 1/72 in,ISO 32000-2 §7)。 沒有文件全域的單位旋鈕——把 mm 轉成點一次 (pt = mm * 72 / 25.4)。 - Y 方向對你而言維持不變。 與 FPDF 一樣,NextPDF 的使用者座標把
y = 0放在頁面頂端並向下增加,所以游標算術可直接移植。NextPDF 會在內部轉成 PDF 原生的左下角原點。 - 建構是明確的。 FPDF 把方向、單位與尺寸折進建構式;NextPDF 接受一個不可變的
NextPDF\Core\Config值物件 (頁面尺寸、邊界、字型目錄)與一個明確的addPage()。 - 永遠 Unicode、永遠子集化。 FPDF 的核心建置是 Latin-1,需要
tFPDF/UTF-8 變體才能用 Unicode。NextPDF 全程是 UTF-8,並 永遠
把字型內嵌為子集程式(ISO 32000-2 §9)。FPDF 的
AddFont/字型度量檔沒有對應項;請註冊一個 TrueType/OpenType 字型目錄,並以名稱選取字族。
API 介面
標題為「API 介面」的區段下面用到的核心進入點是 Document::createStandalone()、
Document::addPage()、Document::setFont()、Document::cell()、
Document::multiCell()、Document::text()、Document::write()、
Document::ln()、Document::image()、游標存取器(setXY/setX/
setY/getX/getY)、Document::output(?string, OutputDestination)、
Document::save(string $path): void、Document::getPdfData(): string,以及
NextPDF\Core\Config 值物件。這些核心繪圖、文字與輸出方法的完整參考,位於 核心模組
與 參考索引,由 PHPDoc 自動產生。
Html 模組 是 HTML 轉 PDF 的相關閱讀,而不是本頁這些動詞的參考。
API 動詞對映
標題為「API 動詞對映」的區段FPDF 的公開方法名稱由來已久且廣為人知。下面的 NextPDF 欄已對照核心原始碼簽章確認(見 佐證/可追溯性)。
| FPDF | NextPDF | Notes |
|---|---|---|
new FPDF($orient, $unit, $size) | Document::createStandalone($config) | 方向/單位/尺寸建構式引數變成一個 NextPDF\Core\Config(pageSize、margins、fontsDirectory)。沒有 $unit——以點工作。預設 createStandalone() 頁面是 A4 直向。 |
$pdf->AddPage($orient, $size) | $doc->addPage($size, $orientation) | 直接對映。$size 是一個 PageSize 值物件;$orientation 是 Orientation 列舉(Portrait/Landscape)。 |
$pdf->SetFont($family, $style, $size) | $doc->setFont($family, $style, $size) | 直接對映。$style 使用相同的 ''/'B'/'I'/'BI'(加上 'U' 底線)代碼。 |
$pdf->Cell($w, $h, $txt, $border, $ln, $align, $fill) | $doc->cell($w, $h, $txt, $border, $newLine, $align, $fill) | 直接對映。$align 是 Alignment 列舉(Left/Center/Right/Justify);$border 接受 bool 或一個 'LTRB' 字串;$ln 變成 bool $newLine。 |
$pdf->MultiCell($w, $h, $txt, $border, $align, $fill) | $doc->multiCell($w, $h, $txt, $border, $align) | 依實際字型度量斷字。沒有 $fill 引數;如果你需要背景,先繪製一個填滿的 rect()。 |
$pdf->Write($h, $txt, $link) | $doc->write($h, $txt, $link) | 從游標流出的文字;$link 附上一個 URL 連結註解。 |
$pdf->Text($x, $y, $txt) | $doc->text($x, $y, $txt) | 絕對定位文字。直接對映。 |
$pdf->Ln($h) | $doc->ln($h) | 換行到左邊界;0 = 預設行高。 |
$pdf->Image($file, $x, $y, $w, $h) | $doc->image($file, $x, $y, $w, $h) | 直接對映;$x/$y/$w/$h 可為 null(null = 目前游標 / 內在尺寸)。 |
$pdf->SetXY($x, $y) / SetX / SetY | $doc->setXY($x, $y) / setX / setY | 直接對映。getX()/getY() 讀取游標。 |
$pdf->SetMargins($l, $t, $r) | $doc->setMargins(new Margin($t, $r, $bottom, $l)) | 一個 Margin 值物件;建構式順序是 (top, right, bottom, left)——不是 FPDF 的 (left, top, right)。FPDF SetMargins 沒有 bottom 引數(它的 bottom 邊界來自 SetAutoPageBreak($auto, $margin)),所以請自己選 $bottom——常見做法是等於 top 邊界,或傳入自動分頁邊界。 |
$pdf->SetAutoPageBreak($auto, $margin) | $doc->setAutoPageBreak($auto, $margin) | 直接對映。 |
$pdf->SetDrawColor / SetFillColor / SetTextColor | $doc->setDrawColor / setFillColor / setTextColor | RGB (r, g, b),或灰階用單一值。 |
$pdf->Line / Rect / SetLineWidth | $doc->line / rect / setLineWidth | 直接對映。rect() 接受一個樣式字串('S'/'F'/'DF')。 |
$pdf->SetTitle/SetAuthor/SetSubject/SetKeywords/SetCreator | $doc->setTitle/setAuthor/setSubject/setKeywords/setCreator | 直接對映。會落在 ISO 32000-2 §14 的資訊字典 / 可延伸中繼資料平台(XMP)。 |
$pdf->Output($dest, $name) | $doc->output($name, OutputDestination::…) | FPDF 目的地字元(I/D/F/S)對映到 OutputDestination 列舉;注意 引數順序互換(在 NextPDF 中 name 在前)。 |
$pdf->Output('S') | $doc->getPdfData() | 回傳 PDF 位元組。 |
$pdf->Output('F', $path) | $doc->save($path) | 寫入一個檔案路徑。 |
$pdf->GetStringWidth($s) | (無公開方法) | 字串寬度在 cell()/multiCell() 斷字期間於內部計算;沒有公開的逐字串量測動詞。請透過 multiCell() 驅動斷字,而不是自己手動量測。 |
程式碼範例 — 快速開始
標題為「程式碼範例 — 快速開始」的區段<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\Alignment;use NextPDF\Core\Document;
// FPDF:// $pdf = new FPDF(); // mm, A4 portrait// $pdf->AddPage();// $pdf->SetFont('Arial', 'B', 16);// $pdf->Cell(40, 10, 'Invoice');// $pdf->Output('F', 'out.pdf');
// NextPDF — points, default page is A4 portrait:$doc = Document::createStandalone();$doc->setTitle('Invoice');$doc->addPage();$doc->setFont('Helvetica', 'B', 16.0);$doc->cell(113.4, 28.3, 'Invoice', false, true, Alignment::Left); // ~40mm x ~10mm in points$doc->save(__DIR__ . '/out.pdf');
echo "Wrote out.pdf\n";程式碼範例 — 正式環境
標題為「程式碼範例 — 正式環境」的區段這個範例與 examples/04-text-and-fonts.php 一致。它使用一個明確的頁面尺寸、邊界、一個已註冊的字型目錄,以及一份 FPDF 程式碼已經在用的游標驅動 cell 模型。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\Alignment;use NextPDF\Contracts\OutputDestination;use NextPDF\Core\Config;use NextPDF\Core\Document;use NextPDF\ValueObjects\Margin;use NextPDF\ValueObjects\PageSize;
// Equivalent of: new FPDF('P', 'mm', 'A4') + SetMargins(20, 16, 20)// i.e. FPDF left=20mm, top=16mm, right=20mm. FPDF SetMargins has no bottom// argument, so we pick bottom = top = 16mm. Convert each mm to points// (pt = mm * 72 / 25.4): 16mm = 45.354pt, 20mm = 56.693pt.// Margin constructor order is (top, right, bottom, left) — NOT FPDF's (L, T, R).$config = new Config( pageSize: new PageSize(595.276, 841.890, 'A4'), margins: new Margin(45.354, 56.693, 45.354, 56.693), // top,right,bottom,left in points fontsDirectory: __DIR__ . '/fonts',);
$doc = Document::createStandalone($config);$doc->setTitle('Quarterly Report');$doc->setAuthor('Finance');$doc->addPage();
// SetFont + Cell, the FPDF way — but in points and with a real Unicode font.$doc->setFont('DejaVuSans', 'B', 18.0);$doc->setTextColor(30, 58, 138);$doc->cell(0, 24.0, 'Quarterly Report', false, true, Alignment::Left);
$doc->setFont('DejaVuSans', '', 11.0);$doc->setTextColor(0, 0, 0);$doc->multiCell(0, 16.0, "Body text wraps on real font metrics. Unicode is " . "native, so accented and non-Latin characters need no tFPDF variant — " . "register the family in the fonts directory and select it by name.");
// Equivalent of $pdf->Output('D', 'report.pdf'):$doc->output('report.pdf', OutputDestination::Download);邊界情況與陷阱
標題為「邊界情況與陷阱」的區段- 單位。 你從 FPDF 複製的每一個數值座標、寬度、高度與邊界預設都是公釐。在移植時,把它乘以
72 / 25.4轉成點一次。 把兩者混用會默默把一切的尺寸算錯。 Output()引數順序。 FPDF 是Output($dest, $name);NextPDF 是output($name, $dest)。目的地是OutputDestination列舉,而非一個字元。檔案 / 字串輸出請優先用save()/getPdfData()。SetMargins順序。 FPDF 是(left, top, right);NextPDF 的Margin值物件是(top, right, bottom, left)。重新排序,不要照抄。- 字型。 FPDF 的
AddFont()+.php度量檔沒有對等項。把 TrueType/OpenType 檔放進字型目錄,並用字族名稱呼叫setFont()。 核心 Base14 名稱(Helvetica、Times、Courier)不需檔案即可解析; 在 PDF/A 或 tagged PDF 之下,它們會被自動替換成一個可內嵌的字型。 GetStringWidth。 沒有公開的字串量測方法。如果你的 FPDF 程式碼量測字串以手動排列欄位,請把那個區塊改成multiCell()(依度量斷字)或固定寬度的cell()呼叫。
NextPDF 以單次串流通行(架構決策記錄 ADR-001)發射內容;
尖峰記憶體隨文件大小變動,而不是隨一棵保留的物件樹。
本指南範例的預算是 wall_ms: 2000, peak_mb: 128。對於長文件,請把內容驅動跨多個 addPage() 呼叫——就是一份 FPDF
報表已經在用的同一個迴圈形狀。
安全性說明
標題為「安全性說明」的區段- 中繼資料。
SetTitle()/SetAuthor()對映到寫入 ISO 32000-2 §14 資訊字典 / XMP 的有型別 setter。切勿在那裡存放祕密。 - 影像路徑。
image()會在讀取前拒絕 stream-wrapper schemes 與內嵌的 NUL 位元組。請傳入應用程式掌控的路徑。 - 沒有文件內的程式碼。 NextPDF 不執行任何文件內指令碼;FPDF 中沒有任何東西能改變這一點。
符合性
標題為「符合性」的區段| Statement | Spec | Clause |
|---|---|---|
| 頁面格式/方向對映到頁面邊界框。 | ISO 32000-2 | §7 |
| 字型寫成內嵌/子集字型程式。 | ISO 32000-2 | §9 |
| 標題 / 中繼資料落在資訊字典 / XMP 中。 | ISO 32000-2 | §14 |
| 線條、矩形與影像是內容串流繪製。 | ISO 32000-2 | §8 |
NextPDF 產生 ISO 32000-2 內容;它並未主張與 FPDF 視覺上完全一致。每當你更換渲染器時,請重新審查輸出。
商業情境
標題為「商業情境」的區段不適用。NextPDF core 涵蓋這裡描述的 FPDF 遷移路徑。
另請參閱
標題為「另請參閱」的區段遷移細節(R6 必備章節)
標題為「遷移細節(R6 必備章節)」的區段這份指南適合誰
標題為「這份指南適合誰」的區段在伺服器端、以 FPDF(或 tFPDF)做程序式 PDF 產生的團隊。如果你的程式碼是一連串由 SetXY 與 Ln 驅動的 AddPage / SetFont / Cell / MultiCell / Image /
Output 呼叫,那麼 動詞對映
就涵蓋你的整個介面。
範圍內:FPDF 繪圖動詞、游標模型、字型、色彩、線條與矩形、中繼資料,以及輸出。範圍外:FPDF 的 AddFont 度量檔工具,以及第三方 FPDF 指令碼擴充功能(條碼、旋轉、書籤)
——把那些對映到對應的 NextPDF 模組(Barcode、Transforms、
Navigation),本文不涵蓋。
相容性對映
標題為「相容性對映」的區段行為相容,並非可直接替換的 shim:core 不提供 FPDF 類別
shim。請改寫每一處呼叫點。這些動詞之所以對得這麼齊,是因為 NextPDF 的
cell/text API 共享 FPDF/TCPDF 血統,但單位模型、Output
引數順序,以及 Margin/列舉型別都不同——所以照抄是錯的,
翻譯才是對的。
單位與設定對映
標題為「單位與設定對映」的區段| FPDF construct | NextPDF | Notes |
|---|---|---|
$unit(預設 'mm') | (無對等項) | 以 PDF 點工作。在移植時用 pt = mm * 72 / 25.4 轉換尺寸一次。 |
$orientation('P'/'L') | addPage() 上的 Orientation 列舉,或對調 PageSize 寬/高 | 橫向 = 寬 > 高。 |
$size('A4'、[w,h]) | Config->pageSize(PageSize 值物件) | 具名格式變成明確的點尺寸;PageSize::A4()…A0() 與 Letter/Legal 工廠存在。 |
SetMargins($l, $t, $r) | Config->margins(Margin VO) | 建構式順序 (top, right, bottom, left)。 |
AddFont($family, $style, $file) | 字型目錄 + 以名稱 setFont() | 丟掉度量檔;把 TTF/OTF 放進 Config->fontsDirectory。 |
字型處理差異
標題為「字型處理差異」的區段- 單一字型目錄。 FPDF 逐字型的
AddFont註冊收斂為一個字型目錄加上以setFont()做字族比對。從Config->fontsDirectory(預設搜尋路徑)開始;當字型分布在不只一處時, 透過FontRegistry::addFontDirectory()或Document::addFontDirectory()註冊額外目錄。 - 永遠 Unicode。 沒有 Latin-1 預設,也沒有獨立的 tFPDF 建置;UTF-8 輸入是常態。
- 永遠子集化。 NextPDF 永遠對內嵌字型做子集化(ISO 32000-2 §9); FPDF 的字型內嵌選擇沒有對等項,也不需要。
- 重新建立字形基準。 字型比對與備援是引擎特定的;一個 FPDF 字型別名可能需要一個確切的字族名稱。替換差異是預期的,不是缺陷。
行為差異
標題為「行為差異」的區段- 單位轉換(mm → pt)— 最常見的移植錯誤;見上文。
Output引數順序互換,且目的地變成一個列舉。Margin/Alignment/Orientation是有型別的物件/列舉,而非字元或位置式的(l, t, r)三元組。- 沒有公開的
GetStringWidth— 透過multiCell()驅動斷字。 - 獨立的點陣化 — 密集內容上的斷行與分頁可能不同;請重新建立視覺差異的基準。
這些是有記錄的行為差異,不是任一引擎的缺陷。
不支援/沒有直接對等項
標題為「不支援/沒有直接對等項」的區段- FPDF
$unit選擇器 — 未建模(一律是點)。 AddFont()+.php/.z度量檔 — 由一個字型目錄取代。GetStringWidth()— 沒有公開的字串量測動詞。- FPDF 的
'I'/'D'/'F'/'S'目的地字元 — 由OutputDestination列舉 +save()/getPdfData()取代。
依賴這些的程式碼無法逐字「遷移」。請用上面的列重新表達它。
安全遷移順序
標題為「安全遷移順序」的區段- 把
nextpdf/core與 FPDF 並存安裝;暫時保留 FPDF。 - 選一份低風險的文件。透過 單位對映 轉換建構式,再用 動詞對映 移植每個動詞。把每一個 mm 座標轉成點。
- 把該文件的字型放進
Config->fontsDirectory,並以字族名稱選取它們;丟掉AddFont呼叫。 - 對同一份輸入產生兩份 PDF 並做視覺差異比對。差異 (字型替換、斷行)對獨立引擎而言是預期的——請以文件為單位接受它們。
- 把任何以
GetStringWidth為基礎的手動排版,換成multiCell()或固定寬度的cell()呼叫。 - 逐份文件重複,從最低風險開始;保留 FPDF 安裝直到最後一次切換。
- 最終切換之後,把 FPDF 從
composer.json移除。
測試遷移
標題為「測試遷移」的區段- 在你改動程式碼之前,先快照代表性文件的 FPDF 輸出 (golden 輸入;位元組會有所不同)。
- 對每一份遷移的文件,用你自己的檢查斷言驗收(視覺差異比對 + 文字擷取)。NextPDF 的 cell/font 行為由
examples/04-text-and-fonts.php加上核心tests/的 Font 與 text-output 套件實際驗證。遷移驗收因文件而異,並由你自行負責。 - 為每一份遷移的文件加上一個回歸測試。
佐證/可追溯性
標題為「佐證/可追溯性」的區段本頁每一項 NextPDF 行為陳述,都有儲存庫內的原始碼簽章、範例或架構決策記錄(ADR)支持,或對 PDF 格式特性而言,由 front-matter citations: 中的 ISO 32000-2 條款與
符合性 表佐證。FPDF 行為僅以
「獨立引擎 — 預期會有記錄在案的差異」來陳述;本頁不主張任何儲存庫內成品無法證明的對等性。
| NextPDF behavioral claim | In-repo evidence (path) |
|---|---|
AddPage 對映到 addPage(?PageSize, Orientation): static。 | src/Core/Concerns/HasPages.php(addPage())。 |
SetFont($family, $style, $size) 對映到 setFont(string, string, float): static;''/'B'/'I'/'BI'/'U' 樣式。 | src/Core/Concerns/HasTypography.php(setFont())。 |
Cell 對映到 cell($w, $h, $txt, $border, $newLine, $align, $fill): static。 | src/Core/Concerns/HasTextOutput.php(cell())。 |
MultiCell 對映到 multiCell($w, $h, $txt, $border, $align): static(依度量斷字)。 | src/Core/Concerns/HasTextOutput.php(multiCell()、wrapText())。 |
Write/Text/Ln 對映到 write()/text()/ln()。 | src/Core/Concerns/HasTextOutput.php(write()、text()、ln())。 |
SetXY/SetX/SetY/GetX/GetY 直接對映;SetMargins 接受一個 Margin VO。 | src/Core/Concerns/HasPages.php(setXY()、getX()、setMargins());src/ValueObjects/Margin.php((top, right, bottom, left))。 |
Image 對映到 image($file, ?$x, ?$y, ?$w, ?$h): static;拒絕 scheme/NUL 路徑。 | src/Core/Concerns/HasImages.php(image()、assertImageFilePath())。 |
Line/Rect/SetLineWidth/SetDrawColor/SetFillColor/SetTextColor 直接對映。 | src/Core/Concerns/HasDrawing.php(line()、rect()、setLineWidth());src/Core/Concerns/HasColors.php(setDrawColor()、setFillColor()、setTextColor())。 |
createStandalone() 的預設頁面是 A4 直向(595.276 × 841.890 pt)。 | src/Core/Document.php(createStandalone());src/ValueObjects/PageSize.php(A4())。 |
輸出目的地是 OutputDestination 列舉(Inline/Download/File/String);Output('S') → getPdfData(),Output('F', $p) → save($p)。 | src/Contracts/OutputDestination.php;src/Core/Concerns/HasOutput.php(output())。 |
SetTitle/SetAuthor/… 對映到有型別的中繼資料 setter;落在資訊字典 / XMP 中。 | src/Core/Concerns/HasMetadata.php(setTitle()、setAuthor());ISO 32000-2 §14(front-matter citations:)。 |
| 字型一律以子集程式的形式內嵌。 | src/Core/Concerns/HasTypography.php(buildFontData());ISO 32000-2 §9(front-matter citations:)。 |
| 內容以單次處理發射。 | docs/architecture/adr/ADR-001-stream-based-rendering-pipeline.md。 |
兩個套件都會保留安裝直到最終切換,所以逐一呼叫點的回滾,就是把該呼叫點還原回 FPDF 路徑。最終切換之後, 回滾就是從版本控制還原 FPDF 與先前的程式碼。不涉及任何資料遷移。
效能考量
標題為「效能考量」的區段見 效能。單次處理模型移除了任何保留緩衝區的成本。新增的逐文件成本是急切的字型解析(步驟 3), 可透過字型目錄快取。
常見陷阱
標題為「常見陷阱」的區段- 把公釐座標照抄成點,卻沒做
* 72 / 25.4轉換。 - 把
Output()留在 FPDF 的($dest, $name)順序,或傳入一個字元而非OutputDestination列舉。 - 把
SetMargins($l, $t, $r)直接照抄進Margin(它的順序是top, right, bottom, left)。 - 期望
AddFont度量檔能移植;改把 TTF/OTF 放進字型目錄。 - 去找一個
GetStringWidth對等項;改用multiCell()來斷字。 - 期望輸出 byte/pixel-identical(獨立引擎 — 本指南從不主張可直接替換或 100% 相容)。