跳到內容
getnextpdf.com

圖片、表格與清單

光有文字很少能構成一份完整的文件。在本教學中,您會加入三種日常會用到的基本元素:一張圖片、一個表格,以及一個項目符號清單。您會撰寫兩段小型腳本,每一段都會產生一個您可以立即開啟的真實 PDF(可攜式文件格式,Portable Document Format)檔案。

  • 01-image.php — 一份單頁 PDF,內含一個標題與一張琥珀色方塊圖片,並放置在頁面上的精確位置。
  • 02-table-and-lists.php — 一份單頁 PDF,內含一個小型書籍表格,下方還有一個項目符號清單。

這兩段腳本都是完整的程式。請沿用 第一篇教學中的專案資料夾,並將每段腳本存放在 composer.json 旁邊。

這段腳本自帶圖片。一張極小的 8 x 8 像素 PNG(可攜式網路圖形,Portable Network Graphics)圖片以 Base64 字串的形式內嵌在腳本中。Base64 是二進位資料的純文字寫法,因此可以放進原始碼中。在實際專案裡,您會略過這個部分, 因為您的圖片檔案已經存在於磁碟上。

請將以下內容存為 01-image.php,並以 php 01-image.php 執行:

<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// A tiny 8 x 8 pixel amber PNG, stored as text inside this script.
// In a real project the image file already exists on disk, so you
// would skip this block and point image() at your own file.
$pngBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAEUlEQVR42mP4Oo8bK2IYWhIAq6BngWh/dt4AAAAASUVORK5CYII=';
@mkdir(__DIR__ . '/out');
$pngPath = __DIR__ . '/out/amber-square.png';
$pngBytes = base64_decode($pngBase64, true);
if ($pngBytes === false) {
fwrite(STDERR, "The embedded image data is damaged.\n");
exit(1);
}
file_put_contents($pngPath, $pngBytes);
$document = Document::createStandalone();
$document->setTitle('Tutorial: images');
$document->addPage();
$document->setFont('helvetica', 'B', 20);
$document->cell(0, 26, 'A picture inside a PDF', newLine: true);
$document->setFont('helvetica', '', 12);
$document->cell(0, 18, 'The amber square below comes from a tiny PNG file.', newLine: true);
// Place the image 72 points (one inch) from the left edge and
// 160 points down from the top, printed as a 96 x 96 point square.
$document->image($pngPath, x: 72, y: 160, width: 96, height: 96);
$document->save(__DIR__ . '/out/image.pdf');
echo "Wrote out/image.pdf\n";

您應該會在畫面上看到 Wrote out/image.pdf。開啟 out/image.pdf,您會看到標題、一行文字,以及一個琥珀色方塊。

  • 腳本會先將 Base64 字串解碼還原成圖片位元組,並寫入 out/amber-square.png。這只是一個讓教學能自成一體的小技巧。真正的重點從 image() 呼叫開始,它會以相同的方式讀取任何既有的 PNG 或 JPEG(聯合圖像專家群組,Joint Photographic Experts Group)檔案。
  • @mkdir(__DIR__ . '/out') 會建立輸出資料夾。@ 符號會隱藏資料夾已存在時所產生的無害警告,讓腳本可以連續執行兩次。
  • image() 接收一個檔案路徑,加上一個位置與一個列印尺寸。位置與尺寸都以點(point)為單位,而 72 點等於一英吋。頁面原點位於左上角,因此 y: 160 代表從頂端往下 160 點。
  • 像素與點是不同的東西。這張圖片只有 8 x 8 像素,但 width: 96, height: 96 會把它列印成一個寬約一又三分之一英吋的方塊。 列印尺寸由您決定,而非由像素數量決定。
  • image() 會把圖片放在您指定的精確位置。它不會移動 cell() 所使用的書寫位置。先寫文字、再放圖片,可以避免兩者互相碰撞。
  • NextPDF 只會從本機檔案讀取圖片,絕不會從網址讀取。它會在嵌入圖片前, 先檢查該檔案是否為真正且受支援的圖片。當檔名來自使用者時,這道檢查能保護您。

步驟 2:加入一個表格與一個項目符號清單

標題為「步驟 2:加入一個表格與一個項目符號清單」的區段

表格與清單屬於結構化內容。描述結構最快的方式是 HTML(超文字標記語言, Hypertext Markup Language),也就是網頁所使用的同一套標記。NextPDF 會將一組受支援的 HTML 直接繪製到 PDF 頁面上。過程中不涉及任何瀏覽器。

請將以下內容存為 02-table-and-lists.php,並以 php 02-table-and-lists.php 執行:

<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
@mkdir(__DIR__ . '/out');
$document = Document::createStandalone();
$document->setTitle('Tutorial: tables and lists');
$document->addPage();
$document->setFont('helvetica', 'B', 20);
$document->cell(0, 26, 'A reading list, two ways', newLine: true);
$document->ln(8);
$html = <<<'HTML'
<h2>The books as a table</h2>
<table border="1" cellpadding="6" style="width: 100%;">
<thead>
<tr style="background-color: #1E3A8A; color: #FFFFFF;">
<th style="width: 50%;">Title</th>
<th style="width: 20%; text-align: center;">Year</th>
<th style="width: 30%; text-align: right;">Pages</th>
</tr>
</thead>
<tbody>
<tr>
<td>The Paper Office</td>
<td style="text-align: center;">2019</td>
<td style="text-align: right;">312</td>
</tr>
<tr style="background-color: #F8FAFC;">
<td>Ink and Pixels</td>
<td style="text-align: center;">2023</td>
<td style="text-align: right;">208</td>
</tr>
</tbody>
</table>
<h2>Why these two books</h2>
<ul>
<li>Short chapters that fit into a lunch break</li>
<li>Worked examples on every page</li>
<li>No jargon without an explanation</li>
</ul>
HTML;
$document->writeHtml($html);
$document->save(__DIR__ . '/out/table-and-lists.pdf');
echo "Wrote out/table-and-lists.pdf\n";

您應該會看到 Wrote out/table-and-lists.pdf。這份 PDF 內含一個標題、 一個帶有深色標題列的三欄表格,以及一個項目符號清單。

  • 這段腳本在同一頁上混用了兩種書寫方式。cell() 會在目前的書寫位置印出大標題。接著 writeHtml() 會把表格與清單接在標題下方,沿著頁面往下排版。
  • ln(8) 會在標題與 HTML 內容之間加入一段高 8 點的小垂直間距。少了它,兩者就會緊貼在一起。
  • 這個表格使用一般的表格標記:<thead> 用於標題列、<tbody> 用於資料列、<th> 用於標題儲存格,<td> 用於資料儲存格。border="1" 會畫出格線,而 cellpadding="6" 則會在每個儲存格內加入喘息空間。
  • 欄寬以百分比表示,例如 width: 50%。它們會依比例分配表格的完整寬度,因此即使頁面尺寸改變,版面配置仍能維持。 排版 HTML 表格這篇食譜會深入說明標題列、頁尾列與欄寬設定。
  • style 屬性使用 CSS(階層式樣式表,Cascading Style Sheets)宣告,也就是網頁的樣式語言。顏色、對齊與寬度的運作方式就如這裡所示。在您依賴其他屬性之前,請先查閱 CSS 支援對照表
  • 項目符號清單就只是一個 <ul>,每個項目對應一個 <li>。NextPDF 會替您畫出項目符號與縮排。
  • 若錯誤訊息指出 ImageProcessingException,代表圖片檔案無法讀取或解碼。請檢查路徑,並確認該檔案是 PNG 或 JPEG 等受支援的格式。
  • 若錯誤訊息指出 PageLayoutException,代表某個位置或尺寸遭到拒絕。 寬度與高度必須大於零,而路徑必須指向本機檔案,而非網址。
  • 這兩種錯誤都記載於 引擎錯誤參考中。
  • 如果表格繪製結果看起來怪怪的,請先檢查標記。每一個 <tr> 列與 <td> 儲存格都需要結束標籤。
  • 若是其他問題,請從疑難排解指南開始著手。

您的頁面現在已經能夠承載圖片、表格與清單了。在 下一篇教學 中,您會讓一份文件超出單頁,並以頁首、頁尾與頁碼讓它保持整潔。若想更深入探討今天的主題, 在文件中嵌入圖片這篇食譜會涵蓋圖片格式與尺寸調整規則。