الحرف المفقود في PDF ليس خطأ. يطلب المنتج محرفا لا تستطيع الخط المختار مطابقته، فيعيد الخط فهرس المحرف صفرا، ويكون الملف الناتج صالحا بنيويا، يفتح في كل مكان، ويعرض صندوقا فارغا مكان اسم أو مبلغ. ولا أحد في مسار التوليد يكتشف ذلك. المستلم يكتشفه. يسد HotPDF تلك الحلقة بـ TrackUnresolvedGlyphs: شغّلها فيسجل مسار رسم النص كل نقطة كود تنتهي فيها مطابقة المحرف إلى الفهرس صفر، مطلقا OnUnresolvedGlyph مرة واحدة لكل نتيجة فريدة مع نقطة الكود والخط الذي فشل عنده والنظام الكتابي الذي تنتمي إليه واقتراح خطوط تغطيها
الكشف نصف الجواب. والنصف الآخر هو SetFontFallbackChain، التي تسجل قائمة مرتبة من الخطوط لكل نظام كتابي، فتحل الحالات الشائعة نفسها ولا يصل إلى معالجك إلا الفجوات الحقيقية. ومعا يحولان صنفا من العيوب كان يبلّغ عنه العملاء إلى فحص وقت البناء
لماذا لا يثير الحرف المفقود شيئا؟
لأن ISO 32000 لا يفرض على المنتج التزاما بالتحقق من التغطية، وفهرس المحرف صفر محرف مشروع. إنه .notdef، الذي يختار مصمم الخط محيطه: عادة مستطيل فارغ أو مفرغ، وأحيانا لا شيء إطلاقا. والعارض الذي يرسمه يتصرف تصرفا صائبا. وقد يعيد استخراج النص المحارف الصحيحة أيضا، لأن مطابقة /ToUnicode تكتب من النص المصدر لا من المحيطات، فيجتاز فحص ذهاب وإياب آلي بكل سرور مستندا نصه المرئي فيه ثقوب
النتيجة العملية أن التغطية يجب فحصها لحظة الرسم، عندما ما تزال المكتبة تعرف أي نقطة كود طُلبت وأي محرف قدمه الخط فعلا. وبعدها تضيع المعلومة
على الكاشف مراقبة حالة المجموعة الجزئية لا سياق الجهاز
هذا هو الموضع الذي أخطأت فيه أول معالجة، والسبب يستحق الفهم لأنه ينطبق على أي فحص تغطية يضاف إلى مسار نصي. تملك HotPDF مسارين نصيين. يصدر أحدهما عبر خط TrueType يونيكودي مسجل بخريطة محارف في الذاكرة بنيت وقت التسجيل. والآخر مسار GDI قديم ينشئ سياق جهاز ومقبض خط جديدين لكل تشغيلة محارف
الحكم على التغطية من مسار GDI ميؤوس منه. مطابقته ليست المطابقة التي تنتهي في مسار المحتوى الصادر، والاثنتان غير متزامنتين، فيفيد كاشف يقرأ نتائج GDI بأن المدى الطباعي من ASCII كله غير محلول. والجواب الموثوق يعيش في الخط المسجل: خريطة المحارف التي يحللها RegisterUnicodeTTF، المستفصَل عنها عبر GetUnicodeGlyphForCodepoint. لذا يحصن الكاشف على حالة جاهزية المجموعة الجزئية، لا على أي شرط GDI، ولا يعمل ببساطة على مستندات لم تسجل خطا يونيكوديا قط، وهذا صحيح لأن تلك المستندات محدودة بالترميزات القياسية على أي حال
فخ ثان يجاوره. اسم عائلة الخط في GDI واسم PostScript المستخرج من ملف الخط الثنائي وقت التسجيل سلسلتان مختلفتان، وليس اختلافا يمكنك تطبيعه: عائلة تدعى Arial Unicode MS تحمل اسم PostScript هو ArialMT. أي تحصين كُتب بصيغة «هل الخط المختار حاليا هو الخط الذي سجلناه»، مقارنا بالاسم، هو كود ميت لا يشتغل أبدا. احصن على الحالة، لا على أسماء الخطوط أبدا
لا تختبر كاشف محارف برموز تعبيرية
حالة الاختبار البديهية وجه مبتسم، وسوف يقنعك بأن الكاشف معطل. نقاط كود الرموز التعبيرية الشائعة في المستويات الفلكية تحل عبر مسار توليف للاستخدام الخاص يطابقها بفهرس محرف مباشرة، فلا تصل أبدا إلى فرع التغطية العام. الكاشف يتصرف صائبا والاختبار يقيس المسار الخطأ
استخدم نقطة كود غير مخصصة بدلا منها. U+0378 غير مخصص نهائيا في يونيكود، فلا يستطيع أي خط مطابقته بشكل مشروع، وهو يجرب بالضبط الفرع الذي تريد التحقق منه. هذا التمييز بين «الميزة معطلة» و«الاختبار انتقى مدخلا يتجاوز الميزة» يكلف ساعات حقيقية، ونقاط الكود غير المخصصة أرخص طريق لتجنب ذلك
type
TCoverageAudit = class
private
FFindings: TStringList;
public
procedure Handle(Sender: TObject;
const Info: THPDFUnresolvedGlyphInfo);
property Findings: TStringList read FFindings;
end;
procedure TCoverageAudit.Handle(Sender: TObject;
const Info: THPDFUnresolvedGlyphInfo);
begin
// يشتغل مرة واحدة لكل نقطة كود فريدة، لا مرة لكل ورود
FFindings.Add(Format('U+%.4X missing in %s (script %d), try: %s',
[Info.CodePoint, String(Info.FontName), Ord(Info.Script),
String(Info.SuggestedFonts)]));
end;
// توصيله في مهمة توليد
Pdf := THotPDF.Create(nil);
try
Pdf.TrackUnresolvedGlyphs := True;
Pdf.OnUnresolvedGlyph := Audit.Handle;
Pdf.RegisterUnicodeTTF('C:\Windows\Fonts\arial.ttf');
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 720, 0, CustomerName);
Pdf.EndDoc;
if Audit.Findings.Count > 0 then
// أجهض المهمة بدل شحن صفحة عليها صناديق
raise Exception.Create(Audit.Findings.Text);
finally
Pdf.Free;
end;
سلاسل البدائل لكل نظام كتابي لا لكل خط
سبب حصر البدائل بحسب النظام الكتابي لا بحسب الخط المصدر أن فجوات التغطية تتجمع بحسب نظام الكتابة. خط نص لاتيني ينقصه الديفاناغاري والثاي والهان والرموز التعبيرية، كلها دفعة واحدة، والبديل لكل منها خط مختلف. تصريح سلسلة واحدة لكل نظام كتابي يصف إذن النشر الحقيقي: خط لاتيني واحد لمتن النص، وخط CJK واحد، وخط رموز تعبيرية واحد، وخط شامل
// يغطي THPDFFontScript الأنظمة hfsCommon وhfsLatin وhfsGreek وhfsCyrillic
// وhfsHebrew وhfsArabic وhfsIndic وhfsSoutheastAsian وhfsCJK وhfsKana
// وhfsHangul وhfsEmoji وhfsOther
Pdf.SetFontFallbackChain(hfsCJK,
['Microsoft YaHei', 'SimSun', 'Yu Gothic']);
Pdf.SetFontFallbackChain(hfsArabic, ['Segoe UI', 'Arial']);
Pdf.SetFontFallbackChain(hfsEmoji, ['Segoe UI Emoji']);
Pdf.SetFontFallbackChain(hfsOther, ['Arial Unicode MS']);
البدائل والكشف متكاملان لا بديلان. السلاسل تعالج التغطية التي توقعتها؛ والكاشف يفيد عن التغطية التي لم توقعها، وهي على نظام يعالج بيانات عملاء اعتباطية النصف المثير. ولاحظ أن استبدال خط يغير المقاييس، ففقرة سقطت إلى بديل قد يعاد سكبها؛ فإن كان التخطيط مهما فسلوك الإغلاق والتجزئة الجزئية للخط المستبدل يستحق القراءة في مقال إغلاق مجموعة الخط الجزئية، والأنظمة التي تحتاج إعادة ترتيب أو وصل تعالجها مرحلة التشكيل الموصوفة في تشكيل النص للأنظمة المعقدة
كيف تضيف سلوكا لاحقا دون المخاطرة بالمسار القائم
أضاف الإصدار نفسه بديلا لجدول kern القديم لتباعد الأزواج، وطريقة حصره نمط يستحق المحاكاة. بدل إضافة نقطة قرار جديدة إلى منطق التقنين، علّق البديل على فرع الخروج المبكر القائم أصلا للخطوط بلا جدول GPOS. الخط الحديث بجدول GPOS لا يصل إليه أبدا، فسلوكه غير متغير بالبناء لا بالاختبار. والمسارات التي لا تسجل خطا يونيكوديا تنتج إزاحتين صفريتين، فهي غير متغيرة هي أيضا
هذا هو الشكل العام لإضافة منخفضة المخاطر في مكتبة تصيير ناضجة: ابحث عن الفرع الذي لا ينتج شيئا حاليا وضع السلوك الجديد فيه. يحول ذلك «نعتقد أن هذا لم يرتد شيئا» إلى «هذا لا يمكن أن يكون ارتد شيئا»، وهو ما هو أفضل بكثير قولاه عن محرك نص تمر عبره فواتير الآخرين
اجعله تحصينا لا سجلا
نتائج التغطية لا تفيد إلا إذا فشل شيء بسببها. في خدمة توليد مستندات الترتيب المثمر إبقاء التتبع مشغلا في مهمة الانحدار الليلية مقابل مدونة أسماء عملاء وعناوين وأوصاف منتجات حقيقية، وإجهاض المهمة عند أي نتيجة. ولأن الحد يشتغل مرة لكل نقطة كود فريدة لا مرة لكل ورود، يبقى الخرج صغيرا بما يكفي للقراءة حتى عندما ينقص نظام كتابي كامل
في الإنتاج يستخدم المعالج نفسه أفضل استخداما كتليمترية: سجل نقطة الكود والخط، واستمر في تقديم المستند، ودع المجموع يخبرك أي نظام كتابي تضيف بعد ذلك إلى مجموعة خطوط النشر. سلوك تصيير الخطوط المضمنة والمستبدلة مشمول أكثر في تصيير محارف الخطوط المضمنة، وقائمة الخصائص الكاملة بما فيها TrackUnresolvedGlyphs موثقة في صفحة منتج HotPDF Delphi PDF component