Tehnični članak

PDFlibPas: deljenje besed in stolpci v Delphiju

PDFlibPas pretoči zadržan odstavek skozi enega do 64 enako širokih stolpcev s DrawTextFlowColumns, vrstice pa lomi z omejenim jezikovno ozaveščenim deljenjem besed, ko pokličete SetTextFlowLanguage in SetTextFlowHyphenation. Podprtih je devet jezikov, jezik pa je lahko podedovan iz vrednosti /Lang v katalogu dokumenta namesto nastavljen za vsak tok posebej

Obe funkciji obstajata iz istega razloga: ozek stolpec je mesto, kjer naivno lomljenje vrstic preneha izgledati kot stavljenje in začne izgledati kot napaka

Zakaj se obojestransko poravnano besedilo v ozkih stolpcih razpade?

Ker obojestranska poravnava razporedi preostali prostor med besedne razmike v vrstici, količina preostanka pa je odvisna od tega, kaj se prilega. Pri širši meri je preostanek majhen in oko ga nikoli ne opazi. Prepolovite širino in ena sama dolga beseda, ki se ne prilega, se prestavi v naslednjo vrstico, njeni predhodnici pa morata vpiti ves ta prostor. Tri takšne vrstice zapored ustvarijo navpične bele kanale, ki jih tipografi imenujejo reke, bralci pa jih doživljajo kot besedilo, ki mu je težko slediti, ne da bi vedeli zakaj

Deljenje besed odpravi vzrok namesto simptoma, saj dovoli prelom znotraj besede. Nemški in nizozemski sestavljeni samostalniki to naredijo neizogibno: 24-znakovni samostalnik v 60-milimetrskem stolpcu nima dobrega izhoda brez mesta za prelom. Angleščina odsotnost prenaša bolje, zato izdelki, usmerjeni najprej v angleščino, pogosto dostavljajo kodo za postavitev, ki se sesuje ob prvi nemški stranki

Kateri jeziki, in od kod prihaja jezik?

Deljenje besed pokriva angleščino, nemščino, nizozemščino, francoščino, španščino, italijanščino, portugalščino, ruščino in turščino. Nastavite ga izrecno za posamezen tok s SetTextFlowLanguage ali pa ga podedujte iz vnosa /Lang v katalogu dokumenta, kar je vrednost, ki jo označen in dostopen dokument že nosi

To dedovanje je vredno uporabiti namesto povoziti. Dokument, ki svoj jezik navede v katalogu, bralnikom zaslona, iskalnim indeksatorjem in deljenju besed sporoča isto dejstvo z enega mesta, eno mesto pa je tam, kjer bi dejstvo moralo živeti. Če že ustvarjate označen izhod, kot je opisano v samodejnem označevanju za dostopne PDF datoteke, je vnos jezika nastavljen in tok mu lahko preprosto sledi

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');
      // Omogoči, vsaj 3 znake pred prelomom, 3 po njem
      Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);
      Lib.SetTextFlowMinLines(Flow, 2);   // nikoli ne osamite ene same vrstice

      repeat
        // Trije stolpci čez območje 480 pt, žlebovi 18 pt, uravnoteženo
        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 in MinSuffix sta tipografija, ne validacija

Dve celi števili za zastavico omogočanja določata najmanjše število znakov, ki mora ostati pred prelomom in za njim. Tri in tri je konzervativna privzeta vrednost, ki jo sprejme večina hišnih slogov. Dve in dve ustvari več priložnosti za prelom in opazno grše rezultate, ker dvočrkovni delček, ki visi na koncu vrstice, deluje kot tipkarska napaka

Zvišajte minimuma, kadar je pisava velika, kjer je vsak delček vizualno izstopajoč, znižajte ju le, kadar je stolpec resnično ozek in ste se odločili, da je tesna mera pomembnejša od čiste. To je odločitev hišnega sloga in ne tehnična odločitev, kar je natanko razlog, da je parameter in ne konstanta

Kaj tukaj dejansko pomeni "uravnoteženo"?

Parameter Balance spremeni vedenje le na koncu odstavka. Z vklopljenim uravnoteženjem se stolpci skrajšajo na natanko enako število vrstic, kadar vse preostalo ustreza znotraj območja, kar prepreči, da bi zadnja stran prikazala dva polna stolpca in tretjega z eno samotno vrstico. Kadar se odstavek ne prilega, vsak stolpec ohrani polno višino, tako da stran nosi kolikor besedila lahko, preostanek pa se nadaljuje na naslednji strani

Ta asimetrija je pravilna privzeta vrednost za zvezne dokumente. Uravnoteženje sredi tekočega članka bi na vsaki strani zapravljalo navpični prostor za kozmetični učinek, ki ga nihče ne vidi, saj so stolpci že polni. Uravnoteženje na koncu je mesto, kjer ga oko dejansko opazi, in prav tam se uporablja

Lomljenje vrstic meri cele besede

Algoritem za lomljenje meri cele besede namesto seštevanja širin znakov in si prihrani omejeno iskanje za predimenzionirane žetone, ki se sploh ne prilegajo vrstici, na primer URL ali številko računa. To ohranja pogost primer hiter, patološkega pa omejenega, ne pa obratno

Neobvezni mehki vezaji in samodejni vezaji so izrisani le, kadar je prelom, ki ga označujejo, dejansko izbrani prelom. To se sliši samoumevno in je klasična napaka: naivna izvedba zapiše znak vezaja med merjenjem, in če se prelom premakne, vezaj ostane sredi vrstice. Nič ne deluje bolj kot pokvarjen tekstovni pogon kot zablodel vezaj sredi besede

var
  Lib: TPDFlib;
  Flow, Needed: Integer;
begin
  // Odločite se za postavitev, preden karkoli izrišete
  Flow := Lib.NewTextFlow(ArticleBody);
  try
    Lib.SetTextFlowLanguage(Flow, 'fr');
    Lib.SetTextFlowHyphenation(Flow, 1, 3, 3);

    // Koliko vrstic ostanek odstavka potrebuje pri širini enega stolpca
    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;

Ohranite nastavitve pisave enake med polji

Eno pravilo velja za vsako postavitev na osnovi toka in vredno ga je povedati naravnost: DrawTextFlow, DrawTextFlowColumns in MeasureTextFlow vsi lomijo vrstice s pisavo, izbrano v trenutku, ko so poklicani. Spremenite pisavo ali velikost med dvema poljema istega toka, ali začnite novo stran brez ponovne izbire pisave, in drugo polje se lomi drugače, kot je izmerilo prvo

Simptom je znorel prav zato, ker deluje občasno: besedilo, ki se prilega na prvi strani, se prelije na drugi, ali pa se izmerjeno število vrstic ne ujema s tem, kar je bilo izrisano. Izberite pisavo enkrat pred zanko, ponovno jo izberite po vsakem NewPage, in tok se bo vedel pravilno. Kadar se v istem odstavku pojavijo mešane pisave, se rešitev, opisana v samodejnem nadomeščanju pisav za CJK in emotikone, uporablja tako za merjenje kot za izris, zato širine ostanejo skladne tudi v nadomestnih odsekih

Za postavitve poročil, kjer je tok en element med glavami, nogami in bloki, gnanimi s podatki, se kompozicijski vzorci v pogonu poročil, gnanem z naborom podatkov čisto ujemajo s stolpčnimi toki: najprej izmerite, postavite fiksno opremo, nato pa toku dajte kar koli območja je ostalo

PDFlibPas je knjižnica PDF za Delphi, C++Builder in Lazarus, celoten življenjski cikel TextFlow, ustvarjanje, izris, merjenje, pregled, previjanje in sprostitev, pa je izpostavljen tudi prek vmesnikov DLL in ActiveX. Celotna dokumentacija je na strani izdelka PDFlibPas