圖片、表格與清單
光有文字很少能構成一份完整的文件。在本教學中,您會加入三種日常會用到的基本元素:一張圖片、一個表格,以及一個項目符號清單。您會撰寫兩段小型腳本,每一段都會產生一個您可以立即開啟的真實 PDF(可攜式文件格式,Portable Document Format)檔案。
您將建構的內容
標題為「您將建構的內容」的區段01-image.php— 一份單頁 PDF,內含一個標題與一張琥珀色方塊圖片,並放置在頁面上的精確位置。02-table-and-lists.php— 一份單頁 PDF,內含一個小型書籍表格,下方還有一個項目符號清單。
這兩段腳本都是完整的程式。請沿用
第一篇教學中的專案資料夾,並將每段腳本存放在 composer.json 旁邊。
步驟 1:在頁面上放一張圖片
標題為「步驟 1:在頁面上放一張圖片」的區段這段腳本自帶圖片。一張極小的 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>儲存格都需要結束標籤。 - 若是其他問題,請從疑難排解指南開始著手。
下一步
標題為「下一步」的區段您的頁面現在已經能夠承載圖片、表格與清單了。在 下一篇教學 中,您會讓一份文件超出單頁,並以頁首、頁尾與頁碼讓它保持整潔。若想更深入探討今天的主題, 在文件中嵌入圖片這篇食譜會涵蓋圖片格式與尺寸調整規則。