图像、表格与列表
只有文本很难构成一份完整的文档。在本教程里,你会加入三个日常常用的组成部分:一张图片、一个表格和一个项目符号列表。你会写两段简短的脚本, 每一段都会生成一个可以立即打开的真实 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 点等于 1 英寸。页面原点是左上角,所以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 内容之间加入一个八点高的小竖直间隙。没有它, 两者就会紧贴在一起。- 这个表格使用普通的表格标记:
<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>单元格都需要各自的闭合标签。 - 遇到其他任何问题,请从 疑难解答指南开始。
下一步
标题为“下一步”的章节现在你的页面已经可以承载图片、表格和列表了。在 下一个教程里, 你会让文档从单页扩展到多页,并用页眉、页脚和页码把它整理得井井有条。 想更深入了解今天的主题,可以看 在文档中嵌入图片一文,它介绍了图片格式和尺寸设置规则。