在文档中嵌入图像
重点摘要
标题为“重点摘要”的章节以指定宽度将位图图像放置在绝对位置。省略高度时,NextPDF 会根据源图像的宽高比推导高度。本示例对应 examples/07-images.php。NextPDF 支持 JPEG、PNG、GIF、BMP、WebP 与 AVIF。
嵌入的图像会成为 ISO 32000-2 图像 XObject。其字典会明确标示宽度、高度与每个分量的位数。
composer require nextpdf/core:^3image() API 属于 Core。嵌入已有文件不需要任何额外组件。若要像本示例一样使用 GD 生成测试图像,则需要 ext-gd。该 API 自 1.0.0 起稳定,并适用于 8.1–8.4 的 backport 兼容矩阵。
概念总览
标题为“概念总览”的章节image($file, x, y, width, height) 会通过图像注册表加载文件、解码并放置图像。注册表会在解码前先验证路径。它会拒绝包含 NUL 字节的路径,以及看起来像 URL scheme(scheme://…)的路径,因为 image() 只读取本地文件,绝不读取远程 URL。注册表也会拒绝非正值的 width 或 height。
放置时,当前变换矩阵会把图像的单位正方形映射到目标矩形。ISO 32000-2 §8.8 为此指定了 cm 运算符,并将其置于 q/Q 配对内,因此该变换会保持隔离。解码后的位图会成为图像 XObject。它的 BitsPerComponent 为必填,且必须是 1、2、4、8 或 16 之一(§8.9.5)。
API 接口
标题为“API 接口”的章节API 接口由 PHPDoc 自动生成。本示例只依赖一个方法:
image(string $file, ?float $x = null, ?float $y = null, ?float $width = null, ?float $height = null): static— 嵌入并放置一个本地位图图像。省略height即可保留源图像的宽高比。以 URL scheme 开头的路径、含 NUL 字节的路径,以及非正值的尺寸,都会被拒绝并抛出PageLayoutException。
代码示例 — 快速上手
标题为“代码示例 — 快速上手”的章节<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->addPage();
// Absolute position; height inferred from the source aspect ratio.$doc->image(__DIR__ . '/logo.png', x: 15, y: 30, width: 80);
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/images.pdf');代码示例 — 生产环境
标题为“代码示例 — 生产环境”的章节这是一个完整示例,可直接在测试载具上运行。它会用 GD 生成一张确定性的测试图像,使本示例保持自包含。它会遵循 NEXTPDF_COOKBOOK_OUTPUT,且不会自行固定任何随机种子。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
if (!\extension_loaded('gd')) { fwrite(STDERR, "ext-gd required for the self-contained test image\n"); exit(1);}
// Build a deterministic test image (fixed pixels — no entropy).$imgPath = \tempnam(\sys_get_temp_dir(), 'npf') . '.png';$img = \imagecreatetruecolor(200, 100);if ($img === false) { fwrite(STDERR, "GD imagecreatetruecolor failed\n"); exit(1);}$bg = (int) \imagecolorallocate($img, 30, 58, 138);$fg = (int) \imagecolorallocate($img, 255, 255, 255);\imagefilledrectangle($img, 0, 0, 199, 99, $bg);\imagestring($img, 5, 40, 40, 'NextPDF Image', $fg);\imagepng($img, $imgPath);\imagedestroy($img);
try { $doc = Document::createStandalone(); $doc->setTitle('Image Embedding'); $doc->addPage();
$doc->setFont('helvetica', 'B', 18); $doc->cell(0, 12, 'Image Embedding', newLine: true); $doc->ln(5);
// Absolute placement; width fixed, height from aspect ratio. $doc->image($imgPath, x: 15, y: 50, width: 80); // Same image, narrower — scaled down by the CTM, not re-decoded. $doc->image($imgPath, x: 15, y: 105, width: 40);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/images.pdf'; $doc->save($out); echo "Created images.pdf\n";} finally { @\unlink($imgPath);}边界情况与陷阱
标题为“边界情况与陷阱”的章节- 不支持远程 URL。 匹配
scheme://…的路径会被拒绝,并抛出PageLayoutException。请先把素材下载到本地文件,再传入该路径。加载器不会替你通过网络抓取文件。这是刻意设计的 SSRF 防护。 - 非正值的尺寸会抛出异常。
width <= 0或height <= 0会引发PageLayoutException。若要使用原始尺寸,请省略相应参数,而不是传入0。 - 含 NUL 字节的路径会被拒绝。 包含
\0的路径会被拒绝。这是针对毒空字节(poison null byte)的防护。请验证用户提供的文件名。 - 宽高比。 只传入
width或只传入height,即可等比例缩放。两者都传入则可能使图像变形。 - 同一个文件嵌入两次。 重复使用同一个路径时,缩放会通过变换矩阵完成。引擎不会重新解码相同的字节。请优先重复使用路径,而不是复制文件。
解码成本与源图像的像素数成正比,因此预算为 96 MB,可容纳一张中等大小的照片。重新放置同一个路径的成本很低:只会多一个 Do 加一个 cm,而不是再次解码。按宽度缩小并不会减少已存储的像素。若在意文档大小,请先重新调整大型源图像的尺寸。
安全须知
标题为“安全须知”的章节拒绝 URL scheme 与 NUL 字节,是针对 SSRF 和路径注入的防护。攻击者无法诱使 image() 抓取 http://…,也无法让它越过空字节读取。即便如此,仍请将用户提供的文件名视为不可信。在你调用 image() 之前,请先把它们 resolve(解析)到允许的基目录之内。当文件来自用户上传时,图像解码会在攻击者可影响的字节上运行。请限制输入大小,并考虑在隔离的 worker 中进行解码。
符合性
标题为“符合性”的章节| 陈述 | 规格 | 条款 | 参考 ID |
|---|---|---|---|
| 图像字典会明确标示宽度、高度与每个分量的位数。 | ISO 32000-2 | §8.9.5 | |
BitsPerComponent 为必填,且必须为 1、2、4、8 或 16。 | ISO 32000-2 | §8.9.5 | |
图像由 cm 运算符放置,该运算符位于 q/Q 内。 | ISO 32000-2 | §8.8 |
重现性配置文件 — 结构层级。 对于固定来源,图像字节具有确定性。每份保存的文档仍会带有 trailer 的 /ID 与日期原子,因此测试载具会剥离这些内容,再比对经 qpdf 规范化后的结构。本示例说明 NextPDF 如何生成这套结构。它并未笼统声称完全符合 ISO 32000-2。
商业情境
标题为“商业情境”的章节不适用。位图图像嵌入是 Core 能力,不受 Premium 限制。