Добавление ссылок и текстовых аннотаций
В этом рецепте показано, как добавить три интерактивных элемента: внутреннюю ссылку для перехода на другую страницу, внешнюю ссылку для открытия URL (Uniform Resource Locator) и текстовую аннотацию, также называемую заметкой. Он следует примерам examples/17-links.php и examples/29-annotations.php.
Кликабельная ссылка — это аннотация-ссылка по ISO 32000-2: гипертекстовая ссылка на адресат или действие. Заметка — это текстовая аннотация. В закрытом виде она отображается как значок, а в открытом — как всплывающее окно.
Установка
Заголовок раздела «Установка»composer require nextpdf/core:^3Дополнительное расширение не требуется. API (application programming interface) для ссылок и аннотаций стабилен начиная с версии 1.0.0 и работает в матрице обратной совместимости 8.1–8.4.
Концептуальный обзор
Заголовок раздела «Концептуальный обзор»Для внутренних ссылок используется шаблон из трёх вызовов, который поддерживает опережающие ссылки:
addLink()резервирует идентификатор ссылки (int).link($x, $y, $w, $h, $id)размещает кликабельный прямоугольник, привязанный к этому id.setLink($id, $pageIndex, $y)привязывает id к странице назначения (нумерация с нуля) и координате Y.
Выполняйте шаг 3 после шага 2, если ссылаетесь на страницу, которой ещё не существует. Адресат задаётся как явный адресат. ISO 32000-2 §12.3.2.2 определяет [page /XYZ left top zoom], где компонент null оставляет текущее значение средства просмотра без изменений.
Для внешней ссылки передайте строку URL в link() вместо int. После этого NextPDF создаёт действие URI (Uniform Resource Identifier), у которого поле URI является обязательной строкой UTF-8 ASCII. Как сокращённая форма, write($height, $text, $link) выводит встроенный текст с прикреплённым URL, а annotation($x, $y, $w, $h, $text) размещает заметку подтипа Text. ISO 32000-2 требует SubtypeLink для аннотации-ссылки и определяет значок текстовой аннотации и поведение всплывающего окна.
Интерфейс API
Заголовок раздела «Интерфейс API»Список методов API формируется из PHPDoc. Этот рецепт опирается на следующие методы:
addLink(): int— зарезервировать идентификатор внутренней ссылки.setLink(int $linkId, int $pageIndex = -1, float $y = 0): static— привязать id к странице назначения (нумерация с нуля) и координате Y.link(float $x, float $y, float $w, float $h, string|int $link): static— создать кликабельный прямоугольник; id типа int задаёт внутреннюю ссылку, строка — внешний URL.write(float $height, string $text, string $link = ''): static— вывести встроенный текст с необязательным URL.annotation(float $x, float $y, float $w, float $h, string $text, string $subtype = 'Text'): static— добавить аннотацию-заметку.
Пример кода — быстрый старт
Заголовок раздела «Пример кода — быстрый старт»<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$jump = $doc->addLink(); // 1. reserve an id (forward reference)
$doc->addPage();$doc->setFont('helvetica', 'B', 12);$x = $doc->getX();$y = $doc->getY();$doc->cell(60, 10, 'Go to page 2', newLine: true);$doc->link($x, $y, 60, 10, $jump); // 2. clickable rectangle -> id
$doc->link($doc->getX(), $doc->getY(), 80, 10, 'https://nextpdf.dev'); // external
$doc->addPage();$doc->setLink($jump, pageIndex: 1, y: 0); // 3. bind id to page 2 (index 1)$doc->cell(0, 10, 'Destination (page 2).', newLine: true);$doc->annotation(x: 180, y: 20, w: 10, h: 10, text: 'A reviewer note.');
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/links.pdf');Пример кода — рабочая версия
Заголовок раздела «Пример кода — рабочая версия»Это полный пример, готовый для тестовой обвязки. Он учитывает NEXTPDF_COOKBOOK_OUTPUT и не добавляет собственной энтропии.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Links and Annotations');
// Reserve the internal-link id before its destination page exists.$linkToPage3 = $doc->addLink();
// Page 1 — source of the internal and external links.$doc->addPage();$doc->setFont('helvetica', 'B', 20);$doc->cell(0, 14, 'Links and Annotations', newLine: true);$doc->ln(6);
$doc->setFont('helvetica', 'B', 12);$doc->setTextColor(0, 51, 153);$linkX = $doc->getX();$linkY = $doc->getY();$doc->cell(60, 10, 'Go to Page 3', newLine: true);$doc->link($linkX, $linkY, 60, 10, $linkToPage3); // internal: int id$doc->setTextColor(0);$doc->ln(6);
$doc->setFont('helvetica', 'B', 12);$doc->setTextColor(0, 102, 204);$doc->write(10, 'Visit https://nextpdf.dev', link: 'https://nextpdf.dev');$doc->setTextColor(0);$doc->ln(6);
$urlX = $doc->getX();$urlY = $doc->getY();$doc->cell(80, 10, 'NextPDF on GitHub', newLine: true);$doc->link($urlX, $urlY, 80, 10, 'https://github.com/nextpdf-labs/nextpdf');
// Page 2 — intermediate.$doc->addPage();$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'Internal links can jump across pages; this page is ' . 'skipped by the link on page 1.');
// Page 3 — destination + a sticky note.$doc->addPage();$doc->setLink($linkToPage3, pageIndex: 2, y: 0); // bind id to page 3 (index 2)$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 14, 'Page 3 — Link Target', newLine: true);$doc->ln(4);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'You arrived via the internal link on page 1.');$doc->annotation( x: 185, y: 40, w: 10, h: 10, text: 'Sticky note: appears as an icon; click to read this text.',);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/links.pdf';$doc->save($out);
echo "Created links.pdf\n";Крайние случаи и подводные камни
Заголовок раздела «Крайние случаи и подводные камни»pageIndexнумеруется с нуля.setLink($id, pageIndex: 2, …)указывает на третью страницу. Ошибка на единицу здесь встречается чаще всего.- String или int в
link(). int — это id внутреннего адресата, полученный отaddLink(). Строка — это внешний URL. Если передать неверный тип, вы получите ссылку не того вида без какой-либо ошибки. - Привязывайте каждый зарезервированный id. id, полученный от
addLink(), который вы так и не привязали черезsetLink(), не имеет адресата. Прямоугольник кликабелен, но бездействует. Привяжите его доsave(). - Кликабельная область — это прямоугольник, а не текст.
link()принимает явныеx, y, w, h. Задайте размер так, чтобы область покрывала видимый текст. Движок не измеряет глифы за вас. - Внешние ссылки не проверяются. NextPDF сохраняет URI дословно. Он не проверяет, что адресат разрешается или является безопасным. За его разрешение отвечает средство просмотра.
Производительность
Заголовок раздела «Производительность»Каждая ссылка или аннотация добавляет на страницу один словарь аннотации. Затраты составляют O(1) на элемент. Сотни элементов на странице остаются в пределах бюджета 2000 ms / 64 MB с большим запасом.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Адресаты внешних ссылок сохраняются дословно и разрешаются средством просмотра, а не библиотекой. Считайте URL, предоставленные пользователем, недоверенными. Разрешайте только схемы из списка разрешённых — обычно это https. Отклоняйте javascript: и file: перед их передачей в link(). Текст аннотации отображается в пользовательском интерфейсе (UI) средства просмотра, поэтому ограничивайте длину и очищайте содержимое заметок, поступившее от пользователя. В этом рецепте не происходит ни разбора входных данных, ни доступа к сети.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Спецификация | Раздел | Идентификатор источника (reference_id) |
|---|---|---|---|
| Аннотация-ссылка — это гипертекстовая ссылка на адресат или действие. | ISO 32000-2 | §12.5.6.5 | |
Subtype равен Link для аннотации-ссылки. | ISO 32000-2 | §12.5.6.5 | |
Поле URI действия URI является обязательной строкой UTF-8 ASCII. | ISO 32000-2 | §12.6.4.8 | |
| Текстовая аннотация — это заметка (закрыта = значок, открыта = всплывающее окно). | ISO 32000-2 | §12.5.6.4 | |
Явный адресат [page /XYZ left top zoom]; null сохраняет текущее значение. | ISO 32000-2 | §12.3.2.2 |
Профиль воспроизводимости — структурный. Атомы /ID трейлера и даты меняются при каждом сохранении. Тестовая обвязка удаляет эти атомы, а затем сравнивает структуру, нормализованную qpdf. Этот рецепт описывает, как NextPDF создаёт эту структуру. Он не заявляет о полном соответствии ISO 32000-2.
Коммерческий контекст
Заголовок раздела «Коммерческий контекст»Неприменимо. Ссылки и текстовые аннотации — это возможности Core без ограничений Premium.