Adicione links e anotações de texto
Visão geral
Seção intitulada “Visão geral”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.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Nenhuma 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.
Visão conceitual
Seção intitulada “Visão conceitual”Links internos usam um padrão de três chamadas, que oferece suporte a referências antecipadas:
addLink()reserva um identificador de link (um int).link($x, $y, $w, $h, $id)posiciona um retângulo clicável vinculado a esse id.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.
Superfície da API
Seção intitulada “Superfície da API”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.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?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');Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”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";Casos extremos e armadilhas
Seção intitulada “Casos extremos e armadilhas”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 deaddLink(). 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 comsetLink()não tem destino. O retângulo é clicável, mas inerte. Vincule-o antes desave(). - A área clicável é o retângulo, não o texto.
link()recebex, y, w, hexplí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.
Desempenho
Seção intitulada “Desempenho”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.
Notas de segurança
Seção intitulada “Notas de segurança”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.
Conformidade
Seção intitulada “Conformidade”| Afirmação | Especificação | Cláusula | reference_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.
Contexto comercial
Seção intitulada “Contexto comercial”Não aplicável. Links e anotações de texto são recursos do Core e não exigem Premium.