PDFlibPas налива задържан текстов пасаж в от една до 64 колони с еднаква ширина чрез DrawTextFlowColumns и пренася редовете му с ограничено, езиково съобразено сричкопренасяне, след като извикате SetTextFlowLanguage и SetTextFlowHyphenation. Поддържат се девет езика, а езикът може да се наследи от стойността /Lang в document Catalog, вместо да се задава за всеки текстов поток
И двете функции съществуват по една и съща причина: тясна колона е мястото, където наивното пренасяне на редове спира да прилича на типография и започва да прилича на доклад за бъг
Защо подравненият текст се разпада в тесни колони?
Защото подравняването разпределя оставащото място в интервалите между думите на реда, а количеството оставащо място зависи от онова, което се побира. В широка мярка остатъкът е малък и окото никога не го забелязва. Намалете ширината наполовина и една дълга дума, която не се побира, се премества на следващия ред, оставяйки предходните думи да поемат цялото това място. Три такива реда последователно произвеждат вертикалните бели канали, които типографите наричат „реки“, а читателите усещат като текст, труден за следене без да знаят защо
Сричкопренасянето лекува причината, а не симптома, като позволява прекъсване вътре в думата. Немските и нидерландските съставни думи правят това небезспорно: 24-знаково съществително в колона от 60 милиметра няма добър изход без точка на прекъсване. Английският понася отсъствието по-добре, което е причината продукти, ориентирани първо към английски, често да пускат код за оформление, който се сгромолясва при първия немски клиент
Кои езици и откъде идва езикът?
Сричкопренасянето покрива английски, немски, нидерландски, френски, испански, италиански, португалски, руски и турски. Задайте го изрично за всеки текстов поток с SetTextFlowLanguage или го оставете да се наследи от записа /Lang в document Catalog, който е стойността, която таг-иран и достъпен документ вече носи
Това наследяване си струва да се използва, а не да се пренаписва. Документ, който декларира езика си в Catalog, съобщава на screen reader-и, търсещи индексатори и сричкопренасяне един и същ факт от едно място, а едно място е точно там, където един факт трябва да живее. Ако вече произвеждате таг-иран изход, както е описано в автоматичното таг-иране за достъпни 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 pt, 18 pt улици, балансирано
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 и потокът ще се държи правилно. Когато в един пасаж се появяват смесени писмености, разрешаването, описано в автоматичния font fallback за CJK и emoji текст, важи и за измерването, и за изчертаването, така че ширините остават последователни и през резервните последователности
За оформления на отчети, където текстовият поток е един елемент сред заглавия, долни колонтитули и блокове с данни, композиционните шаблони в движока за отчети на набори от данни се съчетават чисто с колонни потоци: измерете първо, разположете фиксираните елементи, после дайте на потока каквото пространство е останало
PDFlibPas е PDF библиотека за Delphi, C++Builder и Lazarus, а целият жизнен цикъл на TextFlow — създаване, изчертаване, измерване, инспекция, връщане назад и освобождаване — е изложен и през DLL и ActiveX интерфейсите. Пълната документация е на страницата на PDFlibPas PDF библиотеката за Delphi