Műszaki cikk

PDFlibPas elválasztás és kiegyenlített hasábok Delphiben

A PDFlibPas egy megtartott szövegrészt egy és 64 közötti azonos szélességű hasábon folyat végig a DrawTextFlowColumns-szal, és a sorait korlátozott, nyelvfüggő elválasztással töri, amint meghívod a SetTextFlowLanguage és a SetTextFlowHyphenation függvényeket. Kilenc nyelv támogatott, és a nyelv örökölhető a dokumentum Catalog /Lang értékéből ahelyett, hogy folyamonként állítanád be

Mindkét funkció ugyanazért létezik: egy keskeny hasáb az a hely, ahol a naiv sortörés megszűnik szedésnek látszani, és elkezd hibajelentésnek látszani

Miért esik szét a sorkizárt szöveg keskeny hasábokban?

Mert a sorkizárás a maradék helyet a sor szóközeibe osztja szét, és a maradék mennyisége attól függ, mi fér el. Egy széles hasábszélességnél a maradék kicsi, és a szem soha nem veszi észre. Feleld a szélességet, és egy egyetlen hosszú szó, amely nem fér el, a következő sorra kerül, hagyva, hogy az elődei felszívják az összes helyet. Három ilyen sor egymás után létrehozza azokat a függőleges fehér csatornákat, amelyeket a tipográfusok folyóknak neveznek, és amelyeket az olvasók olyan szövegként élnek meg, amelyet nehéz követni anélkül, hogy tudnák, miért

Az elválasztás az okot javítja a tünet helyett azzal, hogy megengedi a törést a szó belsejében. A német és a holland összetett szavak ezt nem alkupozícióvá teszik: egy 24 karakteres főnévnek egy 60 milliméteres hasábban nincs jó kimenetele töréspont nélkül. Az angol jobban tolerálja a hiányát, ezért az angol-elsőbbségű termékek gyakran szállítanak olyan elrendezési kódot, amely elesik az első alkalommal, amikor egy német ügyfél futtatja

Mely nyelvek, és honnan származik a nyelv?

Az elválasztás lefedi az angolt, a németet, a hollandot, a franciát, a spanyolt, az olaszt, a portugált, az oroszt és a törököt. Állítsd be explicit módon folyamonként a SetTextFlowLanguage-dzsel, vagy hagyd, hogy örökölje a dokumentum Catalog /Lang bejegyzéséből, ami az az érték, amelyet egy tagelt és akadálymentes dokumentum már amúgy is hordoz

Ezt az öröklést érdemes használni felülbírálás helyett. Egy dokumentum, amely a Catalogban deklarálja a nyelvét, ugyanazt a tényt mondja el a képernyőolvasóknak, a keresőindexelőknek és az elválasztásnak egyetlen helyről, és egy hely az, ahol egy ténynek élnie kell. Ha már tagelt kimenetet állítasz elő, ahogy azt az automatikus tagelés akadálymentes PDF-ekhez című cikk leírja, a nyelvbejegyzés be van állítva, és a folyam egyszerűen követheti azt

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');
      // Bekapcsolva, a törés előtt legalább 3 karakter, utána 3
      Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);
      Lib.SetTextFlowMinLines(Flow, 2);   // soha ne hagyj magára egy egyetlen sort

      repeat
        // Három hasáb egy 480 pt-os régióban, 18 pt-os ereszcsatornákkal, kiegyenlítve
        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;

A MinPrefix és a MinSuffix tipográfia, nem validáció

A bekapcsoló jelző utáni két egész szám állítja be a törés előtt és után megmaradó karakterek minimális számát. A három és három egy konzervatív alapértelmezés, amelyet a legtöbb házi stílus elfogad. A kettő és kettő több töréslehetőséget és láthatóan csúnyább eredményeket produkál, mert egy sor végén lógó kétbetűs töredék elgépelésnek tűnik

Emeld meg a minimumokat, amikor a betűméret nagy, ahol minden töredék vizuálisan kiemelkedő, és csak akkor csökkentsd, amikor a hasáb valóban keskeny, és eldöntötted, hogy egy szűk hasábszélesség jobban számít, mint egy tiszta. Ez egy házi stílusdöntés, nem egy technikai, és pontosan ezért egy paraméter, nem egy konstans

Mit jelent valójában a „kiegyenlített” itt?

A Balance paraméter csak egy szövegrész végén változtatja meg a viselkedést. Kiegyenlítéssel bekapcsolva a hasábok pontosan egyenlő sorszámra rövidülnek, amikor minden hátralévő belefér a régióba, ami megakadályozza, hogy egy utolsó oldal két teljes hasábot mutasson, és egy harmadikat, amely egyetlen magányos sort tart. Amikor a szövegrész nem fér el, minden hasáb megtartja a teljes magasságát, így az oldal annyi szöveget hordoz, amennyit csak tud, és a maradék a következő oldalon folytatódik

Ez az aszimmetria a helyes alapértelmezés folyamatos dokumentumoknál. A kiegyenlítés egy folyó cikk közepén minden oldalon függőleges helyet pazarolna el egy kozmetikai hatásért, amelyet senki sem lát, mivel a hasábok amúgy is tele vannak. A kiegyenlítés a végén az, ahol a szem ténylegesen észreveszi, és pontosan ott is érvényesül

A sortörés egész szavakat mér

A törési algoritmus teljes szavakat mér, nem karakterszélességeket halmoz, és egy korlátozott keresést tart fenn a túlméretezett tokenekhez, amelyek egyáltalán nem férnek el egy sorban, mint egy URL vagy egy nyilvántartási szám. Ez gyorsan tartja a gyakori esetet, és korlátozottan a kóros esetet, nem pedig fordítva

Az opcionális lágy kötőjelek és az automatikus kötőjelek csak akkor renderelődnek, amikor az általuk jelölt törés az a törés, amelyet kiválasztanak. Ez triviálisnak hangzik, és egy klasszikus hiba: egy naiv implementáció megírja a kötőjel karaktert mérés közben, és ha a törés elmozdul, a kötőjel hátramarad egy sor közepén. Semmi sem néz ki jobban egy hibás szövegmotorra, mint egy elszabadult kötőjel egy szó belsejében

var
  Lib: TPDFlib;
  Flow, Needed: Integer;
begin
  // Döntsd el az elrendezést, mielőtt bármit is rajzolnál
  Flow := Lib.NewTextFlow(ArticleBody);
  try
    Lib.SetTextFlowLanguage(Flow, 'fr');
    Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);

    // A szövegrész hátralévő része hány sort igényel egy hasábszélességnél
    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;

Tartsd azonosnak a betűtípus-beállításokat a dobozok között

Egy szabály irányít minden folyamalapú elrendezést, és érdemes egyenesen kimondani: a DrawTextFlow, a DrawTextFlowColumns és a MeasureTextFlow mind a hívásuk pillanatában kiválasztott betűtípussal törik a sorokat. Változtasd meg a betűtípust vagy a méretet ugyanazon folyam két doboza között, vagy kezdj új oldalt anélkül, hogy újraválasztanál egyet, és a második doboz máshogy törik, mint amit az első mért

A tünet pontosan azért idegesítő, mert időszakosnak tűnik: az első oldalon elférő szöveg a második oldalon túlcsordul, vagy egy mért sorszám nem egyezik azzal, amit lerajzoltak. Válaszd ki a betűtípust egyszer a ciklus előtt, válaszd újra minden NewPage után, és a folyam viselkedni fog. Amikor vegyes írásrendszerek jelennek meg ugyanabban a szövegrészben, a automatikus betűtartalék CJK és emoji szöveghez című cikkben leírt megoldás mind a mérésre, mind a rajzolásra vonatkozik, így a szélességek a tartalék futásokon át is konzisztensek maradnak

Jelentéselrendezéseknél, ahol a folyam egy elem a fejlécek, láblécek és adatvezérelt blokkok között, a dataset report engine című cikkben leírt kompozíciós minták tisztán kombinálódnak a hasábfolyamokkal: mérj először, helyezd el a rögzített elemeket, majd add a folyamnak, bármilyen régió is maradt

A PDFlibPas egy Delphi, C++Builder és Lazarus PDF-könyvtár, és a teljes TextFlow-életciklus, létrehozás, rajzolás, mérés, vizsgálat, visszatekerés és felszabadítás, a DLL és az ActiveX interfészeken keresztül is elérhető. A teljes dokumentáció a PDFlibPas Delphi PDF-könyvtár oldalán található