يتحقق مكون PDFium لـ Delphi من صحة مستندات PDF/X الجاهزة للطباعة من خلال TPdf.ValidatePdfX، والتي تطبق فحص ISO 15930 في طبقتين: ثمانية فحوصات محتوى على مستوى البايت (ضغط LZW المحظور، و JavaScript، وحقول النماذج، ومراجع OPI، و TrimBox المفقود، ومفتاح Trapped غير المعين، والمزيد) بالإضافة إلى تمريرة نموذج كائن PDFium التي تستخدم FPDFFont_GetIsEmbedded للتحقق من تضمين الخطوط في كل كائن نصي في كل صفحة. والنتيجة هي سجل TPdfXValidationResult يسمي مستوى المطابقة المكتشف ويسرد كل انتهاك كتعداد مكتوب (typed enum)، بحيث يمكن لتطبيق Delphi الخاص بك إخبار العميل بدقة لماذا سيرتد الملف في مطبعة الصحف قبل أن يحرق أي شخص لوحة
إذا سبق لك أن أرسلت وظيفة إلى طابعة تجارية واستلمتها مرة أخرى مع رفض من سطر واحد — "لا TrimBox"، "الخطوط غير مضمنة"، "Trapped غير معين" — فأنت تعرف تكلفة المعرفة المتأخرة. يعد PDF/X هو المقابل لما قبل الطباعة لـ PDF/A: فحيث يضمن PDF/A المخصص للأرشفة تقديم مستند بشكل متطابق بعد عقود من الآن، يضمن PDF/X أن يفصل المستند، وتظهر صوره، ويتم قصه بشكل متطابق على RIP الخاص بشخص آخر صباح الغد. يشترك المعياران في الآليات (تعريف XMP، و OutputIntents، وملفات تعريف ICC المضمنة) ولكنهما يجيبان على أسئلة مختلفة، ولهذا السبب يشحن المكون مدققات منفصلة لكل منهما — جانب PDF/A مغطى في التحقق من صحة PDF/A المسبق للرحلة باستخدام مكون PDFium
ما الذي يتطلبه معيار ISO 15930 فعلياً من ملف PDF جاهز للطباعة؟
تم وضع معيار ISO 15930 لجعل التبادل الأعمى ممكناً: حيث يسلم المصمم ملفاً إلى طابعة لم يتحدث معها أبداً، ويمكن للطابعة إنتاج مخرجات صحيحة دون مكالمة هاتفية، ودون بريد إلكتروني بشأن خط مفقود، ودون صورة مرتبطة بقيت في الكمبيوتر المحمول للمصمم. تخدم كل قاعدة في المعيار هذا الهدف. يجب تضمين الخطوط لأنه لا يمكن افتراض أن RIP المتلقي يمتلكها. وتحظر المراجع الخارجية لأن الملف يجب أن يكون مكتملاً في حد ذاته. وتحظر الميزات التفاعلية لأن الحبر لا يحتوي على معالج للنقرات (onclick)
يتعرف مكون PDFium على ثلاث عائلات مطابقة ويبلغ عنها من خلال التعداد TPdfXConformance في نتيجة التحقق: وهي pxc1a لـ PDF/X-1a:2001 (معيار ISO 15930-1, خط الأساس الصارم لـ CMYK زائد الألوان الموضعية على أساس PDF 1.3/1.4)، و pxc3 لـ PDF/X-3:2002 (معيار ISO 15930-3، الذي يسمح بألوان RGB و Lab والألوان المدارة بـ ICC)، و pxc4 لـ PDF/X-4:2010 (معيار ISO 15930-7، الذي يسمح أخيراً بالشفافية الحية والطبقات على قاعدة PDF 1.6). يعود الملف الذي لا يحمل أي تعريف لـ PDF/X على الإطلاق كـ pxcNone، وهو في حد ذاته إجابة مفيدة: فالمستند لم يدع أبداً أنه جاهز للطباعة، وكل شيء آخر يبلغ عنه المدقق يوضح ما سيتطلبه الأمر للوصول إلى هناك
الخيارات المحظورة تبدو منطقية بمجرد أن تفكر كبائع RIP. حيث يحظر /LZWDecode في كل متغير لـ PDF/X بحيث لا يعتمد المستهلك المتوافق أبداً على مرشح (filter) له تاريخ من التوافق والترخيص؛ وتقوم خوارزمية Flate بنفس المهمة دون هذه الأعباء. ويحظر كل من JavaScript وحقول AcroForm وقواميس الإجراءات الإضافية /AA لأن ملف الطباعة يجب أن يكون وصفاً ثابتاً للعلامات على الورق — وأي شيء يمكن أن يغير المظهر في وقت الفتح يكسر الضمان بأن ما تم إثباته هو ما يطبع. وتحظر عناصر OPI (واجهة ما قبل الطباعة المفتوحة) لأنها، حسب التصميم، مراجع لصور عالية الدقة مخزنة في مكان آخر، و"مكان آخر" هو بالضبط ما يحظره التبادل الأعمى
لماذا ترفض محلات الطباعة ملفات PDF الخالية من TrimBox?
إن TrimBox هو الصفحة المنتهية — وهو المستطيل الذي يتبقى بعد قطع المقصلة. بينما MediaBox، الذي تحتويه كل صفحة PDF، هو مجرد الورقة: ويشمل مساحة النزيف وعلامات القص وأهداف التسجيل وأشرطة الألوان. وتضع برامج الفرض الصفحات على ورقة الصحافة بواسطة TrimBoxes الخاصة بها؛ ودون وجود أحدها، يتعين على المشغل تخمين المكان الذي تنتهي فيه بطاقة عملك بالفعل، والتخمين الخاطئ يزيل النزيف أو يترك قطعة بيضاء على حافة واحدة. لهذا السبب يتطلب معيار ISO 15930 وجود TrimBox (أو ArtBox) في كل صفحة، ولهذا السبب تثير ValidatePdfX مشكلة pvxiMissingTrimBox عندما لا يتم العثور على مفتاح /TrimBox في أي صفحة من صفحات المستند
يجيب مفتاح /Trapped عن سؤال إنتاج مختلف. التجميع (Trapping) هو تقنية ما قبل الطباعة لتداخل الألوان المتجاورة قليلاً بحيث لا يفتح عدم تسجيل المطبوعات الدقيق فجوات بيضاء بينها. وتحتاج الطابعة إلى معرفة ما إذا كان هذا العمل قد تم بالفعل: حيث يؤدي تجميع ملف مجمع بالفعل إلى مضاعفة التداخلات، ويخاطر تخطي التجميع في ملف غير مجمع بحدوث فجوات مرئية. وبالتالي يتطلب PDF/X من قاموس المعلومات ذكر /Trapped /True أو /Trapped /False صراحة — ووجود مفتاح مفقود أو /Unknown يجبر إنساناً على فحص الملف، وهو بالضبط الحوار الذي كان الهدف من التبادل الأعمى إلغاءه. يعلم المكون هذا بـ pvxiTrappedNotSet
تشغيل التحقق من طبقتين باستخدام TPdf.ValidatePdfX
لا تأخذ دالة TPdf.ValidatePdfX أي وسيطات وتعيد سجل TPdfXValidationResult يضم ثلاثة أعضاء: Conformance (نوع PDF/X المكتشف)، و Issues (مجموعة Pascal لقيم TPdfXValidationIssue)، ومساعد IsCompliant. وخلف الكواليس، تقوم بتسلسل المستند المحمل إلى تدفق ذاكرة، وتشغيل فاحص مستوى البايت فوقه، ثم تمشي في نموذج كائن PDFium لفحص تضمين كل خط. تبدو بوابة التحقق المسبق بالحد الأدنى كما يلي:
uses PDFium, FPdfPdfx;
procedure CheckPrintReadiness(const FileName: string);
var
Pdf: TPdf;
Res: TPdfXValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := FileName;
Pdf.Active := True;
Res := Pdf.ValidatePdfX;
Writeln('Detected conformance: ',
Ord(Res.Conformance)); // pxc1a, pxc3, pxc4, pxcNone...
if Res.IsCompliant then
Writeln('PDF/X checks passed')
else
begin
if pvxiMissingTrimBox in Res.Issues then
Writeln('REJECT: no /TrimBox on the pages');
if pvxiTrappedNotSet in Res.Issues then
Writeln('REJECT: /Trapped missing or /Unknown');
if pvxiPdfiumFontNotEmbedded in Res.Issues then
Writeln('REJECT: a page uses a non-embedded font');
if pvxiLzwForbidden in Res.Issues then
Writeln('REJECT: LZWDecode filter present');
end;
finally
Pdf.Free;
end;
end;
ولأن Issues هي مجموعة Pascal عادية، يمكنك تقسيمها بالطريقة التي تتطلبها سير عملك — عامل المشكلات الهيكلية كرفض صارم، وعامل pvxiMissingTitle (وهي مستحسنة في المعيار وليست إلزامية) كتحذير، وقم بتسجيل الباقي. ويغذي نفس نوع السجل مولد تقارير المكون أيضاً, لذا إذا كنت تفضل إخراج مستند مقروء بشرياً بدلاً من التفرع بناءً على التعدادات، فإن النمط الوارد في بناء واجهة خط أوامر لتقرير الفحص المسبق الدفعي مع مكون PDFium ينطبق على PDF/X دون تغيير
ما تلتقطه طبقة مستوى البايت — وما تفقده
إن طبقة مستوى البايت هي عبارة عن مسح للرموز عبر البايتات الهيكلية للمستند مع إفراغ أجسام التدفق، وبالتالي فإن ملف JPEG الذي يحتوي بالصدفة على نمط البايت /JavaScript لا يمكنه إثارة إيجاب كاذب. وفوق فحوصات العلامات (XMP pdfxid:GTS_PDFXVersion، و OutputIntent مع ملف تعريف ICC مضمن، و /ID للمقطورة، وحظر التشفير)، يضيف مرور المحتوى ثمانية فحوصات، لكل منها قيمة التعداد الخاصة به:
pvxiLzwForbidden— يظهر مرشح/LZWDecodeفي أي مكان بالملف (محظور في كل متغيرات PDF/X)pvxiJavaScriptForbidden— يوجد إجراء أو شجرة اسم لـ/JavaScriptpvxiFormFieldsForbidden— يوجد قاموس/AcroFormأو إدخال/XFApvxiAdditionalActions— يوجد قاموس إجراءات إضافية/AApvxiEmbeddedFilesForbidden— يوجد/EmbeddedFilesأو تعليق توضيحي لـ/FileAttachmentpvxiOpiForbidden— يشير إدخال/OPIأو/Alternatesإلى محتوى صورة قابل للاستبدالpvxiMissingTrimBox— لم يتم العثور على/TrimBoxفي أي صفحةpvxiTrappedNotSet— مفتاح/Trappedغائب أو تم تعيينه إلى/Unknown
مسح البايت سريع ولا يحتاج إلى محرك تقديم، ولكن لديه نقطة عمياء متأصلة مع الخطوط: فعند هذا المستوى لا يمكن للمفتش إلا تطبيق الكشف الإرشادي الخشن — فهو يعلم المستند عندما لا يجد برنامج خط مضمن على الإطلاق. الملف الذي يحتوي على تسعة خطوط مضمنة وخط نظام واحد متسلل يبدو جيداً لمسح البايت. تلك الفجوة الفردية هي سبب وجود الطبقة الثانية
تضمين كل خط من خلال نموذج كائن PDFium
تجيب طبقة نموذج كائن مكون PDFium على سؤال الخط بدقة. فبعد مرور مستوى البايت، تقوم TPdf.ValidatePdfX بتكرار كل صفحة، وتسأل FPDFPage_CountObjects عن قائمة الكائنات، وتحل لكل كائن نصي مقبض الخط عبر FPDFTextObj_GetFont وتستعلم عن FPDFFont_GetIsEmbedded. خط واحد غير مضمن في أي مكان بالمستند يضيف pvxiPdfiumFontNotEmbedded إلى مجموعة المشكلات. يختصر هذا التنقل عند مستويين — فهو يتوقف عن مسح الكائنات في صفحة، ويتوقف عن تحميل المزيد من الصفحات، لحظة تأكيد المشكلة — لذا ففي كتالوج ينتهك القواعد ويتكون من 300 صفحة، غالباً ما يصل الحكم بعد الصفحة الأولى
هناك ملاحظتان للحدود تستحقان المعرفة. أولاً، تحتاج هذه الطبقة إلى تحميل مكتبة PDFium وتتطلب بناءً يصدر دالة FPDFFont_GetIsEmbedded؛ وعندما يكون التصدير غائباً، يتم تخطي الفحص بدلاً من الفشل، وبالتالي لا ينتج ملف DLL الأقدم رفضاً وهمياً. ثانياً، يجيب الفحص بـ "مضمن أم لا" ولا شيء غير ذلك — فهو لا يميز التضمين الكامل عن التقسيم الفرعي (subsetting)، ولا يفحص تغطية الصورة الرمزية (glyph coverage). وعندما يفشل ملف وتحتاج إلى معرفة أي خط في أي صفحة، فإن تقنيات السرد الواردة في تحليل خصائص خطوط PDF باستخدام PDFium في Delphi تبدأ من حيث ينتهي مدقق المدقق البولياني تماماً
التحقق من صحة التدفقات دون تحميل مستند — أو مكتبة DLL
يتم كشف فاحص مستوى البايت أيضاً كدالة مستقلة، وهي ValidatePdfXCompliance(Source: TStream) في وحدة FPdfPdfx، وهي عبارة عن Object Pascal نقي دون أي تبعية لملف PDFium DLL. وهذا يجعلها قابلة للنشر في الأماكن التي لا يرحب فيها بمحرك التقديم: مثل بوابة تحميل خفيفة الوزن على خادم ويب، أو مهمة CI تفحص الأعمال الفنية المنشأة، أو خدمة Lazarus على نظام أساسي تفضل عدم شحن ثنائيات أصلية إليه. قم بتعذيتها بأي تدفق قابل للبحث (seekable stream):
uses Classes, FPdfPdfx;
function QuickPdfXGate(const FileName: string): Boolean;
var
Fs: TFileStream;
Res: TPdfXValidationResult;
begin
Fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfXCompliance(Fs);
Result := Res.IsCompliant and (Res.Conformance <> pxcNone);
finally
Fs.Free;
end;
end;
المقايضة صريحة: حيث يقوم المسار المستقل بتشغيل فحوصات العلامات والفحوصات الثمانية للمحتوى، ولكن ليس طبقة PDFium الخاصة بالخط، لذا يتراجع حكم الخط الخاص به إلى المنهج الإرشادي الخشن. وتستخدم البنية المعقولة ValidatePdfXCompliance كبوابة أولى رخيصة وتحجز دالة TPdf.ValidatePdfX الكاملة للملفات التي تجتازها
أين ينتهي هذا المدقق وأين يبدأ الفحص المسبق الكامل للرحلة
الصدق مهم في أدوات الفحص المسبق، لذا إليك الحدود. تتحقق ValidatePdfX من علامات التعريف، والمحظورات الهيكلية، ومفاتيح هندسة الصفحة، وإعلان Trapped، وتضمين الخطوط وصولاً إلى كائنات النص الفردية. وهي لا تقيس تغطية الحبر الكلية، أو تتحقق من أن كل مساحة لون قانونية للمتغير المطالب به (مثل قاعدة CMYK فقط لـ X-1a)، أو تفحص دقة الصورة مقابل شاشة الخطوط، أو تقيم سلوك الطباعة الفوقية وتسطيح الشفافية — حيث تحتاج هذه إلى محرك فحص مسبق مدار بالألوان، وتوصي وثائق الوحدة نفسها بإقرانها بمحرك نهائي للحصول على الشهادة النهائية. ما يمنحك إياه الفحص ثنائي الطبقات هو 80% من حالات الرفض الهيكلية والتي يمكن كشفها مبكراً، ويتم التقاطها في أجزاء من الثانية داخل كود Delphi الخاص بك بدلاً من بريد إلكتروني تتلقاه غداً من الطابعة
تشحن كلتا طبقتا التحقق، وواجهات برمجة تطبيقات حقن علامات PDF/X لإنتاج مخرجات متوافقة، ومدققات PDF/A و PDF/UA و PDF/E و PDF/VT التي تشترك في نفس البنية في مكون PDFium لـ Delphi و C++Builder — مكون واحد، من التقديم وحتى حراسة ما قبل الطباعة