تعيد دار ما قبل الطباعة المهمة: حبر Spot نفسه فُصل على لوحين. يمنع HotPDF ذلك وقت التأليف بكتابة NChannel بصيغة DeviceN خماسية العناصر وفق ISO 32000-2، وبالإبقاء على فضاء بديل قانوني واحد وتحويل صبغة واحد لكل اسم حبر موضعي على امتداد المستند، رافضًا التعريف الثاني المتعارض بدل إصداره
NChannel ليس اسم عائلة فضاء لوني
أول ما ينبغي شطبه من الذهن هو الاسم نفسه. NChannel ليست عائلة فضاء لوني كما أن Separation وDeviceN عائلتان. تصفها ISO 32000-2 §8.6.6.5 بأنها نمط فرعي من DeviceN، لذا يُكتب فضاء NChannel المطابق كمصفوفة خماسية العناصر [/DeviceN names alternateSpace tintTransform attributes]، ويحمل قاموس السمات /Subtype /NChannel. لا توجد مصفوفة [/NChannel ...] في المواصفة. إن سبق أن بنيت واحدة يدويًا ورأيت RIP يتجاهلها، فهذا هو السبب
أخطأ HotPDF في هذا مرة ثم صححه، وهو ما يستحق أن يُقال صراحة لأنه يحدد سلوك المكوّن اليوم. كانت إصدارات HotPDF الأقدم تُصدر صيغة اسم العائلة. أما THotPDF.RegisterNChannelColorSpace اليوم فلا تُصدر إلا صيغة DeviceN مع السمات القياسية، ولأن نمط NChannel الفرعي ظهر في PDF 1.6، فإن نقطة دخول المنتِج تتحكم عبر RequirePDFVersion(pdf16, ...) وترفض ببساطة على الأهداف الأقدم. جانب التصيير أكثر تسامحًا من الكاتب عمدًا: ما تزال HPDFResolveColorSpace تقبل التوكن القديم /NChannel كعائلة DeviceN كي تستمر ملفات الكاتب القديم في التصيير، لكن أي شيء يكتبه HotPDF خرجًا يستخدم الترميز القياسي. التسامح في الإدخال والصرامة في الإخراج هو اللاتماثل الصحيح هنا، لأن قارئك عليه أن يتعامل مع ملفات لم ينشئها بينما لا عذر لكاتبك
لماذا ينتهي اسم حبر موضعي واحد على لوحين؟
لأن اسم الملوّن الموضعي هو هوية لوح على مستوى المستند كله، لا وسيط محلي. استدعاءان يسمّيان كلاهما Orange لكنهما يسلّمان فضاءً بديلًا مختلفًا، أو الفضاء البديل نفسه مع تحويل صبغة مختلف، يصفان حبرين مختلفين يتصادف أن يتشاركا تسمية. ولا تملك RIP تبني الفصائل اللونية وسيلة للتوفيق بين ذلك، فتفعل الشيء الأمين الوحيد وتعطيك لوحين. لذلك يحافظ HotPDF على بصمة قانونية لكل اسم ملوّن داخل المستند. تركّب RegisterSpotColorantDefinition تلك البصمة من الفضاء اللوني البديل وشكل دالة الصبغة، ويمرّ عبرها كل من RegisterSeparation وRegisterSeparationFunc وRegisterSeparationLUT وتعريف Spot في NChannel. حين يختلف تعريف ثانٍ، يُطلق الاستدعاء استثناءً بدل أن يسجّل صيغة ثانية بصمت، والرسالة محددة عمدًا بشأن نمط الفشل، لأن البديل هو اكتشاف الأمر على بروفة لوح بعد ثلاثة أسابيع
// سُجِّل Orange سابقًا مقابل DeviceCMYK بتحويل
// صبغة 0 / 0.55 / 1 / 0 عند الصبغة الكاملة.
Conflicting := Pdf.RegisterExponentialFunction(
Domain1, NoInk, OtherOrangeCMYK, 1, []);
try
Pdf.RegisterSeparationFunc('Orange', 'DeviceCMYK', Conflicting);
except
on E: Exception do
// 'Spot colourant "Orange" has inconsistent alternate colour
// space or tint definition in this document'
LogPrepressWarning(E.Message);
end;
تقسيم الأسماء الرئيسية إلى عملية وموضعية
على NChannel المكتمل أن يُحسب كل اسم من أسماء ملوّناته الرئيسية مرة واحدة بالضبط، إما كمكوّن عملية أو كملوّن موضعي. يأخذ الحمل المتقدم لـ RegisterNChannelColorSpace الأسماء الرئيسية ColorantNames، وأسماء ملوّنات العملية ProcessColorantNames، والفضاء البديل، وتحويل الصبغة الإجمالي، ومصفوفة من سجلات THPDFNChannelSpotColorant، وترتيب طباعة اختياريًا. يحمل كل سجل موضعي اسمه الخاص، وتحويل صبغة Separation أحادي المدخل خاصًا به، وصلاحية اختيارية، ودالة زيادة نقطة اختيارية. على تحويل الصبغة الإجمالي أن يربط N مدخلًا بعدد مكوّنات الفضاء البديل؛ وعلى كل صبغة موضعية أن تربط مدخلًا واحدًا بذلك العدد نفسه
const
Colorants: array[0..4] of AnsiString =
('Cyan', 'Magenta', 'Yellow', 'Black', 'Orange');
ProcessNames: array[0..3] of AnsiString =
('Cyan', 'Magenta', 'Yellow', 'Black');
Order: array[0..4] of AnsiString =
('Yellow', 'Magenta', 'Cyan', 'Orange', 'Black');
Domain5: array[0..9] of Single = (0, 1, 0, 1, 0, 1, 0, 1, 0, 1);
Range4: array[0..7] of Single = (0, 1, 0, 1, 0, 1, 0, 1);
Domain1: array[0..1] of Single = (0, 1);
NoInk: array[0..3] of Single = (0, 0, 0, 0);
OrangeCMYK: array[0..3] of Single = (0, 0.55, 1, 0);
GainC0: array[0..0] of Single = (0);
GainC1: array[0..0] of Single = (1);
var
Pdf: THotPDF;
Spots: array[0..0] of THPDFNChannelSpotColorant;
CSName: AnsiString;
begin
Pdf.Version := pdf20;
Pdf.BeginDoc;
Spots[0].Name := 'Orange';
Spots[0].TintTransform := Pdf.RegisterExponentialFunction(
Domain1, NoInk, OrangeCMYK, 1, []);
Spots[0].HasSolidity := True;
Spots[0].Solidity := 0.82;
Spots[0].DotGainFunction := Pdf.RegisterExponentialFunction(
Domain1, GainC0, GainC1, 1, []);
CSName := Pdf.RegisterNChannelColorSpace(Colorants, ProcessNames,
'DeviceCMYK',
Pdf.RegisterPostScriptFunction(Domain5, Range4,
'{ pop pop pop pop pop 0 0 0 0 }'),
Spots, Order);
من ذلك الاستدعاء يُصدر HotPDF قاموس السمات الذي تطلبه المواصفة: /Subtype /NChannel، وقاموس /Process يكون /ColorSpace فيه هو فضاء العملية ويسرد /Components أسماء العملية بترتيب مكوّنات ذلك الفضاء، وقاموس /Colorants يحمل مصفوفة حقيقية [/Separation name alternate tintfn] لكل حبر موضعي، وقاموس /MixingHints يحمل /Solidities و/PrintingOrder و/DotGain حين تزوّدها بها. اسم المورد المُعاد يذهب إلى SetFillColorSpace أو SetStrokeColorSpace تمامًا كالفضاءات الأبسط التي يغطيها مقال عرض ألوان Spot بنمطي Separation و DeviceN
ما الذي يرفضه فحص الاتساق فعلًا؟
يرفض عدم الترابط البنيوي داخل الفضاء، ويفعل ذلك قبل كتابة أي كائن. يجب أن تكون أسماء الملوّنات فريدة وألا تكون فارغة أو All أو None. يجب أن تغطي تعريفات العملية والموضعية معًا الأسماء الرئيسية بالضبط، بلا ملوّن يظهر في الدورين وبلا ملوّن يُترك بلا تعريف. وحين يكون الفضاء البديل DeviceCMYK، يجب أن تكون مكوّنات العملية Cyan وMagenta وYellow وBlack بهذا الترتيب، ويجب أن يطابق عدد أسماء العملية عدد مكوّنات البديل. كل تحويل صبغة ودالة زيادة نقطة يجب أن يكون كائن دالة غير مباشر بعدد مدخلات ومخرجات صحيح. والصلاحية يجب أن تكون قيمة منتهية ضمن 0..1. وترتيب الطباعة يجب أن يكون فارغًا أو تبديلًا كاملًا للأسماء الرئيسية، لا قائمة جزئية أبدًا. أما ما لا يفعله فهو الحكم على اللون: لا شيء هنا يتحقق من أن تحويل صبغة Orange لديك يشبه فعلًا الحبر في العلبة، أو أن تركيب CMYK له بديل معقول، أو أن الصلاحية التي زوّدتها تطابق السلوك المقاس على الخامة. تلك مسائل مطبعة وقياس، ولا شأن للمكوّن بالإجابة عنها. والحمل الأبسط الخاص بالعملية فقط أشد صرامة بالتصميم: ينتج NChannel للعملية فقط ويرفض عمدًا قبول أسماء Spot، لأن كتابة حبر موضعي في مصفوفة الأسماء بلا مدخل /Colorants مطابق ستنتج ملفًا غير مطابق بنيويًا، واختلاق تعريف افتراضي سيكون أسوأ من الفشل
نوايا إخراج PDF/X-6n يجب أن تغطي كل حبر موضعي مسجَّل
ملف PDF/X-6n متعدد الملوّنات يعلن ملوّناته مرتين، ويجب أن تتوافق الإعلانان. تكتب AddPDFX6ExternalOutputIntent مرجع ملف تعريف ICC الخارجي مع ColorantTable خاصته، وقبل ذلك تجتاز ValidateRegisteredSpotOutputColorants كل حبر موضعي سجّله المستند وتطلق استثناءً إن غاب واحد عن الجدول. يعمل الفحص في الاتجاهين: بمجرد أن تنشر نية إخراج قائمة ملوّناتها، يُرفض أيضًا أي تسجيل Spot لاحق لاسم خارج تلك القائمة. وتضيف AddPDFX6ExternalOutputIntentSpotData البيانات الوصفية لكل حبر فوق ذلك، وتفرض قواعدها الخاصة، وعلى الأخص أن يحمل الملوّن إما قيمة صلابة أو بيانات طيفية CxF/X-4، لا كليهما أبدًا. هذا هو سطح المطابقة نفسه الذي تناقشه المقالة عن التحقق من PDF/A و PDF/X و PDF/UA
Spectral := TMemoryStream.Create;
try
LoadCxFForInk('Orange', Spectral); // حمولة ISO 17972-4
Pdf.AddPDFX6ExternalOutputIntentSpotData(
'ECG-5', 'Five-colour output condition',
'https://profiles.example.com/ecg-5.icc', '5CLR',
Colorants,
'00112233445566778899AABBCCDDEEFF', #4#3#0#0,
['Cyan'], [0.70], // صلابة ملوّن واحد
Order,
['Orange'], [Spectral]); // بيانات طيفية لملوّن آخر
finally
Spectral.Free;
end;
ثمتان تفصيلتان تشغيليتان يسهل إغفالهما. السجل الذي يسند كل هذا خاص بكل مستند ويُصفَّر عند حدود المستندات، فتحميل ملف جديد في نفس مثيل THotPDF لا يرث هويات أحبار المستند السابق؛ ذلك العزل هو بيت القصيد، لأن بصمة مسرَّبة قد ترفض عملًا سليمًا تمامًا في المهمة التالية. ولجانب ملف التعريف حدود صلبة خاصة به: نية الإخراج الخارجية تتطلب هدف PDF 2.0، وعنوان URL مطلقًا لملف التعريف عبر HTTP أو HTTPS، وتوقيع فضاء لوني ICC رباعي البايت، وبالنسبة لـ PDF/X-6n بين 2 و15 ملوّنًا مع توقيع مطابق من 2CLR إلى FCLR
حيث يتوقف الفحص
معالجة CxF/X-4 هي الجزء الذي ينبغي الصدق بشأنه. يطبّق HotPDF فحوص سلامة بنيوية محدودة على التدفق الطيفي ويؤكد أن هوية الحبر داخله تطابق الملوّن الذي سمّيته. يحدّ حجم الحمولة، ويرفض البايتات الفارغة المضمّنة، ويرفض أي تدفق يحوي تعريف DOCTYPE أو ENTITY، ويشترط جذر CxF معروفًا، ويشترط عنصر SpotInkCharacterisation واحدًا بالضبط يحمل SpotInkName واحدًا بالضبط يساوي اسم الملوّن لديك. تلك بوابة ضد الإدخال المشوّه والعدائي، لا مدقّق مخطط. إنها ليست تطبيقًا كاملًا لـ ISO 17972-4، ولا تتحقق من قياساتك الطيفية، ولا تدقّق بأثر رجعي رسوم كائنات اعتباطية لطرف ثالث قائمة سلفًا أو جداول الملوّنات الداخلية في ملف تعريف ICC مضمّن. إن كان سير عملك يعتمد على مطابقة CxF كاملة، فتحقق من الملف بأداة مخصصة قبل تسليمه إلى المكوّن
ثمة قيد مجاور يلدغ من لم يتوقع ملاقاته أبدًا. قناع النعومة من نمط اللمعان لا يستطيع استخدام Separation أو DeviceN أو NChannel كفضاء /CS لمجموعة شفافيته؛ فضاء مزج المجموعة يجب أن يكون فضاء جهاز أو فضاء قائمًا على CIE، لذا يُحلّ طلاء Spot داخل المجموعة عبر تحويل صبغته إلى الفضاء البديل قبل حساب اللمعان. تبني RegisterLuminositySoftMaskState مجموعة DeviceGray تحديدًا كي لا يسوء هذا بالصدفة. الأثر العملي هو أن تصميمًا كثيف الأحبار الموضعية مُقنَّعًا هكذا يُقيَّم عبر بديله CMYK لا عبر حبره، وهو ما يهم حين تقارنه ببروفة مفصولة كما هو موضح في ملاحظات بروفات التراكب وأجهزة التصيير
لا يلغي شيء من هذا الحاجة إلى بروفة لوح، لكنه ينقل فئة كاملة من رفوض ما قبل الطباعة من المطبعة إلى مرحلة البناء. واجهات NChannel و Separation ونوايا إخراج PDF/X-6n الموصوفة هنا تأتي في مكوّن HotPDF القياسي لـ Delphi لكل من Delphi و C++Builder، حيث يوثّق المرجع تخطيطات السجلات الكاملة والشروط الدقيقة التي تفشل عندها كل استدعاء بإغلاق