Pular para o conteúdo

Adicione links e anotações de texto

Use esta receita para adicionar três elementos interativos: um link interno que leva a outra página, um link externo que abre um Uniform Resource Locator (URL) e uma anotação de texto, também chamada de nota adesiva. A receita segue examples/17-links.php e examples/29-annotations.php.

Um link clicável é uma anotação de link da ISO 32000-2: um link de hipertexto para um destino ou uma ação. Uma nota adesiva é uma anotação de texto: aparece como um ícone quando fechada e como um popup quando aberta.

Terminal window
composer require nextpdf/core:^3

Nenhuma extensão opcional é necessária. A API (application programming interface) de links e anotações é estável desde a versão 1.0.0 e roda na matriz de backport 8.1–8.4.

Links internos usam um padrão de três chamadas, que oferece suporte a referências antecipadas:

  1. addLink() reserva um identificador de link (um int).
  2. link($x, $y, $w, $h, $id) posiciona um retângulo clicável vinculado a esse id.
  3. setLink($id, $pageIndex, $y) vincula o id a uma página de destino (com índice baseado em zero) e à coordenada Y.

Execute o passo 3 depois do passo 2 quando você criar um link para uma página que ainda não existe. O destino usa um formato de destino explícito. A ISO 32000-2 §12.3.2.2 define [page /XYZ left top zoom], em que um componente nulo mantém o valor atual do leitor.

Para um link externo, passe uma string de URL para link() em vez de um int. Nesse caso, o NextPDF emite uma ação de Uniform Resource Identifier (URI) cujo URI é uma string ASCII UTF-8 obrigatória. Como atalho, write($height, $text, $link) desenha texto inline com uma URL associada, e annotation($x, $y, $w, $h, $text) posiciona uma nota adesiva do subtipo Text. A ISO 32000-2 exige SubtypeLink para uma anotação de link e define o ícone e o comportamento de popup da anotação de texto.

A superfície da API é gerada a partir do PHPDoc. Esta receita depende destes métodos:

  • addLink(): int — reserva um identificador de link interno.
  • setLink(int $linkId, int $pageIndex = -1, float $y = 0): static — vincula um id a uma página de destino (com índice baseado em zero) e à coordenada Y.
  • link(float $x, float $y, float $w, float $h, string|int $link): static — cria um retângulo clicável; um id int indica um link interno, e uma string indica uma URL externa.
  • write(float $height, string $text, string $link = ''): static — escreve texto inline com uma URL opcional.
  • annotation(float $x, float $y, float $w, float $h, string $text, string $subtype = 'Text'): static — adiciona uma anotação do tipo nota adesiva.
<?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');

Este é o exemplo completo, pronto para o harness. Ele respeita NEXTPDF_COOKBOOK_OUTPUT e não introduz entropia própria.

<?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 é baseado em zero. setLink($id, pageIndex: 2, …) tem como alvo a terceira página. Erros de deslocamento por uma unidade aqui são a confusão mais comum.
  • String vs. int em link(). Um int é um id de destino interno vindo de addLink(). Uma string é uma URL externa. Se você passar o tipo errado, obterá o tipo errado de link sem que nenhum erro seja emitido.
  • Vincule todo id reservado. Um id de addLink() que você nunca vincula com setLink() não tem destino. O retângulo é clicável, mas inerte. Vincule-o antes de save().
  • A área clicável é o retângulo, não o texto. link() recebe x, y, w, h explícitos. Dimensione-o para cobrir o texto visível. O engine não mede os glifos por você.
  • Links externos não são validados. O NextPDF armazena o URI literalmente. Ele não verifica se o alvo pode ser resolvido nem se é seguro. O leitor o resolve.

Cada link ou anotação adiciona um dicionário de anotação à página. O custo é O(1) por elemento. Centenas por página permanecem bem dentro do orçamento de 2000 ms / 64 MB.

Os alvos de links externos são armazenados literalmente e resolvidos pelo leitor, não pela biblioteca. Trate URLs fornecidas pelo usuário como não confiáveis. Use uma allow-list para o esquema, normalmente https. Rejeite javascript: e file: antes de passá-los para link(). O texto da anotação aparece na user interface (UI) do leitor; portanto, limite o tamanho e sanitize o conteúdo de notas controlado pelo usuário. Nenhuma análise de entrada nem acesso à rede ocorre nesta receita.

AfirmaçãoEspecificaçãoCláusulareference_id
Uma anotação de link é um link de hipertexto para um destino ou uma ação.ISO 32000-2§12.5.6.5
Subtype é Link para uma anotação de link.ISO 32000-2§12.5.6.5
O URI de uma ação URI é uma string ASCII UTF-8 obrigatória.ISO 32000-2§12.6.4.8
Uma anotação de texto é uma nota adesiva (fechada = ícone, aberta = popup).ISO 32000-2§12.5.6.4
Destino explícito [page /XYZ left top zoom]; null mantém o valor atual.ISO 32000-2§12.3.2.2

Perfil de reprodutibilidade — estrutural. O /ID do trailer e os átomos de data variam a cada salvamento. O harness remove esses átomos e então compara a estrutura normalizada pelo qpdf. Esta receita descreve como o NextPDF produz a estrutura. Ela não afirma conformidade com a ISO 32000-2 como alegação geral.

Não aplicável. Links e anotações de texto são recursos do Core e não exigem Premium.