بدت دفعة كشوف الحساب الشهرية سليمة على شاشة كل مطور، فشُحنت. أعادت دار الطباعة الدفعة كلها بعد يومين: صور RGB داخل مهمة CMYK ولا تصريح /Trapped. لم تكن الكلفة في إعادة الطباعة؛ بل في يومين من مهلة تنظيمية. كلمة "Preflight" في عالم ما قبل الطباعة تعني التقاط هذا الصنف من المشكلات بالضبط قبل أن تغادر الملفات المبنى، والسؤال الهندسي المهم لفريق Delphi هو أين ينتمي هذا الفحص عندما تنتج ملفات PDF من شيفرتكم نفسها باستخدام مكتبة مثل HotPDF لا من أدوات مصمم مكتبية
المنع أفضل من التفتيش عندما تملك المولّد
يفترض preflight الكلاسيكي ملفًا غريبًا مجهول الجودة ويفحصه بعد الواقعة. عندما يولد تطبيقك المستند، تكون هذه البنية معكوسة: كل خاصية كان المفتش سيفحصها، من تضمين الخطوط، واستخدام فضاءات اللون، ومقاصد الإخراج، والmetadata، قررتها شيفرتك قبل أجزاء من الثانية. أرخص إخفاق preflight هو الإخفاق الذي يُجعل مستحيلًا وقت التوليد
من المهم أن نكون دقيقين بشأن ما يقدمه HotPDF هنا وما لا يقدمه. يشحن المكوّن نافذة تقرير preflight ضمن تطبيق العرض الرسومي، لكن لا توجد API برمجية للـ preflight يمكن استدعاؤها من خدمة أو build script. هذا ليس فجوة كبيرة كما يبدو أولًا، لأن النمط المتين للمستندات المولدة يتكون أصلًا من نصفين مستقلين: قيّد المولد حتى لا يستطيع إخراج بنى غير متوافقة، ثم تحقق من المخرج بمدقق لا تصونه أنت. المكتبة التي تتحقق من خرجها تصحح واجبها بنفسها؛ أما الأداة الخارجية فتعطيك دليلًا يقبله العميل أو المدقق
جانب التوليد: اجعل المطابقة تهيئة لا بند مراجعة
خصائص المعايير في HotPDF هي طبقة المنع. عندما تضبط PDFACompliance أو PDFXCompliance قبل BeginDoc، يفرض المكوّن القواعد المقابلة أثناء التوليد، فيضمّن الخطوط، ويتتبع استخدام DeviceRGB وDeviceCMYK مقابل قصد الإخراج المعلن، ويرفض الميزات التي يحظرها الملف التعريفي. بعد الحفظ، تسجل هذه الخصائص نفسها ما فُرض، وهذا بالضبط ما يحتاجه سجل خط الأنابيب لديك:
// After EndDoc: record the enforced profiles with the run metadata
if Pdf.PDFACompliance <> '' then
Log('Generated as PDF/A level ' + Pdf.PDFACompliance);
if Pdf.PDFXCompliance <> '' then
Log('Generated as PDF/X profile ' + Pdf.PDFXCompliance);
اكتب هذه الأعلام، وhash بيانات الإدخال، وإصدار HotPDF في سطر السجل نفسه. عندما يختلف المدقق لاحقًا مع المولد، يخبرك ذلك السطر أي مراجعة قالب وأي إصدار مكتبة أنتجا الملف محل النزاع، ويستبدل انضباط سطر سجل واحد ظهيرة كاملة من التخمين الجنائي. التهيئة الكاملة التي تسند هذه الأعلام، ومقاصد الإخراج، وملفات ICC، والوسوم، مشروحة في دليلنا إلى إخراج PDF/A وPDF/X وPDF/UA باستخدام HotPDF
فرز الملفات الواردة قبل أن تصل إلى الفحوص المكلفة
ليست كل الخطوط مولدة بالكامل: يرفع العملاء ملفات PDF، وتودع الماسحات ملفاتها، ويرسل الشركاء مستندات بالبريد. تشغيل تحقق بنيوي كامل على كل ملف وارد يهدر وقت الطابور على مدخلات لا تفتح أصلًا. تقرأ Direct File API في HotPDF بنية الملف من دون تحميل شجرة الكائنات كاملة، وهذا يجعلها بوابة أولى رخيصة:
function TriagePdf(Pdf: THotPDF; const FileName: string): Boolean;
var
Handle, Pages: Integer;
begin
Result := False;
Handle := Pdf.DAOpenFileReadOnly(FileName, '');
if Handle <= 0 then
Exit; // structurally unreadable: quarantine, do not validate
try
Pages := Pdf.DAGetPageCount(Handle);
Result := Pages > 0;
finally
Pdf.DACloseFile(Handle);
end;
end;
سلوكان في هذه API يشكلان المنطق المحيط بها. يبقى DAOpenFileReadOnly مسارًا مسطح الذاكرة للمدخلات غير المشفرة فقط، فتمرير كلمة مرور يجعله يعود داخليًا إلى تحليل كامل، لذلك مرر الملفات المعروفة بأنها مشفرة عبر DecryptFile لإنتاج نسخة عمل صريحة أولًا. كما أن DAGetPageCount صالح فقط على handle ناتج من فتح ناجح، لذلك أبق فحص handle صارمًا بدل افتراض قيمة موجبة. توجد أنماط أكثر لهذه الواجهة في مقال Direct File API لسير عمل ملفات PDF الكبيرة
جانب التحقق: veraPDF كخطوة بناء
بالنسبة إلى ادعاءات PDF/A وPDF/UA، يستحق veraPDF الربط بخط الأنابيب: يعمل بلا واجهة، يعالج الدفعات، يخرج XML أو JSON قابلة للقراءة آليًا، ويبلغ عن كل إخفاق برقم بند ISO، لذلك يمكن ربط finding مثل فشل قاعدة مقابل ISO 19005-1 clause 6.2.2 مباشرة بإعداد معروف في المولد. استدعاؤه من Delphi تحكم عادي في العمليات:
function RunVeraPdf(const PdfFile, ReportFile: string): Cardinal;
var
Cmd: string;
SI: TStartupInfo;
PI: TProcessInformation;
begin
Cmd := Format('cmd /c verapdf.bat --format xml "%s" > "%s"',
[PdfFile, ReportFile]);
FillChar(SI, SizeOf(SI), 0);
SI.cb := SizeOf(SI);
if not CreateProcess(nil, PChar(Cmd), nil, nil, False,
CREATE_NO_WINDOW, nil, nil, SI, PI) then
RaiseLastOSError;
try
WaitForSingleObject(PI.hProcess, 120000); // bound the wait per file
GetExitCodeProcess(PI.hProcess, Result);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end;
المهلة ليست زينة. يمكن لملف مشوه أن يدفع أي محلل إلى مسار مرضي، وانتظار غير محدود داخل عامل طابور يسقط الطابور كله معه. قيّد الانتظار، وتعامل مع انتهاء المهلة كفشل له رمزه الخاص، واعزل المدخل للفحص البشري. حلل XML بحثًا عن معرفات القواعد بدل كشط الرسائل المقروءة للبشر؛ معرفات القواعد مستقرة عبر إصدارات المدقق، أما صياغة الرسائل فليست كذلك، والأكواد المستقرة هي ما يستطيع فريق الدعم البحث عنه في التذاكر السابقة
سلوك الدفعات يستحق العناية نفسها مثل صحة الملف الواحد. شغّل المدقق كعملية واحدة لكل ملف لا كعملية واحدة لكل دفعة، حتى يكلفك المدخل المرضي مهلة ذلك الملف لا الدفعة كلها؛ حدّد عدد عمليات المدقق المتزامنة بعدد الأنوية، لأن توليد تقارير XML مرتبط بالمعالج؛ وافرض سقف حجم ملف عند الإدخال، لأن وحشًا ممسوحًا حجمه 2 GB سيسيطر على الطابور مهما كان المحلل مهذبًا. لا شيء من هذا منطق preflight، لكنه الفارق بين بوابة تنجو من حجم نهاية الشهر وبوابة تُعطل أول مرة توقف الخط عند الثانية صباحًا
PDF/X هو الفجوة في هذه القصة: لا يغطيه veraPDF، ويبقى الفحص العملي هو Acrobat Preflight مع ملف ISO 15930 المطابق. Acrobat تفاعلي، لذلك استخدمه للعينات، وأول نسخة من قالب جديد، إضافة إلى سحب عشوائي صغير من كل دفعة، بينما تغطي البوابة الآلية ما يمكن أتمتته. فحص يدوي بالعينة يحدث فعلًا أفضل من أتمتة كاملة نظرية لم يفرغ أحد من بنائها
ما الذي يجب أن يحتويه التقرير ليكون جديرًا بالحفظ
تنتج بوابة preflight قيمة مرتين: مرة عندما تمنع ملفًا سيئًا، ومرة أخرى بعد أشهر عندما يسأل أحدهم لماذا قُبل ملف ما. الاستخدام الثاني هو الذي يفرض شكل التقرير. احتفظ، لكل ملف مفحوص، بما يلي: hash الإدخال، وأعلام المطابقة وإصدار المولد من سطر السجل أعلاه، واسم المدقق وإصداره، والملف التعريفي الذي فُحص ضده، ونتيجة النجاح أو الفشل، وقائمة معرفات القواعد الفاشلة مع أرقام الصفحات عندما يوفرها المدقق. خزّن التقرير بجوار الأثر الذي يصفه، لا في نظام منفصل سيُحال إلى التقاعد قبل الأرشيف
تحتاج الانحرافات المقبولة إلى ورق أيضًا. عندما يصر عميل على شحن ملف لا تحبه البوابة، سجل من وافق عليه، ولماذا، وإلى متى، وألحق سجل الإعفاء هذا بالتقرير بدل إضعاف القاعدة عالميًا. الإعفاء الذي له مالك وتاريخ انتهاء استثناء مُدار؛ أما الفحص المعلّق بتعليق فهو حادثة مستقبلية
تستحق الإخفاقات خطوة أخرى: انسخ الملف الفاشل إلى مجلد regression مسمى. كل حادثة preflight ساعدنا في تحليلها انتهت إلى مدخل قابل للإعادة، والفرق التي احتفظت بتلك المدخلات أصلحت regressions خلال ساعات بدل إعادة اكتشافها في الإنتاج
الأسئلة الشائعة
هل يستطيع HotPDF التحقق برمجيًا من ملف PDF عشوائي من طرف ثالث؟
لا. تقرير preflight في المنتج ميزة عرض رسومية، وليس API قابلة للاستدعاء. نمط الأتمتة المدعوم هو فرض جانب التوليد عبر خصائص المطابقة، مع مدقق خارجي مثل veraPDF للحكم الرسمي
هل يكفي veraPDF لمهام الطباعة؟
يغطي PDF/A وPDF/UA. بالنسبة إلى masters الطباعة PDF/X، شغّل Acrobat Preflight بالملف التعريفي الذي تحدده مطبعتك، وتأكد أن قصد الإخراج يطابق توصيف المطبعة الذي تتوقعه
ما الذي يجب أن يفشل البناء: الأخطاء فقط أم التحذيرات أيضًا؟
اجعل البوابة توقف إخفاقات القواعد الخاصة بالملف التعريفي الذي تدعي المطابقة له، وسجل التحذيرات مع مراقبة الاتجاه. تحويل كل تحذير إلى حاجز يدرّب الناس على تجاوز البوابة، وهذا أسوأ من عدم وجودها
مرجع المنتج
خصائص المطابقة وDirect File API المستخدمة في هذا الخط تنتمي إلى HotPDF Component لـ Delphi وC++Builder؛ وتصف وثائقه كل استدعاء معروض هنا بالكامل