링크 및 텍스트 주석 추가
한눈에 보기
섹션 제목: “한눈에 보기”이 레시피에서는 세 가지 대화형 요소를 추가합니다. 다른 페이지로 이동하는 내부 링크, URL을 여는 외부 링크, 그리고 스티키 노트라고도 하는 텍스트 주석입니다. examples/17-links.php 및 examples/29-annotations.php를 기반으로 합니다.
클릭 가능한 링크는 ISO 32000-2 링크 주석이며, 대상 또는 동작으로 연결되는 하이퍼텍스트 링크입니다. 스티키 노트는 텍스트 주석입니다. 닫혀 있을 때는 아이콘을 표시하고 열려 있을 때는 팝업을 표시합니다.
composer require nextpdf/core:^3선택적 확장 기능은 필요하지 않습니다. 링크 및 주석 API는 1.0.0 이후로 안정적이며 8.1–8.4 백포트 매트릭스에서 실행됩니다.
개념 개요
섹션 제목: “개념 개요”내부 링크는 전방 참조를 지원하는 세 번의 호출 패턴을 사용합니다.
addLink()는 링크 식별자(int)를 예약합니다.link($x, $y, $w, $h, $id)는 해당 id에 바인딩된 클릭 가능한 사각형을 배치합니다.setLink($id, $pageIndex, $y)는 id를 대상 페이지(0부터 시작)와 Y에 바인딩합니다.
아직 존재하지 않는 페이지에 연결하려면 단계 2 이후에 단계 3을 호출합니다. 대상은 명시적 대상 형식으로 지정됩니다. ISO 32000-2 §12.3.2.2는 [page /XYZ left top zoom]를 정의하며, null인 구성 요소는 리더의 현재 값을 유지합니다.
외부 링크에는 int 대신 URL 문자열을 link()에 전달합니다. 그러면 NextPDF는 URI 동작을 내보내며, 해당 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를 대상 페이지(0부터 시작)와 Y에 바인딩합니다.link(float $x, float $y, float $w, float $h, string|int $link): static— 클릭 가능한 사각형입니다. int id는 내부 링크이고, 문자열은 외부 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는 0부터 시작합니다.setLink($id, pageIndex: 2, …)는 세 번째 페이지를 대상으로 합니다. 여기에서 발생하는 하나 차이(off-by-one) 오류가 가장 흔한 실수입니다.link()의 문자열과 int 구분. int는addLink()에서 얻은 내부 대상 id입니다. 문자열은 외부 URL입니다. 잘못된 유형을 전달하면 오류 없이 잘못된 종류의 링크가 생성됩니다.- 예약한 모든 id를 바인딩하세요.
addLink()로 만든 id 중setLink()로 바인딩하지 않은 것에는 대상이 없습니다. 사각형은 클릭할 수 있지만 아무 동작도 하지 않습니다.save()전에 바인딩하세요. - 클릭 가능한 영역은 텍스트가 아니라 사각형입니다.
link()는 명시적인x, y, w, h를 받습니다. 보이는 텍스트를 덮도록 영역 크기를 설정하세요. 엔진은 글리프를 대신 측정해 주지 않습니다. - 외부 링크는 검증되지 않습니다. NextPDF는 URI를 그대로 저장합니다. 대상이 확인 가능한지 또는 안전한지 검증하지 않습니다. 리더가 이를 확인합니다.
각 링크 또는 주석은 페이지에 주석 딕셔너리 하나를 추가합니다. 비용은 요소당 O(1)입니다. 페이지당 수백 개는 2000ms / 64MB 예산 안에 충분히 들어갑니다.
보안 참고 사항
섹션 제목: “보안 참고 사항”외부 링크 대상은 그대로 저장되며 라이브러리가 아니라 리더가 확인합니다. 사용자가 제공한 URL은 신뢰할 수 없는 것으로 취급하세요. 일반적으로 https 스킴을 허용 목록에 추가하세요. javascript: 및 file:는 link()에 전달하기 전에 거부하세요. 주석 텍스트는 리더 UI에 표시되므로 사용자가 제어하는 노트 내용은 길이를 제한하고 정제하세요. 이 레시피에서는 입력 구문 분석이나 네트워크 접근이 발생하지 않습니다.
준수 사항
섹션 제목: “준수 사항”| 설명 | 사양 | 조항 | reference_id 참조 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 준수에 대한 포괄적인 주장을 단언하는 것은 아닙니다.
상업적 맥락
섹션 제목: “상업적 맥락”해당 없음. 링크와 텍스트 주석은 Premium 게이트 없는 Core 기능입니다.