發票 PDF 範例¶
需求套件:nextpdf/core 難度:入門
完整程式碼¶
<?php
declare(strict_types=1);
use NextPDF\Core\Document;
use NextPDF\Core\Content\TextRenderer;
use NextPDF\Core\Graphics\DrawingEngine;
use NextPDF\Core\ValueObjects\PageSize;
use NextPDF\Core\ValueObjects\Margin;
use NextPDF\Core\ValueObjects\Position;
use NextPDF\Core\ValueObjects\Dimension;
use NextPDF\Core\ValueObjects\Color;
// ─── 文件初始化 ───────────────────────────────────────────────
$document = Document::createStandalone(
pageSize: PageSize::A4,
margin: Margin::symmetric(vertical: 20.0, horizontal: 25.0),
);
$page = $document->pages()->add();
$text = $document->text();
$drawing = $document->drawing();
// ─── 頁首:公司資訊 ──────────────────────────────────────────
// Logo(假設已準備好圖片)
$logo = $document->images()->embed('/assets/company-logo.png');
$drawing->image(image: $logo, x: 25.0, y: 20.0, width: 45.0);
// 公司名稱與聯絡資訊
$text->write(
text: 'NextPDF 科技有限公司',
position: Position::at(x: 80.0, y: 25.0),
fontSize: 14.0,
fontName: 'NotoSansCJKtc-Bold',
color: Color::fromHex('#1E3A8A'),
);
$text->write(
text: "台北市信義區信義路五段 7 號\nTel: (02) 1234-5678 | Email: billing@nextpdf.dev",
position: Position::at(x: 80.0, y: 33.0),
fontSize: 9.0,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#6B7280'),
lineHeight: 1.5,
);
// 分隔線
$drawing->line(
x1: 25.0, y1: 55.0,
x2: 185.0, y2: 55.0,
color: Color::fromHex('#E5E7EB'),
width: 0.5,
);
// ─── 發票標題與基本資訊 ──────────────────────────────────────
$text->write(
text: '發 票',
position: Position::at(x: 25.0, y: 65.0),
fontSize: 22.0,
fontName: 'NotoSansCJKtc-Bold',
color: Color::fromHex('#111827'),
);
// 發票號碼、日期(右側對齊)
$invoiceData = [
['label' => '發票號碼', 'value' => 'INV-2024-001'],
['label' => '開立日期', 'value' => '2024-03-15'],
['label' => '付款期限', 'value' => '2024-04-14'],
];
$y = 65.0;
foreach ($invoiceData as $row) {
$text->write(
text: $row['label'] . ':',
position: Position::at(x: 130.0, y: $y),
fontSize: 9.0,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#6B7280'),
);
$text->write(
text: $row['value'],
position: Position::at(x: 155.0, y: $y),
fontSize: 9.0,
fontName: 'NotoSansCJKtc-Bold',
color: Color::fromHex('#111827'),
);
$y += 8.0;
}
// ─── 買方資訊 ────────────────────────────────────────────────
$drawing->rectangle(
x: 25.0, y: 90.0, width: 75.0, height: 35.0,
fill: Color::fromHex('#F9FAFB'),
cornerRadius: 2.0,
);
$text->write(
text: '帳單收件人',
position: Position::at(x: 28.0, y: 93.0),
fontSize: 8.0,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#6B7280'),
);
$text->write(
text: "王小明\n台北市大安區復興南路一段 100 號\n(02) 9876-5432",
position: Position::at(x: 28.0, y: 100.0),
fontSize: 10.0,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#111827'),
lineHeight: 1.6,
);
// ─── 商品明細表格 ────────────────────────────────────────────
$tableTop = 140.0;
// 表格標頭背景
$drawing->rectangle(
x: 25.0, y: $tableTop, width: 160.0, height: 8.0,
fill: Color::fromHex('#1E3A8A'),
);
// 表格標頭文字
$headers = [
['text' => '品名', 'x' => 27.0],
['text' => '數量', 'x' => 115.0],
['text' => '單價', 'x' => 135.0],
['text' => '小計', 'x' => 160.0],
];
foreach ($headers as $header) {
$text->write(
text: $header['text'],
position: Position::at(x: $header['x'], y: $tableTop + 1.5),
fontSize: 9.0,
fontName: 'NotoSansCJKtc-Bold',
color: Color::fromHex('#FFFFFF'),
);
}
// 商品資料
$items = [
['name' => 'NextPDF Pro 年度授權', 'qty' => 1, 'price' => 9_900, 'total' => 9_900],
['name' => 'NextPDF Enterprise 月費', 'qty' => 3, 'price' => 4_500, 'total' => 13_500],
['name' => '技術支援服務(小時)', 'qty' => 5, 'price' => 2_000, 'total' => 10_000],
['name' => '字型授權包(CJK)', 'qty' => 1, 'price' => 3_000, 'total' => 3_000],
];
$rowY = $tableTop + 8.0;
foreach ($items as $i => $item) {
$bgColor = ($i % 2 === 0)
? Color::fromHex('#FFFFFF')
: Color::fromHex('#F9FAFB');
$drawing->rectangle(
x: 25.0, y: $rowY, width: 160.0, height: 9.0,
fill: $bgColor,
);
$text->write(
text: $item['name'],
position: Position::at(x: 27.0, y: $rowY + 2.0),
fontSize: 9.0,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#111827'),
);
$text->write(
text: (string) $item['qty'],
position: Position::at(x: 120.0, y: $rowY + 2.0),
fontSize: 9.0,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#374151'),
alignment: 'right',
maxWidth: 12.0,
);
$text->write(
text: 'NT$ ' . number_format($item['price']),
position: Position::at(x: 130.0, y: $rowY + 2.0),
fontSize: 9.0,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#374151'),
alignment: 'right',
maxWidth: 25.0,
);
$text->write(
text: 'NT$ ' . number_format($item['total']),
position: Position::at(x: 155.0, y: $rowY + 2.0),
fontSize: 9.0,
fontName: 'NotoSansCJKtc-Bold',
color: Color::fromHex('#111827'),
alignment: 'right',
maxWidth: 30.0,
);
$rowY += 9.0;
}
// ─── 合計欄 ──────────────────────────────────────────────────
$subtotal = 36_400;
$tax = (int) ($subtotal * 0.05);
$total = $subtotal + $tax;
$summaryY = $rowY + 5.0;
$summaryRows = [
['label' => '稅前合計', 'value' => 'NT$ ' . number_format($subtotal), 'bold' => false],
['label' => '營業稅(5%)', 'value' => 'NT$ ' . number_format($tax), 'bold' => false],
['label' => '應付總計', 'value' => 'NT$ ' . number_format($total), 'bold' => true],
];
foreach ($summaryRows as $row) {
if ($row['bold']) {
$drawing->line(
x1: 130.0, y1: $summaryY - 1.0,
x2: 185.0, y2: $summaryY - 1.0,
color: Color::fromHex('#1E3A8A'),
width: 0.5,
);
}
$text->write(
text: $row['label'],
position: Position::at(x: 130.0, y: $summaryY),
fontSize: $row['bold'] ? 10.0 : 9.0,
fontName: $row['bold'] ? 'NotoSansCJKtc-Bold' : 'NotoSansCJKtc',
color: Color::fromHex($row['bold'] ? '#1E3A8A' : '#6B7280'),
);
$text->write(
text: $row['value'],
position: Position::at(x: 155.0, y: $summaryY),
fontSize: $row['bold'] ? 11.0 : 9.0,
fontName: $row['bold'] ? 'NotoSansCJKtc-Bold' : 'NotoSansCJKtc',
color: Color::fromHex($row['bold'] ? '#1E3A8A' : '#374151'),
alignment: 'right',
maxWidth: 30.0,
);
$summaryY += $row['bold'] ? 9.0 : 7.0;
}
// ─── 備注與付款資訊 ──────────────────────────────────────────
$text->write(
text: '付款說明',
position: Position::at(x: 25.0, y: $summaryY + 5.0),
fontSize: 9.0,
fontName: 'NotoSansCJKtc-Bold',
color: Color::fromHex('#374151'),
);
$text->write(
text: "銀行:台灣銀行 帳號:012-3456789-01\n戶名:NextPDF 科技有限公司\n請於付款期限前完成匯款,並來信告知。",
position: Position::at(x: 25.0, y: $summaryY + 13.0),
fontSize: 8.5,
fontName: 'NotoSansCJKtc',
color: Color::fromHex('#6B7280'),
lineHeight: 1.6,
);
// ─── 輸出 ────────────────────────────────────────────────────
$document->save('/output/invoice-INV-2024-001.pdf');