مقال تقني

تحويل PDF إلى PDF/A وإصلاح بياناته الوصفية في Delphi

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

هذه الخاصية الأخيرة هي قرار التصميم الذي يستحق التأمل. المُحوِّل الذي يختم الادعاء دون فحص أسوأ من لا مُحوِّل إطلاقًا، لأن ملفًا يقول إنه أرشيفي وليس كذلك يمر مباشرةً عبر الأنظمة التي كانت ستلتقطه لولا ذلك. يظهر الفشل بعد سنوات، في تدقيق، على مستند لا أحد يستطيع إعادة توليده

لماذا يفشل ملف PDF صحيح المظهر في فحص PDF/A؟

في أغلب الأحيان لأن المكانين اللذين يقول فيهما PDF من كتبه لا يتفقان. يقرأ المُحقِّق كلًا من قاموس معلومات المستند وحزمة XMP ويرفض الملف الذي يختلفان فيه — ومعظم الملفات التي تفشل في هذه النقطة ببساطة لم تُكتَب فيها حزمة XMP أصلًا

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

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

var
  Lib: TPDFlib;
  Repaired: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('incoming.pdf', '');
    Repaired := Lib.RepairDocumentMetadata;
    Log(Format('%d metadata entries brought into agreement', [Repaired]));
    Lib.SaveToFile('incoming-fixed.pdf');
  finally
    Lib.Free;
  end;
end;

اختيار الجزء قبل التحويل

يتشارك SetPDFAMode وConvertToPDFA ترقيم النمط نفسه، وثلاث من القيم حديثة. النمط 9 هو PDF/A-4، الجزء المبني على PDF 2.0. النمط 10 هو PDF/A-4e، الذي يسمح إضافةً بثلاثية الأبعاد والوسائط الغنية، والنمط 11 هو PDF/A-4f، الذي يسمح بملف مضمَّن بأي صيغة

يتعرّف الجزء 4 على نفسه بشكل مختلف عن الأجزاء قبله: برقم الجزء وسنة نشره، بلا حرف مطابقة لـ PDF/A-4 العادي والحرف E أو F للامتدادين. يتعرف الفحص على الجزء 4، يحكم على ملفاته مقابل PDF 2.0 بدلًا من 1.7، ويُبلِّغ عن ملف من الجزء 4 لا يصرّح بسنة إصداره

كل ملف مضمَّن في مستند من الجزء 4 يصرّح بعلاقته بالمستند، كما يفرض الجزءان 3 و4 معًا. هذه هي القاعدة التي كانت تلتقط المرفقات العادية: كانت العلاقة تُكتَب فقط للمرفقات بعد الأول وأبدًا للأخير، فيحمل مستند بمرفق واحد — الحالة الشائعة — لا علاقة أصلًا ويفشل في التحقق عند هذه النقطة بالذات

var
  Verdict: Integer;
begin
  Lib.LoadFromFile('report.pdf', '');
  Verdict := Lib.ConvertToPDFA(9);        // 9 = PDF/A-4, 10 = 4e, 11 = 4f
  Memo1.Lines.Text := Lib.GetPDFAConversionReport;
  if Verdict = 1 then
    Lib.SaveToFile('report-pdfa4.pdf')
  else
    Log('conversion incomplete - see the report for what stands in the way');
end;

الغرض من تقرير التحويل

اتخاذ قرار الخطوة التالية. التحويل الذي ينجح لا يحتاج تقريرًا؛ التحويل الذي لا ينجح هو السبب كله لوجود التقرير. بعض العوائق قابل للإزالة من قبل المُحوِّل وبعضها ليس كذلك — التشفير، أو محتوى محظور يحمل معنى، أو برنامج خط غير موجود أصلًا على الآلة. يميّز التقرير ما تم عما تبقّى، وهذا يحوّل «فشل التحويل» إلى بند عمل

تعامل مع الحُكم كبوابة في خط معالجة دفعي. حوّل، اقرأ الحُكم، ووزّع الملف: أرشف ما اجتاز، وضع الباقي في طابور بشري مع التقرير مرفقًا. ما لا ينبغي فعله هو حفظ إخراج تحويل فاشل في الأرشيف لأنه يبدو أفضل من المدخل — يحمل الآن ادعاءً رفض الفحص تأكيده

قراءة العلامة التي يحملها الملف أصلًا

قبل تحويل أي شيء، اعرف ما يقوله المستند عن نفسه. فحص PDF/A لا يستطيع قراءة علامة المعايير القائمة يحكم على كل ملف مقابل الجزء 1 مهما كان تصريحه، ما يعني أن مستند PDF/A-2 أو PDF/A-3 صالح تمامًا يُبلَّغ عنه باعتباره بلا علامة وذات إصدار أعلى من اللازم — عكس الحقيقة

تُقرَأ العلامة سواء كتبها المنتج كعنصر XMP أو كسمة. كلتا الصيغتين XMP عادية، وقبول واحدة فقط منهما يترك ملفات من منتجين آخرين تبدو غير معلَّمة. إن تساءلت يومًا لماذا مستند يُتحقَّق منه في مكان آخر يفشل في خط المعالجة لديك، فهذا مكان جيد للنظر أولًا

التنظيف قبل الأرشفة، والعلة التي تستحق المعرفة

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

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

للعمل الأرشيفي المحيط، انظر شروحات فحص PDF/A وPDF/UA المسبق، وتنقيح المحتوى الحقيقي وإزالته، ومخططات امتداد XMP في PDF/A-3 لـ Factur-X، الذي يغطي جانب البيانات الوصفية حين يحمل المستند المؤرشف بيانات فاتورة منظَّمة أيضًا

PDFlibPas مكتبة Pascal أصلية لـ PDF من أجل Delphi وC++Builder وLazarus، فيحدث التحويل والإصلاح والتحقق داخل عمليتك بلا أداة خارجية في السلسلة — انظر صفحة منتج PDFlibPas لأجزاء PDF/A والمنصات المدعومة