Встраивание изображений в документ
Разместите растровое изображение в абсолютной позиции и явно задайте ширину. Не указывайте высоту, и NextPDF вычислит её по соотношению сторон исходного изображения. Этот рецепт основан на examples/07-images.php. Можно использовать файлы JPEG, PNG, GIF, BMP, WebP и AVIF.
NextPDF встраивает изображение как объект XObject изображения по стандарту ISO 32000-2. Словарь изображения явно задаёт ширину, высоту и число бит на компонент.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3image() входит в API Core. Для встраивания существующего файла больше ничего не требуется. Пример, включённый в рецепт, формирует тестовое изображение с помощью GD, поэтому ему требуется ext-gd. Этот API стабилен с 1.0.0 и поддерживается в матрице бэкпортов 8.1–8.4.
Концептуальный обзор
Заголовок раздела «Концептуальный обзор»image($file, x, y, width, height) загружает файл через реестр изображений, декодирует его и размещает. Перед декодированием реестр проверяет путь. Он отклоняет любой путь, который содержит байт NUL или имеет вид схемы URL (Uniform Resource Locator) (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, пути с байтом 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 МБ: этого достаточно для фотографии умеренного размера. Повторное размещение того же пути обходится дёшево: один дополнительный Do плюс cm, а не повторное декодирование. Уменьшение масштаба по ширине не сокращает число хранимых пикселей. Если важен размер документа, заранее уменьшайте размер крупных исходных изображений.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Отклонение схемы URL и байта NUL защищает от SSRF и внедрения в путь. Нельзя обманом заставить image() выполнить выборку http://… или принять путь с байтом NUL. Тем не менее относитесь к именам файлов, предоставленным пользователем, как к недоверенным. Разрешайте их относительно допустимого базового каталога, прежде чем вызывать image(). Когда файл загружен пользователем, декодирование изображения выполняется над байтами, на которые может влиять злоумышленник. Ограничивайте размер входных данных и рассмотрите декодирование в изолированном рабочем процессе.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Спецификация | Пункт | reference_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 |
Профиль воспроизводимости — структурный. При фиксированном источнике байты изображения детерминированы. Каждый сохранённый документ по-прежнему содержит /ID в трейлере и атомы дат, поэтому тестовый стенд удаляет их и сравнивает структуру после нормализации qpdf. Этот рецепт описывает, как NextPDF формирует структуру. Он не делает общего заявления о соответствии ISO 32000-2.
Коммерческий контекст
Заголовок раздела «Коммерческий контекст»Неприменимо. Встраивание растровых изображений — функция Core, не ограниченная Premium.