يُفتح الملف بشكل سليم على جهازك. يعرضه Acrobat، وتبدو معاينة الطباعة صحيحة، وكل صفحة موجودة. ثم يذهب إلى مكتب الطباعة، أو إلى نظام الأرشيف الذي يستوعب دفعتك الشهرية، ويعود مرفوضاً: صور RGB في مهمة CMYK، ولا يوجد مفتاح /Trapped، ونية إخراج لا تتطابق مع المطبعة. لم يكن هناك خطأ في المستند يمكن لأي شخص رؤيته. لقد كان خاطئاً مقابل ملف تعريف (profile)، وتم فحص ملف التعريف في مكان لم تكن فيه. Preflight هو اسم ما قبل الطباعة (prepress) لذلك الفحص، والسؤال الحقيقي هو أين ينتمي عندما تخرج ملفات PDF من كود Delphi الخاص بك بدلاً من سطح مكتب المصمم
لا يمنحك HotPDF دالة preflight لاستدعائها. يحمل المكون نافذة تقرير preflight في العرض التوضيحي لواجهة المستخدم الرسومية (GUI) الخاصة به، ولكن لا يوجد API خلفه يمكن لخدمة أو برنامج بناء نصي (build script) استدعاؤه، والتظاهر بخلاف ذلك سيرسلك للبحث عن طريقة غير موجودة. يبدو هذا وكأنه فجوة حتى تدرك أنه بالنسبة للملفات التي تقوم بإنشائها بنفسك، فإن استدعاء مدقق (validator) على مخرجاتك هو الشكل الخاطئ على أي حال. أنت تتحكم بالفعل في كل خاصية سيفحصها المدقق. التقسيم المفيد هو جعل المولد غير قادر على إرسال ملف سيئ، ثم إثبات ذلك باستخدام أداة لم تكتبها
لماذا تتحقق من مخرجاتك بشكل مختلف
يفترض الـ preflight التقليدي ملفاً غريباً. أنتجه مصمم ما، أو تطبيق آخر، أو سلسلة غير معروفة من التعديلات، وأنت تفحصه لأنه ليس لديك فكرة عما بداخله. المستند الذي أنتجه كودك ليس غريباً. تضمين الخط، ومساحة اللون، ونية الإخراج، وكتلة البيانات الوصفية: قرر برنامجك كل ذلك قبل بضعة أجزاء من الألف من الثانية من وصول الملف إلى القرص. يعد فحصه لاحقاً لاكتشاف الاختيارات التي قمت بها للتو عملاً لا طائل منه. الخطوة الأرخص هي تقييد هذه الخيارات بحيث لا يتواجد ملف غير متوافق أبداً ليتم التقاطه
هناك أيضاً سبب يتعلق بالمصداقية لإبقاء التحقق خارجياً. المكتبة التي تبارك مخرجاتها تقوم بتصحيح امتحانها الخاص. عندما يرفض نظام أرشيف العميل أو RIP الخاص بمطبعة ملفك، فإن عبارة "يقول المكون الخاص بنا إنه جيد" لا تحمل أي وزن. لكن الحكم الصادر من veraPDF أو Acrobat يحمل وزناً، لأن الجانب الآخر يقوم بتشغيل نفس الأدوات
اجعل الامتثال إعداداً، وليس قائمة تحقق
طبقة المنع هي مجرد تكوين (configuration). قم بتعيين PDFACompliance أو PDFXCompliance قبل BeginDoc وسيحتفظ HotPDF بالقواعد المقابلة لتمريرة الإنشاء بأكملها: يقوم بتضمين الخطوط، ويراقب استخدام DeviceRGB و DeviceCMYK مقابل نية الإخراج التي أعلنتها، ويرفض الميزات التي يمنعها ملف التعريف. تظهر التناقضات عند EndDoc، حيث ترتفع بوابات الامتثال بدلاً من شحن شيء سيفشل في المراحل اللاحقة بهدوء. بمجرد حفظ الملف، تقرأ نفس الخصائص ما تم فرضه فعلياً، وهي الحقيقة الوحيدة التي يحتاجها سجل خط الأنابيب الخاص بك أكثر من غيرها:
// 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);
ضع هذه العلامات (flags) في نفس سطر السجل مثل تجزئة بيانات الإدخال (input data hash) وإصدار HotPDF. في اليوم الذي يختلف فيه المدقق والمولد الخاص بك حول ملف، يخبرك هذا السطر عن القالب الذي أنتجه وأي بناء للمكتبة تم تحميله، ويصبح الجدال الذي كان من شأنه أن يلتهم فترة ما بعد الظهيرة عبارة عن أمر grep. يتم توضيح نوايا الإخراج، وملفات تعريف ICC، والوسم (tagging) التي تقف وراء هذه العلامات في الدليل لإنتاج PDF/A، و PDF/X، و PDF/UA باستخدام HotPDF
بوابة أولى رخيصة للملفات التي لم تقم بإنشائها
ليس كل خط أنابيب إنشائياً بحتاً. يقوم العملاء بتحميل ملفات PDF، وتقوم الماسحات الضوئية بإفلاتها في مجلد، ويرفقها الشركاء بالبريد الإلكتروني. يؤدي دفع كل واحد من هؤلاء عبر مدقق هيكلي كامل إلى إضاعة وقت قائمة الانتظار في الملفات التي لن تُفتح حتى. يقرأ API الملف المباشر (Direct File API) الخاص بـ HotPDF ما يكفي من بنية الملف للإجابة على "هل هذا ملف PDF قابل للاستخدام على الإطلاق" دون تحميل شجرة الكائنات (object tree) بأكملها، مما يجعله مكاناً جيداً للفشل السريع:
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 تقرران كيفية تغليفك له. ينطبق اختصار الذاكرة المسطحة (flat-memory shortcut) فقط على المدخلات غير المشفرة؛ سلم DAOpenFileReadOnly كلمة مرور ويتراجع بهدوء إلى تحليل كامل، لذلك يجب أن يمر الملف الذي تعرف أنه مشفر عبر DecryptFile إلى نسخة عمل عادية قبل الفرز (triage). ولا يعني DAGetPageCount شيئاً على مقبض (handle) لم يُفتح بشكل سليم، لذا يظل التحقق من المقبض صارماً وتكون النتيجة غير الإيجابية رفضاً، وليست إعادة محاولة. يتوفر المزيد من هذه الأنماط في مقال API الملف المباشر لمهام PDF الكبيرة
تشغيل veraPDF كجزء من عملية البناء
بالنسبة لأي شيء تدعيه كـ PDF/A أو PDF/UA، فإن veraPDF هو المدقق الذي يجب ربطه. إنه يعمل بدون واجهة مستخدم (headless)، ويأخذ دفعة (batch)، ويُصدر XML أو JSON، ويسمي كل عطل حسب شرط ISO الخاص به، لذلك يشير فشل القاعدة مقابل ISO 19005-1 شرط 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;
تستحق هذه المهلة الزمنية قيمتها. يمكن أن يدفع ملف مشوه (malformed) أي محلل إلى زاوية لا يخرج منها أبداً، والانتظار المفتوح داخل عامل قائمة الانتظار يسحب بقية القائمة معه إلى الأسفل. حدّد وقت الانتظار، وأعطِ المهلة الزمنية رمز خطأ خاصاً بها، وضع الملف جانباً ليتحقق منه إنسان. عند قراءة النتيجة، قم بتحليل XML للبحث عن معرفات القواعد (rule identifiers)، وليس عن النص الذي يمكن للإنسان قراءته. تصمد معرفات القواعد أمام ترقيات المدقق؛ بينما لا تصمد صياغة الرسائل، والكود المستقر هو شيء يمكن لمهندس الدعم البحث به في التذاكر القديمة
كيفية تشغيل الدفعة (batch) تهم بقدر ما يهم ما إذا كان كل ملف يمر. عملية واحدة لكل ملف، وليس واحدة لكل دفعة، لذا فإن الإدخال السام يكلفك مهلة هذا الملف الزمنية ولا شيء آخر. ضع حداً أقصى لعدد عمليات المدقق عند عدد الأنوية (core count)، لأن بناء تقرير XML مقيد بوحدة المعالجة المركزية (CPU-bound) والإفراط في الاشتراك (oversubscription) يؤدي ببساطة إلى التخبط (thrashes). وضع سقفاً للحجم عند الإدخال، لأن كتاباً ممسوحاً ضوئياً بحجم 2 جيجابايت سيمتلك قائمة الانتظار بغض النظر عن مدى صبر المحلل. لا شيء من ذلك يسمى preflight بالمعنى الدقيق للكلمة. إنه الفرق بين بوابة تعيش عبر حجم العمل في نهاية الشهر وبوابة يتم إيقاف تشغيلها في الليلة الأولى التي تعطل فيها خط الأنابيب في الساعة 2 صباحاً
PDF/X هو المكان الذي يقصر فيه هذا الأمر. لا يقوم veraPDF بالتحقق منه، لذلك يظل الفحص العملي هو Acrobat Preflight مع ملف تعريف ISO 15930 الذي حددته مطبعتك. يريد Acrobat إنساناً، مما يعني أخذ عينات (sampling) بدلاً من التغطية الكاملة: الملف الأول من قالب جديد، بالإضافة إلى سحب عشوائي صغير من كل دفعة، بينما تتعامل البوابة الآلية مع كل ما يمكن التعامل معه بدون إنسان. إن الفحص بأخذ العينات الذي يتم تشغيله فعلياً يتفوق على الأتمتة الكاملة التي تظل نصف منتهية إلى الأبد
تقرير ستظل تريده بعد عام
تؤتي بوابة preflight ثمارها مرتين. مرة واحدة عندما توقف ملفاً سيئاً عند الباب، ومرة أخرى بعد ذلك بكثير عندما يسأل شخص ما لماذا تم السماح بمرور ملف معين. تلك اللحظة الثانية هي التي يجب أن تملي التنسيق، لأنها اللحظة التي يتركك فيها تقرير ضعيف عالقاً. لكل ملف تم فحصه، احتفظ بتجزئة الإدخال (input hash)، وعلامات امتثال المولد، وإصدار المكتبة من سطر السجل أعلاه، واسم المدقق وإصداره، وملف التعريف الذي تم الفحص مقابله، والنجاح أو الفشل، ومعرفات القواعد الفاشلة مع أرقام الصفحات حيثما يوفرها المدقق. قم بتخزين هذا التقرير بجانب الملف الذي يصفه. ضعه في نظام منفصل وسيتم إخراج هذا النظام من الخدمة قبل الأرشيف الذي يوثقه
الاستثناءات بحاجة إلى تدوين أيضاً. عندما يصر عميل على شحن ملف تكرهه البوابة، فإن الإجابة ليست تخفيف القاعدة للجميع. سجل من وافق على هذا الملف، وعلى أي أساس، وحتى أي تاريخ، ثم أرفق هذا التنازل (waiver) بتقريره. إن التنازل المقترن باسم وتاريخ انتهاء صلاحية هو قرار يمتلكه شخص ما. أما الفحص الذي تم التعليق عليه (commented out) "مؤقتاً" فهو حادث ينتظر تاريخه
وهناك عادة أخرى تؤتي ثمارها: عندما يفشل ملف، انسخه إلى مجلد تراجع (regression) مسمى قبل أن يلمسه أحد. تعود تقريباً كل مشكلة preflight تستحق التصحيح إلى إدخال واحد محدد، والفرق التي تحتفظ بتلك المدخلات تصلح التكرار في غضون ساعة بدلاً من انتظار ظهوره مرة أخرى في الإنتاج. تعد خصائص الامتثال و API الملف المباشر (Direct File API) الموضحة هنا جزءاً من مكون HotPDF لكل من Delphi و C++Builder، وتغطي وثائقه كل استدعاء بالكامل