跳轉到

串流排版引擎

NextPDF Core 提供固定座標排版——開發者需手動指定每個元素的確切位置。串流排版引擎(StreamingLayoutEngine)引入了流式排版模型:內容自動向下流動,頁面空間耗盡時自動插入分頁,並應用高品質的排版規則。

這是生成長篇報告、法律文件、技術手冊等可變長度文件的正確選擇。


核心概念

graph TD
    Content["內容串流\n(文字/圖片/表格)"] --> Engine["StreamingLayoutEngine"]
    Engine --> PageBreaker["SmartPageBreaker\n智慧分頁決策"]
    PageBreaker --> OrphanWidow["OrphanWidowController\n孤行/寡行控制"]
    OrphanWidow --> ColumnLayout["ColumnLayoutManager\n多欄排版"]
    ColumnLayout --> Pages["PDF 頁面\n(自動生成)"]
    Engine --> FloatManager["FloatManager\n圖片浮動"]
    FloatManager --> Pages

快速開始

use NextPDF\Pro\FlowLayout\StreamingLayoutEngine;
use NextPDF\Pro\FlowLayout\LayoutOptions;
use NextPDF\Pro\FlowLayout\Content\Paragraph;
use NextPDF\Pro\FlowLayout\Content\Heading;
use NextPDF\Pro\FlowLayout\Content\FlowTable;
use NextPDF\Pro\FlowLayout\Content\PageBreak;

$engine = new StreamingLayoutEngine(
    LayoutOptions::create(
        pageWidth: 595.28,    // A4 寬度(pt)
        pageHeight: 841.89,   // A4 高度(pt)
        marginTop: 72.0,      // 25.4mm
        marginBottom: 72.0,
        marginLeft: 72.0,
        marginRight: 72.0,
    )
);

// 加入標題
$engine->add(Heading::create('年度財務報告', level: 1));
$engine->add(Heading::create('摘要', level: 2));

// 加入段落(自動換行與分頁)
$engine->add(Paragraph::create(
    '本報告涵蓋 2025 年度全年財務數據,包括收入、支出、利潤與現金流量分析。'
    . '所有數據均依據國際財務報告準則(IFRS)編製,並經由獨立會計師事務所審計確認。'
));

// 顯式分頁
$engine->add(PageBreak::create());

// 加入大型表格(自動跨頁,含標題列重複)
$engine->add(
    FlowTable::create(headers: ['季度', '收入', '支出', '淨利', '毛利率'])
        ->addRow(['Q1 2025', 'NT$12,500,000', 'NT$8,200,000', 'NT$4,300,000', '34.4%'])
        ->addRow(['Q2 2025', 'NT$14,100,000', 'NT$9,100,000', 'NT$5,000,000', '35.5%'])
        ->addRow(['Q3 2025', 'NT$13,800,000', 'NT$8,800,000', 'NT$5,000,000', '36.2%'])
        ->addRow(['Q4 2025', 'NT$16,200,000', 'NT$10,100,000', 'NT$6,100,000', '37.7%'])
        ->withRepeatHeaderOnNewPage(true)
        ->withAlternatingRowColor('#F8FAFC', '#FFFFFF')
);

// 生成 PDF
$pdf = $engine->render();
file_put_contents('/output/annual-report.pdf', $pdf);

SmartPageBreaker — 智慧分頁

SmartPageBreaker 在插入分頁前評估多個排版品質指標,避免產生視覺上不佳的分頁點:

use NextPDF\Pro\FlowLayout\PageBreak\SmartPageBreaker;
use NextPDF\Pro\FlowLayout\PageBreak\PageBreakOptions;

$pageBreaker = new SmartPageBreaker(
    PageBreakOptions::create()
        ->avoidBreakingAfterHeading(true)     // 標題後不分頁(至少跟隨一行)
        ->avoidBreakingInsideTable(false)     // 允許表格內分頁(長表格必要)
        ->avoidBreakingInsideList(true)       // 清單項目不拆分
        ->preferBreakBeforeHeading(true)      // 傾向在標題前分頁
        ->minimumLinesBeforeBreak(3)          // 分頁前至少保留 3 行
        ->minimumLinesAfterBreak(3)           // 分頁後至少保留 3 行
);

$engine = new StreamingLayoutEngine(
    options: LayoutOptions::create(/* ... */),
    pageBreaker: $pageBreaker,
);

強制與禁止分頁

use NextPDF\Pro\FlowLayout\Content\Paragraph;
use NextPDF\Pro\FlowLayout\Content\KeepTogether;

// 強制在此前分頁
$engine->add(Paragraph::create('新章節開始', breakBefore: true));

// 強制在此後分頁
$engine->add(Paragraph::create('章節結束', breakAfter: true));

// 將多個元素保持在同一頁(若空間不足則整體移至下頁)
$engine->add(
    KeepTogether::create([
        Heading::create('重要圖表', level: 3),
        Image::create('/charts/q4-revenue.png', width: 400),
        Caption::create('圖 3.1:Q4 2025 收入分布'),
    ])
);

OrphanWidowController — 孤行/寡行控制

排版學中,孤行(orphan)是段落第一行遺留在上一頁底部,寡行(widow)是段落最後一行落在下一頁頂部。兩者都是需要避免的排版瑕疵:

use NextPDF\Pro\FlowLayout\Typography\OrphanWidowController;
use NextPDF\Pro\FlowLayout\Typography\OrphanWidowOptions;

$owController = new OrphanWidowController(
    OrphanWidowOptions::create(
        minimumOrphanLines: 2,   // 段落第一行後至少保留 2 行在同頁
        minimumWidowLines: 2,    // 段落最後 2 行必須在同頁
        strategy: 'push-forward', // 'push-forward'(整段移至下頁)| 'pull-back'(從下頁拉回行)
    )
);

$engine = new StreamingLayoutEngine(
    options: $layoutOptions,
    orphanWidowController: $owController,
);

行間距與段落間距

use NextPDF\Pro\FlowLayout\Content\Paragraph;
use NextPDF\Pro\FlowLayout\Style\ParagraphStyle;

$style = ParagraphStyle::create(
    fontSize: 10.5,
    lineHeight: 1.6,         // 行高倍數
    spaceBefore: 6.0,        // 段落前間距(pt)
    spaceAfter: 6.0,         // 段落後間距(pt)
    firstLineIndent: 14.0,   // 首行縮排
    alignment: 'justify',    // 'left' | 'right' | 'center' | 'justify'
    hyphenation: true,       // 啟用斷字(需設定語言)
    language: 'zh-Hant',
);

$engine->add(Paragraph::create('段落文字...', style: $style));

多欄版面

use NextPDF\Pro\FlowLayout\ColumnLayout\ColumnDefinition;

$engine->setColumnLayout(
    columns: 2,
    gutter: 18.0,         // 欄間距(pt)
    columnRule: true,     // 是否顯示欄線
    balanceLastPage: true // 最後一頁是否平衡兩欄
);

// 跨欄元素(如大型圖片或標題)
$engine->add(
    Heading::create('全版標題', level: 1)
        ->spanAllColumns(true)
);

$engine->add(Paragraph::create('第一欄文字...'));
$engine->add(Paragraph::create('繼續流入第一欄...'));

// 強制跳至下一欄
$engine->add(ColumnBreak::create());

$engine->add(Paragraph::create('第二欄文字...'));

圖片浮動

use NextPDF\Pro\FlowLayout\Content\FloatImage;
use NextPDF\Pro\FlowLayout\Float\FloatSide;

$engine->add(
    FloatImage::create(
        path: '/images/company-logo.png',
        width: 150.0,
        side: FloatSide::Right,
        margin: 12.0,          // 圖文間距
        captionText: '圖 1.1:公司 Logo',
    )
);

// 圖片右浮動,後續段落自動環繞
$engine->add(Paragraph::create('這段文字會自動環繞右側的圖片排版...'));

頁眉頁尾範本

use NextPDF\Pro\FlowLayout\Template\HeaderTemplate;
use NextPDF\Pro\FlowLayout\Template\FooterTemplate;

$engine->setHeader(
    HeaderTemplate::create()
        ->leftText('機密文件')
        ->centerText('年度財務報告 2025')
        ->rightImage('/assets/logo.png', height: 20.0)
        ->borderBottom(0.5, '#D97706')
        ->firstPageDifferent(true)   // 封面頁不顯示頁眉
);

$engine->setFooter(
    FooterTemplate::create()
        ->leftText('NextPDF Pro 生成')
        ->centerText('頁次:{page} / {total}')  // 自動總頁數
        ->rightText(date('Y-m-d'))
        ->borderTop(0.5, '#E5E7EB')
);

自動目錄(TOC)

use NextPDF\Pro\FlowLayout\Toc\TableOfContents;
use NextPDF\Pro\FlowLayout\Toc\TocOptions;

$toc = new TableOfContents(
    TocOptions::create(
        title: '目錄',
        maxLevel: 3,                    // 包含至 H3
        dotLeader: true,                // .......... 點線
        pageNumberAlignment: 'right',
        indentPerLevel: 15.0,
    )
);

// 在文件開頭插入 TOC 佔位符
$engine->add($toc->placeholder());

// 加入正文內容(標題會自動注冊至 TOC)
$engine->add(Heading::create('第一章:執行摘要', level: 1));
// ...

// render() 後 TOC 自動填入正確頁碼
$pdf = $engine->render();

效能與大型文件

文件規模 記憶體使用 渲染時間
50 頁(1 萬字) ~32 MB < 1 秒
200 頁(5 萬字) ~85 MB 2–4 秒
1,000 頁(25 萬字) ~320 MB 15–30 秒
5,000 頁以上 建議串流模式 依章節分批
// 超大型文件:使用串流章節模式,控制記憶體峰值
$engine = StreamingLayoutEngine::createChunked(
    options: $layoutOptions,
    chunkSize: 100,          // 每 100 頁輸出一次,釋放記憶體
    outputPath: '/tmp/report-chunks/',
);

// 最後合併所有章節 PDF
$merger = new PdfMerger();
$finalPdf = $merger->mergeDirectory('/tmp/report-chunks/');

相關資源