تُدفِّق PDFlibPas مقطعاً نصياً محتفظاً به عبر عمود واحد إلى 64 عموداً متساوية العرض باستخدام DrawTextFlowColumns، وتفصل أسطره بفصل مقطعي محدود واعٍ باللغة بمجرد استدعاء SetTextFlowLanguage وSetTextFlowHyphenation. تدعم المكتبة تسع لغات، ويمكن أن تُورَّث اللغة من قيمة /Lang في فهرس المستند بدلاً من ضبطها لكل تدفق على حدة
توجد كلتا الميزتين للسبب نفسه: العمود الضيق هو المكان الذي يتوقف فيه فصل الأسطر الساذج عن الظهور كصف طباعي ويبدأ بالظهور كتقرير أخطاء
لماذا ينهار النص المُبرَّر في الأعمدة الضيقة؟
لأن التبرير يوزّع المساحة المتبقية على الفراغات بين الكلمات في السطر، وتعتمد كمية المتبقي على ما يتسع له السطر. في قياس عريض يكون المتبقي صغيراً ولا تلاحظه العين أبداً. قسّم العرض إلى النصف وستجد أن كلمة طويلة واحدة لا تتسع تُدفع إلى السطر التالي، تاركةً ما قبلها ليمتص كل تلك المساحة. ثلاثة أسطر متتالية من هذا النوع تُنتج قنوات بيضاء عمودية يسميها المصممون الطباعيون الأنهار (rivers)، ويختبرها القراء كنص يصعب متابعته دون معرفة السبب
يعالج الفصل المقطعي السبب بدلاً من العرَض من خلال السماح بكسر داخل الكلمة. الكلمات المركّبة في الألمانية والهولندية تجعل هذا الأمر غير قابل للتفاوض: اسم مكوَّن من 24 حرفاً في عمود عرضه 60 ملم ليس له مخرج جيد دون نقطة كسر. الإنجليزية تتحمل غياب هذه الميزة بشكل أفضل، وهذا ما يفسر لماذا تشحن المنتجات المصممة أولاً للإنجليزية غالباً كود تخطيط ينهار في أول مرة يشغّله عميل ألماني
أي اللغات، ومن أين تأتي اللغة؟
يغطي الفصل المقطعي الإنجليزية والألمانية والهولندية والفرنسية والإسبانية والإيطالية والبرتغالية والروسية والتركية. اضبطها صراحةً لكل تدفق عبر SetTextFlowLanguage، أو دعها تُورَّث من إدخال /Lang في فهرس المستند، وهي القيمة التي يحملها بالفعل أي مستند موسوم ويمكن الوصول إليه
هذا التوارث يستحق الاستخدام بدلاً من تجاوزه. المستند الذي يعلن لغته في الفهرس يخبر قارئات الشاشة ومفهرسات البحث والفصل المقطعي بالحقيقة نفسها من مكان واحد، والمكان الواحد هو حيث يجب أن تعيش الحقيقة. إذا كنت تنتج بالفعل مخرجات موسومة كما هو موضح في الوسم التلقائي لملفات PDF التي يمكن الوصول إليها، فإن إدخال اللغة يكون مضبوطاً بالفعل ويمكن للتدفق أن يتبعه ببساطة
var
Lib: TPDFlib;
Flow, Drawn: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1);
Lib.AddTrueTypeFont('Georgia', 1);
Lib.SetTextSize(10.5);
Flow := Lib.NewTextFlow(ArticleBody);
try
Lib.SetTextFlowLanguage(Flow, 'de');
// تفعيل، 3 أحرف على الأقل قبل الكسر، و3 بعده
Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);
Lib.SetTextFlowMinLines(Flow, 2); // لا تترك سطراً وحيداً معزولاً أبداً
repeat
// ثلاثة أعمدة عبر منطقة عرضها 480 نقطة، بفواصل 18 نقطة، متوازنة
Drawn := Lib.DrawTextFlowColumns(Flow, 72, 720, 480, 620, 3, 18, 1);
if (Drawn = 0) or (Lib.TextFlowFinished(Flow) = 1) then
Break;
Lib.NewPage;
until False;
finally
Lib.ReleaseTextFlow(Flow);
end;
Lib.SaveToFile('newsletter.pdf');
finally
Lib.Free;
end;
end;
MinPrefix وMinSuffix مسألة طباعية، لا مسألة تحقق
يضبط العددان الصحيحان بعد علامة التفعيل الحد الأدنى لعدد الأحرف التي يجب أن تبقى قبل الكسر وبعده. ثلاثة وثلاثة هو إعداد افتراضي محافظ تقبله معظم أدلة الأسلوب الداخلية. اثنان واثنان ينتج فرص كسر أكثر ونتائج أقبح بشكل ملحوظ، لأن جزءاً من حرفين متدلياً في نهاية سطر يُقرأ وكأنه خطأ إملائي
ارفع الحدود الدنيا عندما يكون حجم الخط كبيراً، حيث يكون كل جزء بارزاً بصرياً، وخفّضها فقط عندما يكون العمود ضيقاً حقاً وقررت أن القياس الضيق أهم من النتيجة النظيفة. هذا قرار متعلق بأسلوب الدار وليس قراراً تقنياً، وهذا بالضبط سبب كونه معاملاً بدلاً من ثابت
ماذا تعني «التوازن» هنا فعلياً؟
يغيّر المعامل Balance السلوك فقط في نهاية المقطع النصي. عند تفعيل التوازن، تُقصَّر الأعمدة إلى عدد أسطر متساوٍ تماماً عندما يتسع كل ما تبقى داخل المنطقة، وهذا ما يمنع الصفحة الأخيرة من إظهار عمودين كاملين وعمود ثالث يحتوي على سطر وحيد معزول. أما عندما لا يتسع المقطع النصي، فيحتفظ كل عمود بارتفاعه الكامل بحيث تحمل الصفحة أكبر قدر ممكن من النص ويستمر الباقي في الصفحة التالية
هذا التفاوت هو الإعداد الافتراضي الصحيح للمستندات المتصلة. التوازن في منتصف مقال متدفق سيهدر مساحة عمودية في كل صفحة من أجل تأثير تجميلي لا يراه أحد، لأن الأعمدة ممتلئة على أي حال. التوازن في النهاية هو حيث تلاحظ العين فعلاً، وهناك بالضبط يُطبَّق
كسر الأسطر يقيس كلمات كاملة
تقيس خوارزمية الكسر كلمات كاملة بدلاً من تجميع عروض الأحرف، وتحجز بحثاً محدوداً للرموز الكبيرة الحجم التي لا تتسع لسطر على الإطلاق، مثل رابط URL أو رقم قيد. هذا يبقي الحالة الشائعة سريعة والحالة المَرَضية محدودة، بدلاً من العكس
لا تُرسم الشرطات الاختيارية اللينة والشرطات التلقائية إلا عندما يكون الكسر الذي تحدده هو الكسر الذي يُختار فعلياً. قد يبدو هذا بديهياً، لكنه عيب كلاسيكي: التطبيق الساذج يكتب حرف الشرطة أثناء القياس، وإذا تحرك موضع الكسر تبقى الشرطة عالقة في منتصف السطر. لا شيء يبدو أكثر دلالة على محرك نصوص معطوب من شرطة شاردة داخل كلمة
var
Lib: TPDFlib;
Flow, Needed: Integer;
begin
// قرر التخطيط قبل رسم أي شيء
Flow := Lib.NewTextFlow(ArticleBody);
try
Lib.SetTextFlowLanguage(Flow, 'fr');
Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);
// عدد الأسطر التي يحتاجها باقي المقطع بعرض عمود واحد
Needed := Lib.MeasureTextFlow(Flow, 148);
if Needed > 3 * LinesPerColumn then
UseTwoPageSpread
else
UseSinglePage;
Lib.DrawTextFlowColumns(Flow, 72, 720, 480, 620, 3, 18, 1);
if Lib.TextFlowFinished(Flow) <> 1 then
CarryOver(Lib.GetTextFlowRemaining(Flow));
finally
Lib.ReleaseTextFlow(Flow);
end;
end;
حافظ على إعدادات الخط متطابقة عبر المربعات
قاعدة واحدة تحكم كل تخطيط قائم على التدفق، وتستحق أن تُذكر بصراحة: DrawTextFlow وDrawTextFlowColumns وMeasureTextFlow جميعها تكسر الأسطر باستخدام الخط المختار في لحظة استدعائها. غيّر الخط أو الحجم بين مربعين من التدفق نفسه، أو ابدأ صفحة جديدة دون إعادة اختيار خط، وسيكسر المربع الثاني بشكل مختلف عمّا قاسه المربع الأول
العرَض مزعج بالضبط لأنه يبدو متقطعاً: نص يتسع في الصفحة الأولى يفيض في الصفحة الثانية، أو عدد أسطر مقاس لا يتطابق مع ما تم رسمه. اختر الخط مرة واحدة قبل الحلقة، وأعد اختياره بعد كل NewPage، وسيتصرف التدفق كما هو متوقع. عندما تظهر نصوص كتابة مختلطة في المقطع نفسه، تنطبق المعالجة الموضحة في الخط الاحتياطي التلقائي لنصوص CJK والإيموجي على كل من القياس والرسم، بحيث تبقى العروض متسقة عبر تشغيلات الاحتياط أيضاً
بالنسبة لتخطيطات التقارير حيث يكون التدفق عنصراً واحداً بين رؤوس الصفحات وتذييلاتها والكتل المدفوعة بالبيانات، تتكامل أنماط التركيب الموضحة في محرك تقارير مجموعة البيانات بسلاسة مع تدفقات الأعمدة: قِس أولاً، ثم ضع العناصر الثابتة، ثم امنح التدفق أي منطقة متبقية
PDFlibPas هي مكتبة PDF لـ Delphi و C++Builder و Lazarus، ودورة حياة TextFlow الكاملة، من الإنشاء والرسم والقياس والفحص وإعادة الضبط والتحرير، متاحة أيضاً عبر واجهتي DLL وActiveX. التوثيق الكامل متاح على صفحة مكتبة PDFlibPas لـ Delphi