Добавление закладок и оглавления
В этом рецепте показано, как добавить закладки в виде иерархической структуры документа. Программа просмотра показывает эти элементы на боковой панели навигации, где они работают как кликабельное оглавление. Уровень вложенности задаётся целым числом. Рецепт основан на examples/12-bookmarks-and-toc.php.
ISO 32000-2 называет такую структуру структурой документа (document outline): это дерево элементов структуры, которое служит визуальным оглавлением.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Дополнительное расширение не требуется. API закладок стабилен с версии 1.0.0 и работает в матрице бэкпортов 8.1–8.4.
Концептуальный обзор
Заголовок раздела «Концептуальный обзор»bookmark($title, $level, $y) добавляет один элемент структуры, привязанный к текущей странице. Если явное значение Y не передано, привязка использует текущую позицию по Y. $level задаёт глубину вложенности: уровень 0 — это глава верхнего уровня, уровень 1 — раздел внутри ближайшего предыдущего элемента уровня 0 и так далее. Дерево структуры движок строит автоматически. ISO 32000-2 связывает элементы через Prev/Next на каждом уровне и вкладывает их через First/Last, при этом корнем служит запись Outlines каталога.
Каждый элемент содержит точку назначения, поэтому при щелчке по закладке программа просмотра переходит на нужную страницу. ISO 32000-2 §12.3.2 устанавливает, что точки назначения могут связываться с элементами структуры. Этот же вызов передаёт данные построителю оглавления NextPDF, поэтому структура и отрисованное оглавление остаются синхронизированными.
Поверхность API
Заголовок раздела «Поверхность API»Поверхность API формируется на основе PHPDoc. Этот рецепт опирается на один метод:
bookmark(string $title, int $level = 0, float $y = -1): static— добавляет элемент структуры на уровне$level, привязанный к текущей странице.$y = -1использует текущую позицию курсора по Y. Передайте неотрицательное значение Y, чтобы точно закрепить точку назначения.
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();$doc->bookmark('Chapter 1', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 1', newLine: true);
$doc->bookmark('Section 1.1', level: 1); // nested under Chapter 1$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'Section body.');
$doc->addPage();$doc->bookmark('Chapter 2', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 2', newLine: true);
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/bookmarks.pdf');Пример кода — продакшен
Заголовок раздела «Пример кода — продакшен»Полный пример, готовый для тестового стенда, учитывает NEXTPDF_COOKBOOK_OUTPUT и не добавляет собственной энтропии.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Bookmarks and Navigation');$doc->setPrintHeader(false);$doc->setPrintFooter(false);$doc->setAutoPageBreak(true, margin: 25);
// Chapter 1$doc->addPage();$doc->bookmark('Chapter 1: Introduction', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 1: Introduction', newLine: true);$doc->ln(3);
$doc->bookmark('What is NextPDF?', level: 1);$doc->setFont('helvetica', 'B', 14);$doc->cell(0, 10, 'What is NextPDF?', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'NextPDF is a modern PDF 2.0 library for PHP 8.4+. ' . 'It generates standards-targeting documents with typography, ' . 'graphics, and signatures.');$doc->ln(5);
$doc->bookmark('Key Features', level: 1);$doc->setFont('helvetica', 'B', 14);$doc->cell(0, 10, 'Key Features', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'HTML rendering, barcodes, PAdES signatures, ' . 'and a worker-safe architecture.');
// Chapter 2$doc->addPage();$doc->bookmark('Chapter 2: Getting Started', level: 0);$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Chapter 2: Getting Started', newLine: true);$doc->ln(3);
$doc->bookmark('Installation', level: 1);$doc->setFont('helvetica', 'B', 14);$doc->cell(0, 10, 'Installation', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'Install via Composer: composer require nextpdf/core');
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/bookmarks.pdf';$doc->save($out);
echo "Created bookmarks.pdf with a 2-level outline\n";Граничные случаи и подводные камни
Заголовок раздела «Граничные случаи и подводные камни»- Пропуски уровней. Переход с уровня 0 на уровень 2 без промежуточного уровня 1 может отображаться некорректно в некоторых программах просмотра. Увеличивайте уровень не более чем на единицу за раз.
- Закладка перед содержимым. Вызывайте
bookmark()в той точке, где вы хотите разместить точку назначения. В большинстве случаев ставьте вызов непосредственно перед заголовком. Вызов после заголовка задаёт точку назначения немного ниже него. - Явное значение Y для точных точек назначения. При
$y = -1точка назначения — текущая позиция курсора по Y. Передайте явное значение Y для стабильной точки назначения. Например, явное значение Y закрепляет начало раздела независимо от того, сколько содержимого ему предшествует. - Поддержка структуры универсальна, но представление различается. Программы просмотра могут отображать структуру свёрнутой или развёрнутой. Этот API не может принудительно задать открытое или закрытое состояние отдельного элемента.
Производительность
Заголовок раздела «Производительность»Каждый вызов bookmark() добавляет один элемент структуры и одну запись оглавления; это операция со сложностью O(1). Дерево структуры окончательно формируется один раз, при save(). Сотни закладок с запасом укладываются в бюджет 2000 мс / 64 МБ.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Заголовки закладок отображаются в интерфейсе навигации программы просмотра. Если заголовок содержит данные, контролируемые пользователем, ограничьте длину и очищайте его так же, как любую отображаемую строку. Этот рецепт не выполняет разбор входных данных и не обращается к сети.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Стандарт | Раздел | Идентификатор ссылки (reference_id) |
|---|---|---|---|
| Структура документа — это дерево элементов структуры, выступающее в роли визуального оглавления. | ISO 32000-2 | §12.3.3 | |
Элементы структуры связываются через Prev/Next и вкладываются через First/Last. | ISO 32000-2 | §12.3.3 | |
Словарь структуры — это запись Outlines каталога. | ISO 32000-2 | §7.7.2 | |
| Точки назначения могут связываться с элементами структуры. | ISO 32000-2 | §12.3.2 |
Профиль воспроизводимости — структурный. Атомы /ID и даты в трейлере меняются при каждом сохранении, поэтому тестовый стенд удаляет эти атомы и сравнивает структуру, нормализованную qpdf. Этот рецепт описывает, как NextPDF создаёт эту структуру. Он не делает всеобъемлющего заявления о соответствии ISO 32000-2.
Коммерческий контекст
Заголовок раздела «Коммерческий контекст»Неприменимо. Структура документа и оглавление доступны в Core и не ограничены Premium.