يعتمد ملف PDF القابل للوصول على هيكل واحد لا تعرضه الصفحة المرئية أبدًا: شجرة الهيكل المحددة في ISO 32000-1 §14.7. إنه تسلسل هرمي منطقي للعناوين والفقرات والجداول والأشكال، يقع فوق المحتوى المرسوم ويتم تعيينه للأدوار القياسية من خلال خريطة أدوار. يقرأ قارئ الشاشة تلك الشجرة، وليس العلامات الموجودة على الصفحة. بدونها، تكون الفاتورة المُنشأة التي تبدو خالية من العيوب فارغة دلاليًا، لأن تدفق المحتوى يسجل ترتيب الرسم ولا شيء غير ذلك. يمكن الإعلان عن الإجمالي قبل عناصر السطر، ويمكن للتذييل أن يقطع في فقرة، ويمكن أن ينهار جدول العناصر في سلسلة واحدة غير متمايزة من الكلمات. تكلفة منع ذلك تميل لصالحك. إن إصدار الهيكل أثناء الرسم هو دقائق من الكود؛ تعديله في المستندات النهائية هو مشروع معالجة. تعرض losLab PDF Library (PDFlibPas) الشجرة لـ Delphi و C++Builder من خلال مجموعة صغيرة من الاستدعاءات التي تغلف كل عملية رسم في دورها المنطقي
كيف يرتبط المحتوى المميز بشجرة الهيكل
تتعاون طبقتان. في تدفق المحتوى، يتم تجميع عمليات الرسم في تسلسلات محتوى مميزة (marked-content sequences)، كل منها يحمل معرف محتوى مميز (MCID) كعدد صحيح. في كتالوج المستند، تقوم شجرة الهيكل بتعيين هذه الـ MCIDs في تسلسل هرمي من العناصر المكتوبة (H1، P، Table، Figure) بسمات مثل النص البديل واللغة. تعد أنواع العناصر المخصصة قانونية، ولكن يجب أن يحل كل منها دورًا قياسيًا من خلال خريطة الأدوار (ISO 32000-1 §14.8.4). يُصنف المحتوى الذي لا يحمل أي معنى على الإطلاق، مثل القواعد والخلفيات وأثاث الصفحة المتكرر، على أنه قطعة أثرية (artifact) حتى تتخطاه التكنولوجيا المساعدة بدلاً من قراءته في منتصف الجملة
تحتفظ PDFlibPas بكلتا الطبقتين خلف زوج أقواس واحد. يفتح BeginTag عنصر هيكل ويبدأ تسلسل المحتوى المميز، وتهبط مكالمات الرسم داخله، ويغلق EndTag كليهما. مسك الدفاتر الذي يعرقل وضع العلامات اليدوية، و MCIDs وشجرة الأصل ومراجع الصفحة، يحدث داخليًا حيث لا يمكنك فهمه بشكل خاطئ
مفتاحان على مستوى المستند يؤطران العمل قبل فتح أي علامة. يكتب SetMarkInfo علامة الكتالوج التي تعلن عن المستند الموسوم، ويقرأها IsTaggedPDF مرة أخرى، وهو المسبار الأول الرخيص عند تحديد ما إذا كان الملف الوارد يحتوي على أي هيكل يستحق الحفاظ عليه. اللغة لها نقطتا دخول. يقوم SetDocumentLanguage بتعيين المستند الافتراضي بمفرده، بينما يقوم SetPDFUAMode بتعيينه كجزء من تمكين مخرجات PDF/UA الكاملة. يمكن وضع علامة مفيدة على الملف دون المطالبة بتوافق PDF/UA، وغالبًا ما يبدأ الطرح التدريجي من هناك بالضبط
وضع العلامات أثناء الرسم، وليس بعده
نمط الإنشاء الذي يعمل هو التعامل مع قوس العلامة كجزء من توقيع كل استدعاء رسم، وليس أبدًا كتمريرة لاحقة:
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1); // top-left origin
Lib.SetPDFUAMode('en-US'); // bumps the save version to PDF 1.7
Lib.SetInformation(1, 'Service Manual'); // /Title is mandatory for PDF/UA
Lib.AddRoleMap('ManualTitle', 'H1'); // custom type -> standard role
Lib.AddStandardFont(4);
Lib.SetTextSize(18);
Lib.BeginTagEx2('ManualTitle', '', '', 'en-US', '', 'h1-cover', '');
Lib.DrawText(72, 96, 'Service Manual');
Lib.EndTag;
Lib.BeginTag('Figure', 'Exploded view of the gearbox assembly', '');
Lib.AddImageFromFile('gearbox.png', 0);
Lib.EndTag;
Lib.BeginArtifact('Layout'); // page decoration: excluded from reading
// ... draw rules and background tint ...
Lib.EndArtifact;
Lib.SaveToFile('manual.pdf');
finally
Lib.Free;
end;
end;
ثلاث مكالمات في هذا التسلسل تحمل وزن الامتثال. يقوم SetPDFUAMode بتمكين إخراج PDF/UA ويصطدم بصمت إصدار المستند بـ PDF 1.7، والذي يصطدم بتثبيت الإصدار (version pinning). يرفض المستند المقفل إلى PDF 1.4 بـ LockSaveVersion الحفظ ويُرجع رمز الخطأ 602 بمجرد تنشيط وضع UA، وهو تصادم يميل إلى الظهور عندما يتم تكوين ملفات تعريف الأرشفة ومتطلبات الوصول بواسطة فرق مختلفة. يكتب SetInformation(1, ...) عنوان المستند، والذي يتوقع ISO 14289 من المشاهدين عرضه بدلاً من اسم الملف؛ غيابه هو أحد أكثر نتائج PDF/UA شيوعًا في البرية. يسجل AddRoleMap النوع المخصص ManualTitle كـ H1، ويؤدي تخطيه إلى ترك التشخيصات الموضحة أدناه تضع علامة على دور غير محدد
تستحق مستويات العناوين سياسة مدروسة، وليست خيارات مخصصة مصممة لمظهر الصفحة. يقفز مستخدمو قارئ الشاشة بين الأقسام من خلال اختصار العنوان، لذلك فإن القالب الذي ينتقل من H1 إلى H3 لأن المستوى المتوسط بدا كبيرًا جدًا في التصميم المرئي يكسر هذا التنقل بهدوء، ولن تكتشفه أي مراجعة مرئية على الإطلاق. إنه بالضبط العيب الذي يوجد تشخيص HEADING-LEVEL-SKIP لتسميته. قم بتعيين الأنماط المرئية لكل قالب إلى سلم عناوين ثابت مرة واحدة، في مكان واحد، ولن يبدأ الانجراف أبدًا
جداول يمكن لقارئ الشاشة التنقل فيها فعليًا
خطوط الشبكة المرسومة لا تعني شيئًا خارج الشاشة. ما تتنقل فيه برامج قراءة الشاشة هو العلاقات الهيكلية: أي الخلايا هي رؤوس، وما الذي يحكمه كل رأس، وكيف ترتبط خلايا البيانات بالرؤوس في التخطيطات غير المنتظمة. تتعامل استدعاءات سمة عنصر الهيكل مع الثلاثة:
Lib.BeginTag('Table', '', '');
Lib.BeginTag('TR', '', '');
Lib.BeginTagEx2('TH', '', '', '', '', 'col-part', '');
Lib.SetStructElemScope('Column'); // valid only while this TH is open
Lib.DrawText(72, 120, 'Part');
Lib.EndTag;
Lib.BeginTagEx2('TH', '', '', '', '', 'col-torque', '');
Lib.SetStructElemScope('Column');
Lib.SetStructElemColSpan(2); // header spans the value and unit columns
Lib.DrawText(200, 120, 'Tightening torque');
Lib.EndTag;
Lib.EndTag;
Lib.BeginTag('TR', '', '');
Lib.BeginTag('TD', '', '');
Lib.SetStructElemHeaders('col-part'); // explicit binding for irregular tables
Lib.DrawText(72, 140, 'M8 flange bolt');
Lib.EndTag;
Lib.EndTag;
Lib.EndTag; // Table
قاعدة الترتيب صارمة ويتم إنفاذها في صمت. ينطبق كل استدعاء SetStructElem* على العلامة المفتوحة في تلك اللحظة، بين BeginTag و EndTag الخاصين بها، ويعود بصفر دون رفع أي شيء عندما لا تكون أي علامة مفتوحة أو السمة لا تنطبق على العلامة الحالية. الاستدعاء في غير محله يختفي ببساطة. التفاف قيم الإرجاع في تأكيدات أثناء التطوير يمسك الانجراف بينما لا يزال بإمكانك رؤيته؛ إذا ترك بمفرده، يظهر النطاق المفقود فقط عندما يقوم تدقيق إمكانية الوصول بتشغيل قارئ شاشة حقيقي عبر الجدول. معرفات العناصر التي يتم تمريرها عبر BeginTagEx2 تغذي شجرة المعرف (ISO 32000-1 §14.7.4)، وهذا ما يجعل ربط SetStructElemHeaders قابلاً للحل في المقام الأول
تغطي عائلة السمات نفسها بقية ما تعتمد عليه التكنولوجيا المساعدة. يعلن SetStructElemListNumbering عن كيفية تسمية عناصر القائمة، لذلك يعلن قارئ الشاشة عن الموضع داخل القائمة بدلاً من قراءة الحروف الرسومية للتعداد النقطي (bullet glyphs). يسجل SetStructElemBBox المربع المحيط للأشكال والجداول، والذي تستخدمه مشاهدات إعادة التدفق لوضع المحتوى. يوفر SetStructElemActualText نصًا بديلاً للعمليات التي لا يتم تعيين الحروف الرسومية الخاصة بها إلى أحرف قابلة للقراءة، مثل الحرف الاستهلالي المسقط المُجمع من فن المتجهات. كل واحد يتبع نفس القاعدة: يرتبط بالعلامة المفتوحة، أو يختفي
القطع الأثرية (Artifacts)، واللغة، وبوابة التشخيص قبل الحفظ
أثاث الصفحة المتكرر، يعني الرؤوس الجارية، وعلامات الطي، والعلامات المائية، وظلال الخلفية، تنتمي داخل أقواس BeginArtifact و EndArtifact حتى لا تدخل مجرى القراءة أبدًا. اللغة قابلة للتوريث. يأتي المستند الافتراضي من وسيطة SetPDFUAMode، ويقوم التشغيل بلغة أخرى بتجاوزه لكل عنصر من خلال BeginTagEx أو SetStructElemLang. هذا ما يجعل الاقتباس الفرنسي داخل دليل باللغة الإنجليزية قابلًا للنطق
قبل الحفظ، يقوم GetPDFUADiagnostics بتشغيل الفحوصات الهيكلية للمكتبة فوق المستند الموجود في الذاكرة وإرجاع النتائج كنص، حيث تعني سلسلة فارغة أنه لم يتم العثور على شيء. تسمي الرموز أخطاء التأليف الكلاسيكية مباشرة: FIGURE-NO-ALT لصورة بدون نص بديل، HEADING-LEVEL-SKIP لـ H3 يتبع H1، ROLEMAP-UNMAPPED لنوع مخصص لم يتم تسجيله أبدًا. قم بتوصيل هذا في البناء (قم بإنشاء مجموعة المستندات، وفشل في الخطوة في تشخيصات غير فارغة) وتصبح تراجعات إمكانية الوصول إخفاقات بنمط وقت الترجمة بدلاً من نتائج التدقيق بعد أشهر. لا يزال حكم الامتثال الكامل ينتمي إلى الفحص المبدئي (preflight) على الملف المحفوظ، وهو مغطى في الفحص المبدئي PDF/A و PDF/UA في Delphi، لأنه يتم تطبيق بعض عمليات التطبيع فقط أثناء التسلسل
التنقل التعليق التوضيحي له مقبضه الخاص. يتوقع PDF/UA اجتياز لوحة المفاتيح لحقول النموذج والروابط لاتباع ترتيب الهيكل، ويكتب SetTabOrderMode إدخال ترتيب علامة التبويب على مستوى الصفحة الذي يكرمه المشاهدون، مع توفر GetTabOrderMode لتدقيق الملفات الواردة. إنه نوع المتطلبات التي لا يلاحظها أحد حتى يقدم مستخدم لوحة المفاتيح فقط الخطأ، ويكلف استدعاء واحد لكل مستند للحصول عليه بشكل صحيح
أشجار الهيكل لا تنجو من كل دمج
تظل المستندات الموسومة (Tagged documents) موسومة فقط عندما تحتفظ كل خطوة معالجة لاحقة بالشجرة، والحافة الحادة داخل PDFlibPas هي عائلة قائمة الدمج. MergeFileListFast يتاجر بحفظ شجرة الهيكل من أجل السرعة. هذه هي التجارة الصحيحة لدُفعات الصور الممسوحة ضوئيًا والخاطئة للتقارير الموسومة، لأن الإخراج يفتح بشكل جيد، ويعرض بشكل متطابق، وقد فقد بهدوء طبقة إمكانية الوصول الخاصة به. استخدم MergeFileList الافتراضي أو المتغير الصارم كلما تم وضع علامة على أي إدخال، واجعل IsTaggedPDF جزءًا من تأكيدات ما بعد التجميع بحيث لا يمكن شحن دفعة مسطحة دون أن يلاحظ أحد ذلك. تحمل خطوط أنابيب التجميع لمجموعات المستندات الكبيرة المزيد من المفاضلات من هذا النوع، والتي تم استكشافها في دمج وتقسيم ملفات PDF الكبيرة والوصول المباشر
يتم إغلاق حلقة التحقق خارج المكتبة: افتح الإخراج في Acrobat، وافحص لوحة العلامات، واقرأ مستندًا واحدًا على الأقل لكل عائلة قالب بقارئ شاشة حقيقي. تلتقط التشخيصات الأخطاء الهيكلية؛ تلتقط الأذن البشرية فقط ترتيب القراءة الصالح من الناحية الفنية والمحير من الناحية العملية. تتوفر تصميمات التقييم والمرجع الكامل لواجهة برمجة تطبيقات وضع العلامات (API reference) على صفحة منتج losLab PDF Library for Delphi