ข้ามไปยังเนื้อหา

เพิ่มลิงก์และข้อความกำกับ (annotation)

ใช้สูตรนี้เพื่อเพิ่มองค์ประกอบแบบโต้ตอบสามอย่าง ได้แก่ ลิงก์ภายในสำหรับข้ามไปยังหน้าอื่น ลิงก์ภายนอกสำหรับเปิด Uniform Resource Locator (URL) และข้อความกำกับ (annotation) หรือกระดาษโน้ต สูตรนี้อ้างอิงจาก examples/17-links.php และ examples/29-annotations.php

ลิงก์ที่คลิกได้เป็น link annotation ตาม ISO 32000-2 หมายถึงลิงก์ไฮเปอร์เท็กซ์ไปยังปลายทางหรือการกระทำ (action) ส่วนกระดาษโน้ตเป็นข้อความกำกับ (text annotation) ซึ่งปรากฏเป็นไอคอนเมื่อปิด และเป็นป็อปอัปเมื่อเปิด

Terminal window
composer require nextpdf/core:^3

ไม่จำเป็นต้องใช้ส่วนขยายเพิ่มเติมใด ๆ application programming interface (API) สำหรับลิงก์และข้อความกำกับ (annotation) มีความเสถียรตั้งแต่เวอร์ชัน 1.0.0 และทำงานบน backport matrix เวอร์ชัน 8.1–8.4

ลิงก์ภายในใช้รูปแบบการเรียกสามครั้ง ซึ่งรองรับการอ้างอิงล่วงหน้า (forward reference):

  1. addLink() จองตัวระบุลิงก์ (ชนิด int)
  2. link($x, $y, $w, $h, $id) วางพื้นที่สี่เหลี่ยมผืนผ้าที่คลิกได้ซึ่งผูกกับ id นั้น
  3. setLink($id, $pageIndex, $y) ผูก id เข้ากับหน้าปลายทาง (เริ่มนับจากศูนย์) และค่า Y

เมื่อสร้างลิงก์ไปยังหน้าที่ยังไม่มีอยู่ ให้เรียกขั้นตอนที่ 3 หลังจากขั้นตอนที่ 2 ปลายทางนี้ใช้รูปแบบปลายทางที่ระบุอย่างชัดแจ้ง (explicit destination) ISO 32000-2 §12.3.2.2 นิยาม [page /XYZ left top zoom] ซึ่งส่วนประกอบที่เป็น null จะคงค่าปัจจุบันของโปรแกรมอ่านไว้

สำหรับลิงก์ภายนอก ให้ส่ง สตริง URL ไปยัง link() แทนค่า int จากนั้น NextPDF จะสร้าง Uniform Resource Identifier (URI) action ที่มี URI เป็นสตริง UTF-8 ASCII ที่จำเป็นต้องมี รูปแบบทางลัด write($height, $text, $link) จะวาดข้อความแบบ inline พร้อมแนบ URL ส่วน annotation($x, $y, $w, $h, $text) จะวางกระดาษโน้ตแบบ subtype Text ISO 32000-2 กำหนดให้ต้องใช้ SubtypeLink สำหรับ link annotation และนิยามไอคอนของ text annotation รวมถึงพฤติกรรมป็อปอัป

ขอบเขตของ API อ้างอิงจาก PHPDoc สูตรนี้ใช้เมท็อดต่อไปนี้:

  • addLink(): int — จองตัวระบุลิงก์ภายใน
  • setLink(int $linkId, int $pageIndex = -1, float $y = 0): static — ผูก id เข้ากับหน้าปลายทาง (เริ่มนับจากศูนย์) และค่า Y
  • link(float $x, float $y, float $w, float $h, string|int $link): static — สร้างพื้นที่สี่เหลี่ยมผืนผ้าที่คลิกได้ โดย id ชนิด int หมายถึงลิงก์ภายใน และสตริงหมายถึง URL ภายนอก
  • write(float $height, string $text, string $link = ''): static — เขียนข้อความแบบ inline พร้อม URL ทางเลือก
  • annotation(float $x, float $y, float $w, float $h, string $text, string $subtype = 'Text'): static — เพิ่มข้อความกำกับ (annotation) แบบกระดาษโน้ต
<?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');

ต่อไปนี้คือตัวอย่างฉบับสมบูรณ์ที่พร้อมใช้กับ harness โดยเคารพค่า NEXTPDF_COOKBOOK_OUTPUT และไม่เพิ่มค่าแบบสุ่ม (entropy) ใด ๆ เอง

<?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 เริ่มนับจากศูนย์ setLink($id, pageIndex: 2, …) ชี้ไปยังหน้าที่สาม ความคลาดเคลื่อนหนึ่งหน่วย (off-by-one) ในจุดนี้เป็นข้อผิดพลาดที่พบบ่อยที่สุด
  • สตริงกับ int ใน link() ค่า int คือ id ของปลายทางภายในที่ได้จาก addLink() ส่วนสตริงคือ URL ภายนอก หากส่งชนิดข้อมูลผิด จะได้ลิงก์ผิดประเภทโดยไม่มีข้อผิดพลาดแจ้งเตือน
  • ผูก id ที่จองไว้ทุกตัว id จาก addLink() ที่ไม่ได้ผูกด้วย setLink() จะไม่มีปลายทาง พื้นที่สี่เหลี่ยมผืนผ้านั้นคลิกได้แต่ไม่มีการตอบสนอง ผูก id ก่อนเรียก save()
  • พื้นที่ที่คลิกได้คือสี่เหลี่ยมผืนผ้า ไม่ใช่ข้อความ link() รับค่า x, y, w, h อย่างชัดแจ้ง กำหนดขนาดให้ครอบคลุมข้อความที่มองเห็น เอนจินไม่ได้วัดขนาดของกลีฟ (glyph) ให้โดยอัตโนมัติ
  • ลิงก์ภายนอกไม่ได้รับการตรวจสอบความถูกต้อง NextPDF จัดเก็บ URI ตามที่ระบุไว้ทุกตัวอักษร โดยไม่ตรวจสอบว่าปลายทางเข้าถึงได้หรือปลอดภัยหรือไม่ โปรแกรมอ่านเป็นผู้เข้าถึงปลายทางนั้น

ลิงก์หรือ annotation แต่ละรายการจะเพิ่ม annotation dictionary หนึ่งรายการลงในหน้า ต้นทุนเป็น O(1) ต่อองค์ประกอบ แม้มีหลายร้อยรายการต่อหน้า ก็ยังอยู่ในงบประมาณ 2000 ms / 64 MB ได้อย่างสบาย

ปลายทางของลิงก์ภายนอกถูกจัดเก็บตามที่ระบุไว้ทุกตัวอักษร และโปรแกรมอ่านเป็นผู้เข้าถึง ไม่ใช่ไลบรารี ให้ถือว่า URL ที่ผู้ใช้ป้อนเป็นข้อมูลที่ไม่น่าเชื่อถือ กำหนด allow-list ของ scheme ซึ่งโดยทั่วไปคือ https ปฏิเสธ javascript: และ file: ก่อนส่งไปยัง link() ข้อความของ annotation จะปรากฏใน user interface (UI) ของโปรแกรมอ่าน ดังนั้นจึงควรจำกัดความยาวและทำความสะอาด (sanitize) เนื้อหาของโน้ตที่ผู้ใช้ควบคุม สูตรนี้ไม่มีการแยกวิเคราะห์อินพุตหรือการเข้าถึงเครือข่าย

ข้อความระบุข้อกำหนดข้อรหัสอ้างอิง (reference_id)
link annotation คือลิงก์ไฮเปอร์เท็กซ์ไปยังปลายทางหรือไปยังการกระทำ (action)ISO 32000-2§12.5.6.5
Subtype เป็น Link สำหรับ link annotationISO 32000-2§12.5.6.5
ค่า URI ของ URI action เป็นสตริง UTF-8 ASCII ที่ต้องมีISO 32000-2§12.6.4.8
text annotation คือกระดาษโน้ต (ปิด = ไอคอน เปิด = ป็อปอัป)ISO 32000-2§12.5.6.4
ปลายทางแบบชัดแจ้ง [page /XYZ left top zoom] โดยค่า null จะคงค่าปัจจุบันไว้ISO 32000-2§12.3.2.2

โปรไฟล์ความสามารถในการสร้างซ้ำ — เชิงโครงสร้าง /ID ใน trailer และค่าวันที่จะแตกต่างกันทุกครั้งที่บันทึก harness จะตัดค่าเหล่านั้นออก แล้วจึงเปรียบเทียบโครงสร้างที่ผ่านการทำให้เป็นบรรทัดฐานด้วย qpdf สูตรนี้อธิบายวิธีที่ NextPDF สร้างโครงสร้างดังกล่าว โดยไม่ได้ยืนยันความสอดคล้องตาม ISO 32000-2 แบบครอบคลุมทั้งหมด

ไม่เกี่ยวข้อง ลิงก์และข้อความกำกับ (text annotation) เป็นความสามารถของ Core โดยไม่มีเงื่อนไขการเข้าถึงระดับ Premium