เพิ่มลิงก์และข้อความกำกับ (annotation)
ภาพรวมโดยสรุป
หัวข้อที่มีชื่อว่า “ภาพรวมโดยสรุป”ใช้สูตรนี้เพื่อเพิ่มองค์ประกอบแบบโต้ตอบสามอย่าง ได้แก่ ลิงก์ภายในสำหรับข้ามไปยังหน้าอื่น ลิงก์ภายนอกสำหรับเปิด Uniform Resource Locator (URL) และข้อความกำกับ (annotation) หรือกระดาษโน้ต สูตรนี้อ้างอิงจาก examples/17-links.php และ examples/29-annotations.php
ลิงก์ที่คลิกได้เป็น link annotation ตาม ISO 32000-2 หมายถึงลิงก์ไฮเปอร์เท็กซ์ไปยังปลายทางหรือการกระทำ (action) ส่วนกระดาษโน้ตเป็นข้อความกำกับ (text annotation) ซึ่งปรากฏเป็นไอคอนเมื่อปิด และเป็นป็อปอัปเมื่อเปิด
การติดตั้ง
หัวข้อที่มีชื่อว่า “การติดตั้ง”composer require nextpdf/core:^3ไม่จำเป็นต้องใช้ส่วนขยายเพิ่มเติมใด ๆ application programming interface (API) สำหรับลิงก์และข้อความกำกับ (annotation) มีความเสถียรตั้งแต่เวอร์ชัน 1.0.0 และทำงานบน backport matrix เวอร์ชัน 8.1–8.4
ภาพรวมเชิงแนวคิด
หัวข้อที่มีชื่อว่า “ภาพรวมเชิงแนวคิด”ลิงก์ภายในใช้รูปแบบการเรียกสามครั้ง ซึ่งรองรับการอ้างอิงล่วงหน้า (forward reference):
addLink()จองตัวระบุลิงก์ (ชนิด int)link($x, $y, $w, $h, $id)วางพื้นที่สี่เหลี่ยมผืนผ้าที่คลิกได้ซึ่งผูกกับ id นั้น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
หัวข้อที่มีชื่อว่า “ขอบเขตของ API”ขอบเขตของ API อ้างอิงจาก PHPDoc สูตรนี้ใช้เมท็อดต่อไปนี้:
addLink(): int— จองตัวระบุลิงก์ภายในsetLink(int $linkId, int $pageIndex = -1, float $y = 0): static— ผูก id เข้ากับหน้าปลายทาง (เริ่มนับจากศูนย์) และค่า Ylink(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 annotation | ISO 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