การช่วยสำหรับการเข้าถึง: พรีมิทิฟสำหรับการแท็กและโมเดลโครงสร้าง PDF/UA-2
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”NextPDF Core มีพรีมิทิฟสำหรับการสร้างเนื้อหาที่เข้าถึงได้ ได้แก่ แผนผังโครงสร้างเชิงตรรกะ (logical structure tree) การแมประหว่างบทบาทมาตรฐาน การแท็กเนื้อหาแบบ marked-content และแอตทริบิวต์ภาษาตาม Best Current Practice (BCP) 47 ซึ่งสอดคล้องกับโมเดลแผนผังโครงสร้างใน ISO 14289-2 (PDF/UA-2) และ ISO 32000-2 §14.7 ไฟล์ที่สร้างขึ้นจะสอดคล้องได้ก็ต่อเมื่อเอกสารฉบับสุดท้าย ตัวเลือกเนื้อหาของผู้สร้าง และตัวตรวจสอบภายนอกรองรับผลลัพธ์ดังกล่าวเท่านั้น ไลบรารีไม่ได้ยืนยันการรับประกันนี้แทนคุณ
การติดตั้ง
หัวข้อที่มีชื่อว่า “การติดตั้ง”composer require nextpdf/coreภาพรวมเชิงแนวคิด
หัวข้อที่มีชื่อว่า “ภาพรวมเชิงแนวคิด”ไฟล์ Portable Document Format (PDF) แบบติดแท็กจะมีแผนผังโครงสร้างเชิงตรรกะ โดยรากของแผนผังมีองค์ประกอบโครงสร้าง Document เพียงรายการเดียว เทคโนโลยีสิ่งอำนวยความสะดวกจะอ่านแผนผังนี้เพื่อกำหนดลำดับการอ่านที่มีความหมายและไม่ขึ้นอยู่กับเค้าโครงเชิงภาพ (ISO 32000-2 §14.7.2; ISO 14289-2 §8.2.5.2) NextPDF จำลองแนวคิดนี้ด้วยชนิดข้อมูลสามชนิดที่ทำงานร่วมกันในเนมสเปซ NextPDF\Accessibility
StructureTree เป็นเจ้าของลำดับชั้น โดยจะจัดสรรตัวระบุ marked-content สำหรับแต่ละหน้า ติดตามการซ้อนกันของพาเรนต์และไชลด์ และซีเรียลไลซ์รากของแผนผังโครงสร้าง องค์ประกอบโครงสร้าง พาเรนต์ทรี (parent tree) แมปบทบาท (role map) และเนมสเปซโครงสร้างมาตรฐานของ PDF 2.0 ตาม ISO 32000-2 §14.7 createRoot() จะสร้างองค์ประกอบ Document เพียงรายการเดียวที่บังคับให้ต้องมี พร้อมแอตทริบิวต์ภาษา addElement() จะแนบไชลด์ที่ระบุชนิดไว้ hasRoot() และ rootHasChildren() จะรายงานว่ามีแผนผังอยู่หรือไม่ และแผนผังนั้นมีลูกหลานหรือไม่
StructureElement เป็น value object สำหรับดิกชันนารีองค์ประกอบโครงสร้างหนึ่งรายการ โดยเก็บชนิดโครงสร้างมาตรฐาน (ชื่อตาม Table 368 เช่น H1 ถึง H6, P, L, LI, Table, Figure, Link) รายการตัวระบุ marked-content และแอตทริบิวต์การช่วยสำหรับการเข้าถึงแบบเลือกได้สำหรับข้อความทางเลือก (alternative text) ข้อความแทนที่ (replacement text) ชื่อเรื่อง และภาษา องค์ประกอบเดียวสามารถครอบคลุมหลายหน้าได้ โดยสะสมรายการตัวระบุหนึ่งรายการต่อหน้า เพื่อให้อาร์เรย์ kids อ้างอิงถึง marked content ข้ามขอบเขตหน้าได้
TaggedContentEmitter เชื่อมต่อไปป์ไลน์ Hypertext Markup Language (HTML) เข้ากับแผนผังโครงสร้าง เมื่อ Document::enableTaggedPdf() เปิดใช้งานอยู่ ตัวเรนเดอร์ HTML จะเชื่อมต่อ emitter เพื่อให้องค์ประกอบระดับบล็อกสร้างคู่ตัวดำเนินการ marked-content และโหนดองค์ประกอบโครงสร้างที่สัมพันธ์กัน HtmlToStructureMap ให้การแมปแบบอิงตารางจากแท็ก HTML ไปยังชนิดโครงสร้าง PDF (ISO 14289-2 §8) emitter จะส่งเนื้อหาตกแต่งที่ปรากฏซ้ำ เช่น พื้นที่ส่วนหัวและส่วนท้าย HTML ไปยัง artifact และกันเนื้อหานั้นออกจากลำดับการอ่าน
Bcp47Validator ตรวจสอบการแท็กภาษา (Request for Comments (RFC) 5646) โดยตรวจไวยากรณ์ว่าถูกต้องตามรูปแบบ (well-formed) และตรวจความถูกต้องโดยอ้างอิงจากรีจิสทรี โหมดเข้มงวด (ConformancePolicy::strictUa2()) จะปฏิเสธแท็กที่ผิดรูปแบบที่ขอบเขตของ application programming interface (API) แทนที่จะตัดทิ้งอย่างเงียบ ๆ ในเวลาเขียน พฤติกรรมนี้สอดคล้องกับข้อกำหนดของ ISO 14289-2 §8.4.4 ที่ระบุว่ารายการภาษาในแคตาล็อกต้องระบุเป็นภาษาที่เจาะจงได้
พื้นผิว API
หัวข้อที่มีชื่อว่า “พื้นผิว API”| สัญลักษณ์ | ประเภท | สรุป |
|---|---|---|
Document::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): static | เมท็อด | เปิดใช้งานแผนผังโครงสร้างและบริดจ์ HTML กำหนดรายการ mark-info และรายการภาษาในแคตาล็อก |
Document::setLanguage(string $lang): static | เมท็อด | กำหนดภาษาธรรมชาติระดับเอกสาร (BCP-47) |
Document::isTaggedPdfEnabled(): bool | เมท็อด | รายงานว่าโหมดความสอดคล้องที่เปิดใช้งานอยู่บังคับให้ต้องมีการแท็กเชิงโครงสร้างหรือไม่ |
StructureTree::createRoot(string $lang = 'en'): int | เมท็อด | สร้างองค์ประกอบราก Document เพียงรายการเดียวที่บังคับให้ต้องมี |
StructureTree::addElement(int $parentIndex, string $type, int $pageIndex, ...): int | เมท็อด | แนบองค์ประกอบโครงสร้างไชลด์ที่มีการระบุชนิด |
StructureTree::hasRoot(): bool และ rootHasChildren(): bool | เมท็อด | รายงานว่ามีแผนผังอยู่หรือไม่ และแผนผังนั้นมีลูกหลานหรือไม่ |
StructureElement | final class | value object สำหรับองค์ประกอบโครงสร้างหนึ่งรายการ (ข้อความทางเลือก ข้อความแทนที่ ชื่อเรื่อง ภาษา ตัวระบุ) |
RoleMap::standard(): array<string,string> | static | คืนค่าคำศัพท์ชนิดโครงสร้างมาตรฐาน (ISO 32000-2 Table 368 รวมถึงชนิดแบบ PDF 2.0) |
Bcp47Validator::isWellFormed/isValid/validate/normalise | เมท็อด | ตรวจสอบแท็กภาษา RFC 5646 ด้วยการตรวจไวยากรณ์และการตรวจที่อ้างอิงจากรีจิสทรี |
AccessibilityAutoFixerRegistry | final class | รีจิสทรีแบบเลือกเข้าร่วม (opt-in) ตามสไตล์ PHP Standards Recommendation (PSR)-11 สำหรับตัวแก้ไขโครงสร้างแบบฮิวริสติก |
ตัวอย่างโค้ด — เริ่มต้นอย่างรวดเร็ว
หัวข้อที่มีชื่อว่า “ตัวอย่างโค้ด — เริ่มต้นอย่างรวดเร็ว”<?php
declare(strict_types=1);
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// The BCP 47 tag drives the catalog language entry and the// structure-tree root language attribute.$doc->enableTaggedPdf(lang: 'en');$doc->setTitle('Tagged accessibility demo');$doc->addPage();
// Semantic HTML maps to structure elements: h1 to /H1, p to /P,// ul and li to /L plus /LI. Text runs are wrapped in// marked-content operators with stable identifiers.$doc->writeHtml('<h1>Document title</h1><p>Body paragraph.</p>');
$doc->save(__DIR__ . '/output/tagged.pdf');ตัวอย่างโค้ด — การใช้งานจริง
หัวข้อที่มีชื่อว่า “ตัวอย่างโค้ด — การใช้งานจริง”<?php
declare(strict_types=1);
use NextPDF\Conformance\ConformancePolicy;use NextPDF\Core\Document;use NextPDF\Exception\InvalidConfigException;use Psr\Log\LoggerInterface;
final class AccessibleReportWriter{ public function __construct(private readonly LoggerInterface $logger) { }
public function render(string $html, string $bcp47Lang, string $outPath): void { $doc = Document::createStandalone();
try { // strictUa2() rejects malformed BCP 47 tags at the API // boundary (ISO 14289-2 §8.4.4) instead of dropping silently. $doc->enableTaggedPdf($bcp47Lang, ConformancePolicy::strictUa2()); } catch (InvalidConfigException $e) { $this->logger->error('Rejected language tag for tagged PDF', [ 'lang' => $bcp47Lang, 'reason' => $e->getMessage(), ]);
throw $e; }
$doc->setTitle('Quarterly accessibility report') ->setLanguage($bcp47Lang) ->addPage();
$doc->writeHtml($html);
// The engine emits a Degraded / ComplianceRisk advisory directing // the caller to validate externally; surface it to operators // rather than treating tagged output as certified. foreach ($doc->getWarnings() as $warning) { $this->logger->warning('Tagged-PDF advisory', [ 'code' => $warning->code->value, 'message' => $warning->message, ]); }
$doc->save($outPath); }}กรณีขอบและข้อควรระวัง
หัวข้อที่มีชื่อว่า “กรณีขอบและข้อควรระวัง”- ลำดับการเรียกใช้ ให้เรียก
enableTaggedPdf()ก่อนwriteHtml()ไปป์ไลน์ HTML จะตรวจสอบโหมดความสอดคล้องขณะสร้างตัวแยกวิเคราะห์ และจะไม่เชื่อมต่อ emitter ย้อนหลังให้กับเนื้อหาที่เรนเดอร์ไปแล้ว - แผนผังโครงสร้างว่างเปล่า เอกสารที่มี
enableTaggedPdf()แต่ไม่มีลูกหลานเชิงโครงสร้างที่แนบไว้ จะไม่ประกาศ PDF/UA-2 ในเมทาดาทาของเอกสารนั้น เกตสำหรับการเผยแพร่คือrootHasChildren()ไม่ใช่hasRoot()เนื่องจากตัวตรวจสอบจะปฏิเสธไฟล์ที่อ้างว่าเป็น PDF/UA-2 ในขณะที่มีแผนผังโครงสร้างว่างเปล่า (ISO 14289-2 §5; ตรวจยืนยันโดยEmptyTaggedPdfDoesNotAdvertisePdfUa2Test) - การยุบรวมโหมดความสอดคล้อง เมื่อเรียก
enablePdfA()และenableTaggedPdf()บนเอกสารเดียวกัน ตัวจำแนกความสอดคล้องแบบค่าเดียวจะยุบรวมเป็นแบบเรียกครั้งหลังชนะ (last-wins) ผลข้างเคียง (แผนผังโครงสร้าง mark-info) ยังคงเป็นแบบเพิ่มสะสม และ NextPDF จะส่งคำเตือนCONFORMANCE_MODE_CLOBBEREDเพื่อให้สังเกตเห็นการยุบรวมนี้ได้ - ตัวแก้ไขอัตโนมัติไม่ได้ทำงานอัตโนมัติ ตัวแก้ไขในตัว (
EmptyTagStripper,LegacyLangNormaliser,RootLangFallback) มาพร้อมภายใต้NextPDF\Accessibility\AutoFixer\*แต่จะไม่ถูกลงทะเบียนโดยอัตโนมัติ คุณต้องลงทะเบียนตัวแก้ไขเหล่านี้กับAccessibilityAutoFixerRegistryด้วยตนเองอย่างชัดเจน
ข้อจำกัดที่ทราบ
หัวข้อที่มีชื่อว่า “ข้อจำกัดที่ทราบ”NextPDF สร้างโครงสร้างที่สอดคล้องกับโมเดลแผนผังโครงสร้าง PDF/UA-2 แต่จะไม่สร้างความหมายเชิง semantic ที่ไม่สามารถอนุมานได้ คุณต้องจัดเตรียมมาร์กอัปหรือแอตทริบิวต์สำหรับสิ่งต่อไปนี้ NextPDF จะไม่สร้างสิ่งเหล่านี้ให้คุณ:
- ข้อความทางเลือกสำหรับรูปภาพและเนื้อหาที่ไม่ใช่ข้อความอื่น ๆ
- ขอบเขตหัวตาราง (table header scope) และการเชื่อมโยงระหว่างหัวตารางกับเซลล์ที่เกินกว่าที่มาร์กอัป HTML แสดงออกมา
- ข้อความระบุวัตถุประสงค์ของลิงก์ในกรณีที่ข้อความลิงก์ที่มองเห็นไม่ได้อธิบายตัวเอง
- ความหมายเชิงรายการสำหรับเนื้อหาที่จัดวางเชิงภาพเป็นรายการแต่ไม่มีมาร์กอัปของรายการ
- ลำดับการอ่านที่ปรับแก้แล้วในกรณีที่ลำดับในต้นฉบับต่างจากลำดับการอ่านที่ตั้งใจไว้
- การจำแนกระหว่างเนื้อหาตกแต่งกับเนื้อหาที่มีความหมายสำหรับเนื้อหาที่กำกวม
NextPDF ไม่ได้ดำเนินการตรวจยืนยัน PDF/UA-2 แบบครบวงจร ขณะรันไทม์ จะส่งคำแนะนำแบบ Degraded / ComplianceRisk (PDFUA2_FOUNDATIONAL) เพื่อชี้ให้ผู้เรียกตรวจสอบเอาต์พุตด้วยตัวตรวจสอบภายนอกก่อนอนุมัติเข้าสู่การใช้งานจริง ให้ตรวจสอบด้วยตัวตรวจสอบ PDF/UA (เช่น veraPDF) NextPDF ไม่ได้ยืนยันความสอดคล้องแทนคุณ ความสอดคล้องของเอกสารฉบับสุดท้ายขึ้นอยู่กับตัวเลือกในการสร้างเนื้อหาและตัวตรวจสอบ ไม่ได้ขึ้นอยู่กับการเรียก API
ประสิทธิภาพ
หัวข้อที่มีชื่อว่า “ประสิทธิภาพ”การสร้างแผนผังโครงสร้างเป็นเชิงเส้นตามจำนวนองค์ประกอบโครงสร้าง การจัดสรรตัวระบุใช้เวลาคงที่แบบเฉลี่ย (amortized) ต่อหนึ่งลำดับ marked-content การซีเรียลไลซ์เป็นการวนผ่านชุดองค์ประกอบแบบเชิงเส้นเพียงรอบเดียว สำหรับการแท็กที่ขับเคลื่อนด้วย HTML ต้นทุนหลักคือตัวไปป์ไลน์ HTML เอง ไม่ใช่การส่งแท็ก ขีดจำกัดต่อสูตร (recipe) ที่ประกาศไว้ใน performance_budget (เวลารวม 1500 ms หน่วยความจำสูงสุด 64 MB) ใช้กับเอกสารเชิง semantic หลายหน้าทั่วไป เอกสารขนาดใหญ่จะขยายขนาดเป็นเชิงเส้นตามจำนวนองค์ประกอบ ไม่ใช่ตามจำนวนหน้า
หมายเหตุด้านความปลอดภัย
หัวข้อที่มีชื่อว่า “หมายเหตุด้านความปลอดภัย”แท็กภาษาและแอตทริบิวต์การช่วยสำหรับการเข้าถึงจะไหลเข้าสู่ออบเจกต์ชนิด name และ string ของ PDF NextPDF จะ escape ค่าเหล่านี้ผ่าน PdfStringEscaper ดังนั้นค่าภาษา ข้อความทางเลือก ข้อความแทนที่ และชื่อเรื่องที่ผิดรูปแบบหรือมุ่งร้ายจึงไม่สามารถหลุดออกจากบริบทออบเจกต์ PDF ของตนเองได้ นอกจากนี้ โหมดเข้มงวดยังปฏิเสธแท็ก BCP-47 ที่ไม่ได้ลงทะเบียนที่ขอบเขตของ API ซึ่งช่วยลดพื้นผิวอินพุตก่อนที่จะไปถึงตัวเขียน แอตทริบิวต์การช่วยสำหรับการเข้าถึงสามารถบรรจุข้อความอิสระที่ผู้สร้างเป็นผู้ระบุได้ ให้ถือว่าค่าเหล่านี้เป็นเอาต์พุตที่ไม่น่าเชื่อถือ และตรวจทานเช่นเดียวกับที่ตรวจทานเนื้อหาเอกสารอื่น ๆ ดูโมดูล Conformance สำหรับพฤติกรรมของตัวตรวจสอบโปรไฟล์
ความสอดคล้อง
หัวข้อที่มีชื่อว่า “ความสอดคล้อง”หน้านี้แมปพฤติกรรมของไลบรารีเข้ากับตัวระบุข้อกำหนด (clause) แต่ไม่ได้ยืนยันว่าเอาต์พุตของคุณสอดคล้อง ข้อกำหนดที่อ้างอิงเป็นการเรียบเรียงใหม่ ไม่ได้คัดลอกมาแบบอ้างคำต่อคำ ดูการแมปข้อกำหนด PDF/UA-2 สำหรับตารางระดับบทบัญญัติและส่วนที่ไม่ครอบคลุมอย่างชัดเจน แฮชของชังก์การอ้างอิง (citation chunk) ถูกบันทึกไว้ใน docs/public/modules/core/_normative-evidence-a11y.md เรียบร้อยแล้ว