Перейти к содержимому

Отрисовка HTML на странице PDF

Используйте writeHtml(), чтобы отрисовать фрагмент HTML и CSS как содержимое страницы PDF. Передайте разметку, и NextPDF отрисует отформатированную страницу. Полная, готовая к запуску версия этого кода находится в examples/08-html-basic.php. Выполните шаги ниже или скопируйте пример напрямую.

NextPDF считывает ваш HTML один раз и потоково передаёт результат прямо на страницу. Это однопроходный потоковый конвейер. Чтобы воспользоваться этим рецептом, понимать эту модель не требуется. Но стоит держать её в уме: она объясняет несколько правил далее на этой странице.

Окно терминала
composer require nextpdf/core:^3

Эта команда устанавливает пакет nextpdf/core. Примеры на этой странице работают на PHP 8.4; поддерживаемая среда выполнения — >=8.4 <9.0.

writeHtml() принимает строку HTML и рисует её на текущей странице, начиная с текущего положения курсора. Внутри движка NextPDF один раз сканирует ваш HTML и разбивает его на токены (HtmlTokenizer). Затем он проходит этот список слева направо (HtmlParser). Для каждого элемента он записывает в буфер соответствующие инструкции рисования PDF, которые называются операторами потока содержимого. Движок никогда не строит и не хранит дерево элементов в памяти между вызовами. Это осознанное проектное решение и есть однопроходная потоковая модель, зафиксированная в ADR-001.

Каждый поддерживаемый блочный элемент становится блоком макета, а каждый фрагмент текста — оператором показа текста. Стили из встроенных атрибутов style и блока <style> разрешаются через каскад CSS: правила, которые определяют, какой стиль побеждает, если применимо несколько стилей. Перенос текста, выравнивание и интервалы следуют модели CSS Text, которая определяет, как исходный текст превращается в отформатированный текст с разбивкой на строки (W3C CSS Text Level 3).

Если вы не выбираете шрифт, основной текст использует начертание по умолчанию. Это стандартный шрифт Type 1, один из 14 стандартных шрифтов, перечисленных в ISO 32000-2. Начертание по умолчанию меняется только тогда, когда вы регистрируете и выбираете собственный шрифт или когда профиль соответствия требует, чтобы NextPDF встроил замену.

Сразу задайте правильное ожидание: NextPDF поддерживает подмножество HTML и CSS, а не весь их объём. Этот рецепт охватывает поддерживаемое подмножество. Он не заявляет полную поддержку HTML или CSS. Точный проверенный статус каждого модуля смотрите в матрице поддержки CSS.

Сигнатура метода — writeHtml(string $html): static. Он объявлен в интерфейсе NextPDF\Contracts\PdfDocumentInterface и реализован в NextPDF\Core\Concerns\HasTextOutput. Метод выполняет отрисовку на текущей странице и создаёт её за вас, если страницы ещё нет. Полная таблица PHPDoc для этого метода генерируется из исходного кода.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$doc->writeHtml('<h1>HTML Rendering in NextPDF</h1><p>Rendered with <strong>writeHtml()</strong>.</p>');
$doc->save(__DIR__ . '/out.pdf');

Этот полный самодостаточный пример запускает тестовая оснастка. Он повторяет examples/08-html-basic.php. Вместо жёстко заданного пути вывода он записывает файл по пути, который предоставляет оснастка. Это позволяет оснастке воспроизводимости запустить скрипт дважды и сравнить результаты.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">HTML Rendering in NextPDF</h1>
<p>NextPDF renders <strong>HTML content</strong> directly into PDF pages.
This is the recommended approach for <em>mixed formatting</em>.</p>
<h2>Supported elements</h2>
<ul>
<li>Headings (h1-h6)</li>
<li>Paragraphs with <strong>bold</strong> and <em>italic</em></li>
<li>Ordered and unordered lists</li>
<li>Tables with borders and alignment</li>
<li>Inline styles (color, font-size, margin)</li>
</ul>
<h2>Ordered list</h2>
<ol>
<li>Create a Document instance</li>
<li>Add pages and content</li>
<li>Call save() or output()</li>
</ol>
HTML;
$doc->writeHtml($html);
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script twice.
// Honour it: do not hard-code a path, do not echo the PDF to STDOUT.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/render-html-to-pdf.pdf');
echo "Wrote render-html-to-pdf.pdf\n";

Ожидаемый STDOUT:

Wrote render-html-to-pdf.pdf
  • Передача курсора. writeHtml() перемещает курсор в конец отрисованного содержимого. Следующий cell() или второй writeHtml() продолжит с этого места, а не от верха страницы.
  • Страницы ещё нет. Если страницы не существует, writeHtml() добавляет её перед отрисовкой. Сначала вызовите addPage(), когда нужно задать конкретный размер страницы.
  • Ограничения на число элементов и вложенность. Потоковый движок применяет ограничение в 50,000 элементов и ограничение вложенности в 100 уровней (ADR-001). Документ, превышающий любое из этих ограничений, отклоняется, а не молча усекается.
  • Неподдерживаемая разметка. Элементы и свойства за пределами поддерживаемого подмножества игнорируются или используют запасной вариант; ошибок они не вызывают. Прежде чем полагаться на свойство, проверьте его покрытие по матрице поддержки CSS.
  • Внешние ресурсы. Удалённые изображения и таблицы стилей подчиняются политике внешних ресурсов; политика по умолчанию не загружает произвольные удалённые URL.

Токенизация и отрисовка выполняются за один проход по входным данным, поэтому затраты растут линейно с числом токенов, O(n). Бюджет по умолчанию для этого рецепта — wall_ms: 1500, peak_mb: 96. Поскольку движок передаёт вывод потоком и не держит в памяти объектную модель документа (DOM), пиковое потребление памяти зависит от буфера потока содержимого и активного стека стилей, а не от размера всего документа.

Выдержка из матрицы поддержки CSS (только строки со статусом Verified)

Заголовок раздела «Выдержка из матрицы поддержки CSS (только строки со статусом Verified)»

Эта выдержка включает только строки со статусом Verified в проверенной на достоверность матрице поддержки CSS. “Verified” означает, что есть реализация в src/Html/ и существенный выделенный набор фикстур, который детерминированно проходит в структурном профиле.

Модуль W3CУровеньСтатусПодтверждение
CSS Flexible Box Layout — гибкие блоки (css_flexbox_1)1Verified (проверено)src/Html/Flex/, tests/Unit/Html/Flex/
CSS Grid Layout — сеточная раскладка (css_grid_1)1Verified (проверено)src/Html/Grid/, корпус WPT
CSS Cascading and Inheritance — каскад и наследование (css_cascade_3)3Verified (проверено)src/Html/Cascade/, tests/Unit/Html/Cascade/
CSS Table — таблицы (css_tables_3)3Verified (проверено)src/Html/Table/, фикстуры таблиц + эталонные PDF
CSS Fonts — шрифты (css_fonts_4)4Verified (проверено)src/Html/FontFace/, tests/Unit/Html/FontFace/

Свойства, такие как text-align, text-indent и color, оценены в матрице как “Claimed” (реализованы, но без выделенной модульной фикстуры), поэтому здесь они не указаны как Verified.

Ограничения однопроходной потоковой обработки (ADR-001)

Заголовок раздела «Ограничения однопроходной потоковой обработки (ADR-001)»

Движок HTML не сохраняет DOM. Его состояние — это скалярный курсор и стек стилей по принципу push/pop; текстовые узлы, состоящие только из пробелов, отбрасываются при токенизации. Отсюда следует, что более поздний элемент не может заново стилизовать более ранний, а селекторы, которым нужен контекст всего дерева (например, сложные случаи :has()), ограничены согласно ADR-006. Планируйте макет так, чтобы он зависел только от порядка следования в документе.

Разбор, макет и отрисовка — отдельные слои. Парсер не выдаёт сырые операторы отрисовки, а диспетчеризация макета не разбирает CSS. Пересечение этих границ создаёт долг связанности, который запрещает ADR-010. Для авторов рецептов это означает, что публичная точка входа — writeHtml(). Не обращайтесь к внутренним механизмам парсера.

Согласно ADR-020 форматирующие контексты внутри контейнера (flex, table) могут строить эфемерное поддерево, ограниченное 5,000 узлами на контекст, 20 уровнями в глубину, потолком активной памяти 50 МБ для всех живых контекстов и 10 уровнями вложенности. За пределами этих контекстов потоковая модель не держит дерево. Держите отдельные таблицы и flex-контейнеры в пределах ограничения по узлам, чтобы потребление памяти оставалось предсказуемым.

Считайте входной HTML недоверенным. NextPDF не исполняет скрипты, а политика внешних ресурсов по умолчанию не загружает произвольные удалённые URL, поэтому сам движок ведёт себя осторожно. Тем не менее проверяйте или очищайте любой HTML, который собираете из пользовательского ввода, перед отрисовкой. Ограничения на число элементов и вложенность тоже защищают вас: они ограничивают объём работы, который может потребовать враждебный или некорректный документ.

УтверждениеСпецификацияПунктreference_id (идентификатор ссылки)
CSS Text управляет преобразованием исходного текста в отформатированный текст с разбивкой на строки.W3C CSS Text Level 3 (CSS Text, уровень 3)Пункт css_text_3#x1.x2.p4
Основное начертание по умолчанию разрешается в стандартный шрифт Type 1.ISO 32000-2Пункт iso32000_2_sec9#x1.x29

Этот рецепт показывает, как NextPDF отрисовывает поддерживаемое подмножество HTML и CSS. Он не заявляет полную поддержку HTML или CSS. Проверенный статус каждого модуля приведён в матрице поддержки CSS.

Неприменимо.