Ajouter des liens et annotations de texte
Cette recette ajoute trois éléments interactifs : un lien interne qui mène vers une autre page, un lien externe qui ouvre une URL et une annotation de texte, aussi appelée note autocollante. Elle fait suite à examples/17-links.php et examples/29-annotations.php.
Un lien cliquable est une annotation de lien ISO 32000-2 : un lien hypertexte vers une destination ou vers une action. Une note autocollante est une annotation de texte : elle affiche une icône lorsqu’elle est fermée et une fenêtre contextuelle lorsqu’elle est ouverte.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Aucune extension optionnelle n’est requise. L’API des liens et des annotations est stable depuis la version 1.0.0 et fonctionne sur la matrice de backport 8.1–8.4.
Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »Les liens internes utilisent un modèle en trois appels qui prend en charge les références anticipées :
addLink()réserve un identifiant de lien (un int).link($x, $y, $w, $h, $id)place un rectangle cliquable lié à cet identifiant.setLink($id, $pageIndex, $y)lie l’identifiant à une page de destination (indexée à partir de zéro) et à une position Y.
Appelle l’étape 3 après l’étape 2 pour cibler une page qui n’existe pas encore. La destination est exprimée sous forme de destination explicite. ISO 32000-2 §12.3.2.2 définit [page /XYZ left top zoom], où un composant null conserve la valeur courante du lecteur.
Pour un lien externe, passe une chaîne d’URL à link() au lieu d’un int. NextPDF émet alors une action URI dont l’URI est une chaîne ASCII UTF-8 obligatoire. Le raccourci write($height, $text, $link) dessine du texte en ligne avec une URL attachée, et annotation($x, $y, $w, $h, $text) place une note autocollante de sous-type Text. ISO 32000-2 exige SubtypeLink pour une annotation de lien et définit l’icône de l’annotation de texte ainsi que le comportement de la fenêtre contextuelle.
Surface de l’API
Section intitulée « Surface de l’API »La surface de l’API est générée automatiquement à partir de la PHPDoc. Cette recette s’appuie sur ces méthodes :
addLink(): int— réserve un identifiant de lien interne.setLink(int $linkId, int $pageIndex = -1, float $y = 0): static— lie un identifiant à une page de destination (indexée à partir de zéro) et à un Y.link(float $x, float $y, float $w, float $h, string|int $link): static— rectangle cliquable ; un identifiant int est interne, une chaîne est une URL externe.write(float $height, string $text, string $link = ''): static— texte en ligne avec une URL optionnelle.annotation(float $x, float $y, float $w, float $h, string $text, string $subtype = 'Text'): static— annotation de type note autocollante.
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »<?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');Exemple de code — Production
Section intitulée « Exemple de code — Production »Voici l’exemple complet prêt pour le harnais de test. Il respecte NEXTPDF_COOKBOOK_OUTPUT et n’introduit aucune entropie de son côté.
<?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";Cas limites et pièges
Section intitulée « Cas limites et pièges »pageIndexest indexé à partir de zéro.setLink($id, pageIndex: 2, …)cible la troisième page. Un décalage d’un cran ici est l’erreur la plus courante.- Chaîne ou int sur
link(). Un int est un identifiant de destination interne issu deaddLink(). Une chaîne est une URL externe. Si tu passes le mauvais type, tu obtiens le mauvais genre de lien sans déclencher d’erreur. - Lie chaque identifiant réservé. Un identifiant
addLink()que tu ne lies jamais avecsetLink()n’a aucune destination. Le rectangle est cliquable, mais inerte. Lie-le avantsave(). - La zone cliquable est le rectangle, pas le texte.
link()prend desx, y, w, hexplicites. Dimensionne-le pour couvrir le texte visible. Le moteur ne mesure pas les glyphes à ta place. - Les liens externes ne sont pas validés. NextPDF stocke l’URI tel quel. Il ne vérifie pas que la cible se résout ni qu’elle est sûre. C’est le lecteur qui la résout.
Performances
Section intitulée « Performances »Chaque lien ou annotation ajoute un dictionnaire d’annotation à la page. Le coût est en O(1) par élément. Des centaines par page restent largement dans le budget de 2000 ms / 64 Mo.
Notes de sécurité
Section intitulée « Notes de sécurité »Les cibles de liens externes sont stockées telles quelles et résolues par le lecteur, pas par la bibliothèque. Traite les URL fournies par l’utilisateur comme non fiables. Restreins le schéma au moyen d’une liste blanche, généralement https. Rejette javascript: et file: avant de les passer à link(). Le texte de l’annotation est affiché dans l’interface du lecteur ; borne donc sa longueur et assainis le contenu de la note contrôlé par l’utilisateur. Il n’y a ni analyse d’entrée ni accès réseau dans cette recette.
Conformité
Section intitulée « Conformité »| Énoncé | Spécification | Clause | reference_id |
|---|---|---|---|
| Une annotation de lien est un lien hypertexte vers une destination ou vers une action. | ISO 32000-2 | §12.5.6.5 | |
Subtype vaut Link pour une annotation de lien. | ISO 32000-2 | §12.5.6.5 | |
L’URI d’une action URI est une chaîne ASCII UTF-8 obligatoire. | ISO 32000-2 | §12.6.4.8 | |
| Une annotation de texte est une note autocollante (fermée = icône, ouverte = fenêtre contextuelle). | ISO 32000-2 | §12.5.6.4 | |
Destination explicite [page /XYZ left top zoom] ; null conserve la valeur courante. | ISO 32000-2 | §12.3.2.2 |
Profil de reproductibilité — structurel. L’/ID du trailer et les atomes de date varient à chaque sauvegarde. Le harnais de test retire ces atomes puis compare la structure normalisée par qpdf. Cette recette décrit comment NextPDF produit la structure. Elle n’affirme pas la conformité ISO 32000-2 comme une garantie générale.
Contexte commercial
Section intitulée « Contexte commercial »Sans objet. Les liens et les annotations de texte sont des fonctionnalités du noyau, sans verrou Premium.