Embed images in a document
At a glance
Section titled “At a glance”Place a raster image at an absolute position with an explicit width. Omit the height, and NextPDF derives it from the source aspect ratio. This recipe follows examples/07-images.php. You can use JPEG, PNG, GIF, BMP, WebP, and AVIF files.
NextPDF embeds the image as an ISO 32000-2 image XObject. The image dictionary states the width, height, and bits per component explicitly.
Install
Section titled “Install”composer require nextpdf/core:^3The image() API is part of Core. You need nothing else to embed an existing file. The backing example generates a test image with GD, so it needs ext-gd. The API has been stable since 1.0.0 and runs on the 8.1–8.4 backport matrix.
Conceptual overview
Section titled “Conceptual overview”image($file, x, y, width, height) loads the file through the image registry, decodes it, and places it. The registry validates the path before decoding. It rejects any path that contains a NUL byte or looks like a Uniform Resource Locator (URL) scheme (scheme://…). image() reads local files only, never a remote URL. The registry also rejects a non-positive width or height.
Placement uses the current transformation matrix to map the image’s unit square into the target rectangle. ISO 32000-2 §8.8 specifies the cm operator inside a q/Q pair for this placement, so the transform stays isolated. The decoded raster becomes an image XObject. Its BitsPerComponent is required and must be one of 1, 2, 4, 8, or 16 (§8.9.5).
API surface
Section titled “API surface”The API surface is generated from PHPDoc. This recipe uses one method:
image(string $file, ?float $x = null, ?float $y = null, ?float $width = null, ?float $height = null): static— embeds and places a local raster image. Omitheightto preserve the source aspect ratio. It rejects URL-scheme paths, NUL-byte paths, and non-positive dimensions with aPageLayoutException.
Code sample — Quick start
Section titled “Code sample — Quick start”<?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');Code sample — Production
Section titled “Code sample — Production”This complete, harness-ready example generates a deterministic test image with GD, so the recipe stays self-contained. It honours NEXTPDF_COOKBOOK_OUTPUT and pins no entropy of its own.
<?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);}Edge cases & gotchas
Section titled “Edge cases & gotchas”- No remote URLs. A path matching
scheme://…is rejected with aPageLayoutException. Download the asset to a local file first, then pass that path. The loader does not fetch over the network for you. This is a deliberate Server-Side Request Forgery (SSRF) guard. - Non-positive dimensions throw. A
width <= 0orheight <= 0raises aPageLayoutException. To use the natural size, omit the argument instead of passing0. - NUL-byte path rejected. A path that contains
\0is rejected. This guards against poison-null-byte paths. Validate user-supplied filenames. - Aspect ratio. Pass only
width, or onlyheight, to scale proportionally. Passing both values can distort the image. - The same file embedded twice. Reuse one path to scale through the transformation matrix. The engine does not re-decode identical bytes. Favour reusing the path over duplicating files.
Performance
Section titled “Performance”Decode cost is proportional to the source pixel count, so the budget is 96 MB to allow a moderate photo. Placing the same path again costs little: one extra Do plus a cm, not a second decode. Scaling down by width does not reduce the stored pixels. Pre-resize large source images if document size matters.
Security notes
Section titled “Security notes”The URL-scheme and NUL-byte rejections guard against SSRF and path injection. image() cannot be tricked into fetching http://… or traversing past a null byte. Even so, treat user-supplied filenames as untrusted. Resolve them against an allowed base directory before you call image(). When the file is user-uploaded, image decoding runs on attacker-influenced bytes. Cap the input size and consider decoding in an isolated worker.
Conformance
Section titled “Conformance”| Statement | Spec | Clause | reference_id |
|---|---|---|---|
| An image dictionary specifies width, height, and bits per component explicitly. | ISO 32000-2 | §8.9.5 | |
BitsPerComponent is required and is 1, 2, 4, 8, or 16. | ISO 32000-2 | §8.9.5 | |
An image is placed by the cm operator inside q/Q. | ISO 32000-2 | §8.8 |
Reproducibility profile — structural. Image bytes are deterministic for a fixed source. Every saved document still carries a trailer /ID and date atoms, so the harness strips those and compares the qpdf-normalised structure. This recipe describes how NextPDF produces the structure. It does not make a blanket ISO 32000-2 conformance claim.
Commercial context
Section titled “Commercial context”Not applicable. Raster image embedding is a Core capability, with no Premium gate.