콘텐츠로 이동

링크 및 텍스트 주석 추가

이 레시피에서는 세 가지 대화형 요소를 추가합니다. 다른 페이지로 이동하는 내부 링크, URL을 여는 외부 링크, 그리고 스티키 노트라고도 하는 텍스트 주석입니다. examples/17-links.phpexamples/29-annotations.php를 기반으로 합니다.

클릭 가능한 링크는 ISO 32000-2 링크 주석이며, 대상 또는 동작으로 연결되는 하이퍼텍스트 링크입니다. 스티키 노트는 텍스트 주석입니다. 닫혀 있을 때는 아이콘을 표시하고 열려 있을 때는 팝업을 표시합니다.

Terminal window
composer require nextpdf/core:^3

선택적 확장 기능은 필요하지 않습니다. 링크 및 주석 API는 1.0.0 이후로 안정적이며 8.1–8.4 백포트 매트릭스에서 실행됩니다.

내부 링크는 전방 참조를 지원하는 세 번의 호출 패턴을 사용합니다.

  1. addLink()는 링크 식별자(int)를 예약합니다.
  2. link($x, $y, $w, $h, $id)는 해당 id에 바인딩된 클릭 가능한 사각형을 배치합니다.
  3. 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 표면은 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 기능입니다.