مقال تقني

حدود تنفيذ PDF/A وفحوص ترميز الخطوط

يتحقق مكوّن PDFium من حدود تنفيذ ISO 19005-1 الملحق C — رموز الاسم بـ 127 بايت، و8191 عنصر مصفوفة، و4095 مدخل قاموس، و28 مستوى تعشيش حاوية — ويُبلِّغ عن خط TrueType رمزي يحمل مدخل /Encoding. يجري الفحصان على مسار المسح بالبايت، فيحصل تطبيق Delphi أو Lazarus على الحُكم دون تحميل DLL الخاص بـ PDFium إطلاقًا

هذه هي الإخفاقات التي تحيّر الناس أكثر، لأن المستند يبدو سليمًا. يُعرض، يُطبع، كل خط مضمَّن، نية الإخراج موجودة. ثم يرفضه مُحقِّق بسبب قاموس يحمل 4096 مدخل، ولا شيء في المستند المرئي يفسّر السبب

ما الذي تحميه حدود الملحق C فعلًا؟

التشغيل البيني مع تنفيذات تسبق مُولِّدك. يحمل الملحق C حدود تنفيذ مرجع PDF إلى كل جزء PDF/A، والأرقام ليست اعتباطية — تصف ما طُلِب تاريخيًا من قارئ مطابق أن يتعامل معه. ملف يتجاوزها قد يفتح بشكل مثالي في عارض حديث ويفشل في القارئ الأرشيفي الذي قيّد عليه نظام سجلات منذ خمسة عشر عامًا، وهذا بالضبط السيناريو الذي وُجد PDF/A لمنعه

الحدود الأربعة شاملة. رمز اسم بـ 127 بايت بالضبط يُتحقَّق منه؛ 128 لا. مصفوفة بـ 8191 عنصر بالضبط تُتحقَّق منها؛ 8192 لا. يُثبّت مكوّن PDFium كلا جانبي كل حد في مجموعة اختباراته لهذا السبب، لأن خطأ بحرف واحد في فحص حد يُنتج أسوأ نوع من المُحقِّقين: واحد يرفض ملفات مطابقة ويُصدَّق على أي حال

uses FPdfPdfa;

var
  Src: TFileStream;
  Res: TPdfAValidationResult;
begin
  Src := TFileStream.Create('archive.pdf', fmOpenRead or fmShareDenyWrite);
  try
    Res := ValidatePdfACompliance(Src);
    if pvaiArrayOverLimit in Res.Issues then
      Memo1.Lines.Add('An array carries more than 8191 elements');
    if pvaiDictOverLimit in Res.Issues then
      Memo1.Lines.Add('A dictionary carries more than 4095 entries');
    if pvaiNestingOverLimit in Res.Issues then
      Memo1.Lines.Add('Containers nest deeper than 28 levels');
    if pvaiNameOverLimit in Res.Issues then
      Memo1.Lines.Add('A name token is longer than 127 bytes');
  finally
    Src.Free;
  end;
end;

أيُّ المُولِّدات يصطدم بهذه الحدود فعلًا؟

التي تبني البنية برمجيًا، وهذا أغلب إخراج خطوط الأعمال. استمارة ببضعة آلاف من الحقول تُنتج مصفوفة /Annots أو مصفوفة /Fields في AcroForm تنمو بعد 8191. صفحة يتراكم قاموس مواردها مدخلًا واحدًا لكل صورة مُولَّدة أو نسخة خط تعبر 4095. أشجار بنية مُولَّدة بعمق — مستند موسوم مبني بالتكرار فوق نموذج بيانات متداخل — تتجاوز 28 مستوى دون أن يلاحظها أحد، لأن لا أحد ينظر إلى عمق التعشيش

تأتي الأسماء الطويلة من عادة مختلفة: ترميز البيانات إلى رموز اسم. اسم صبغة مبني من معرّف عميل، أو مجموعة محتوى اختياري مسماة بمسار ملف كامل، أو حقل استمارة اسمه الكامل المؤهل يدمج ستة مستويات من التسلسل الهرمي. الأسماء رخيصة التوليد وسهلة جعلها طويلة، و127 بايت تختفي أسرع مما تتوقع متى تُتضمَّن تسمية بترميز UTF-8

الإصلاح بنيوي في كل حالة. قسّم المصفوفة، قسّم القاموس، سطّح التعشيش، قصّر الاسم — توصية الفحص المسبق لكل مشكلة تسمّي الحد الملموس بدلًا من أن تخبرك أن الملف غير صالح. حقن العلامات لا يستطيع المساعدة هنا: هذه ليست ادعاءات بيانات وصفية، هي شكل رسم الكائنات

لماذا يجب ألا يحمل خط TrueType رمزي /Encoding

لأن ISO 19005-1 §6.3.7 يقبل فقط cmap المدمج في الخط لخطوط TrueType الرمزية، ومدخل /Encoding سيناقضه. خط رمزي يربط الأكواد بالرموز بشروطه الخاصة — هذا ما يعنيه رمزي. أضِف جدول ترميز ويصبح هناك الآن إجابتان على سؤال «أي رمز يختاره البايت 0x41»، بلا قاعدة في الملف تقول أيٌّ منها يفوز. يحلها قرّاء مختلفون بشكل مختلف، فيُعرض مستند كنص في عارض ويُعرض كـ dingbats في آخر

يقرأ مكوّن PDFium العلم الرمزي من /FontDescriptor، سواء كُتب الواصف مضمَّنًا في قاموس الخط أو مرجعيًا غير مباشر. يحتفظ خط TrueType غير رمزي بـ /WinAnsiEncoding أو /MacRomanEncoding المطلوب له دون أن يُعلَّم، لأن للخطوط غير الرمزية الترميز هو بالضبط ما يطلبه المعيار. يُطلَق الفحص على التناقض، لا على وجود ترميز

if pvaiSymbolicTrueTypeEncoding in Res.Issues then
  Memo1.Lines.Add(
    'A symbolic TrueType font carries /Encoding; PDF/A admits only its ' +
    'built-in cmap (ISO 19005-1 6.3.7)');

المصدر العملي لهذا العيب هو تحديد الخط الفرعي الذي يقوم به منتج يعامل كل خط TrueType بالطريقة نفسها. Symbol وWingdings وخطوط الباركود وخطوط الأيقونات هي الحاملات المعتادة — بالضبط الخطوط التي يستخدمها مستند عمل لخانات الاختيار والشعارات والباركود، وبالضبط التي لا يعيد أحد فحصها حين يفشل مستند في التحقق بسبب «الخطوط»

كيف تصل المشكلات إلى تقرير فحص مسبق

حدود الحاوية الأربعة مُصنَّفة تحت البنية؛ مشكلة ترميز TrueType الرمزي مُصنَّفة تحت المحتوى. ذلك التقسيم يهم حين يذهب التقرير إلى شخصين مختلفين: نتائج البنية تنتمي عادة إلى من كتب المُولِّد، ونتائج المحتوى تنتمي عادة إلى من زوّد الأصول

تحمل كل مشكلة توصية تسمّي العلاج بمصطلحات ملموسة — قصّر رموز الاسم إلى 127 بايت أو أقل، قسّم المصفوفات بحيث لا تحمل أيٌّ منها أكثر من 8191 عنصرًا، أزل /Encoding من خطوط TrueType الرمزية. تقرير يقول «غير مطابق لـ PDF/A» يبدأ تحقيقًا. تقرير يقول أيُّ حد تجاوز وبكم ينهي واحدًا

التحقق بلا DLL، ولماذا يهم هذا هنا

تجري الفحوص أعلاه جميعها مقابل بايتات الملف، فتعمل في خدمة لا DLL لـ PDFium منشور فيها، أو في خطوة بناء، أو على آلة حيث تحميل DLL أصلي مشكلة سياسة. هذا خط تصميم متعمَّد في مكوّن PDFium: الفحوص التي يمكن الإجابة عنها من البنية تُجاب من البنية، وDLL محجوز لتلك التي تحتاج فعلًا محرّك عرض

لسير العمل المحيط — تشغيل التحقق فوق مجلد، وإنتاج التقارير، وتقرير ماذا تفعل بالنتائج — انظر شروحات فحص PDF/A المسبق في Delphi وواجهة سطر أوامر الفحص المسبق الدفعي. لاختيار الملف الأرشيفي الذي يجلس فوق كل هذه الفحوص، تغطي ملاحظات امتثال PDF/A الأرشيفي أي جزء ومستوى تستهدف قبل أن تبدأ إصلاح النتائج

يغلّف مكوّن PDFium محرّك PDFium من أجل Delphi وC++Builder وLazarus بواجهة VCL عالية المستوى ومجموعة من مُحقِّقات الامتثال تعمل مع DLL أو بدونه — انظر صفحة منتج مكوّن PDFium للمعايير والمنصات المدعومة