Volanie, ktoré umiestňuje text na stránku PDF, je priamočiare. Zadáte funkcii AddText reťazec, písmo, veľkosť a pozíciu a znaky sa zobrazia. Čo vám však toto volanie nepovie, je to, aký široký bude tento reťazec po jeho nakreslení a nerozdelí dlhý reťazec do niekoľkých riadkov. Jedno volanie nakreslí jeden beh textu na jednej pozícii. Ak je tento úsek širší ako stĺpec, do ktorého ste ho chceli umiestniť, jednoducho presiahne okraj a samotné vykresľovacie volanie vás na to nijak neupozorní. Vo chvíli, keď chcete odsek namiesto jediného štítku, chýbajúcim dielikom je zistenie šírky reťazca vo zvolenom písme a veľkosti, nameranej pred jeho skutočným zápisom na stránku
Toto je klasický problém rozloženia (layoutu). Ak chcete zalomiť odsek do stĺpca, musíte slovo po slove vedieť, koľko horizontálneho priestoru zaberie každý kandidátsky riadok, a musíte to vedieť pred vykreslením čohokoľvek. Zalamovanie slov (word wrap) je meracia slučka obalená okolo volania vykresľovania, pričom pripojenie (binding), ktoré iba vykresľuje, vám dáva len druhú polovicu tohto procesu. Podpora merania textu v komponente PDFium tento nedostatok odstraňuje dvoma funkciami MeasureText a MeasureTextWidth, ktoré hlásia rozsah vykresleného reťazca bez toho, aby na ľubovoľnú stránku urobili akúkoľvek značku
Prečo je meranie class helperom, nie novou metódou v TPdf
Podpora merania prichádza ako tzv. class helper (pomocník triedy) Delphi pre objekt TPdf, sídliaci vo vlastnej jednotke, a nie ako nové metódy priskrutkované priamo do triedy TPdf. Class helper je funkcia jazyka, ktorá vám umožňuje pripojiť metódy k existujúcemu typu zvonku jeho deklarácie. Akonáhle je táto jednotka v obore platnosti (v scope), k novým metódam sa pristupuje rovnako, ako keby patrili danej triede, takže helperová metóda sa zapisuje ako Pdf.MeasureTextWidth(...) a nevyžaduje na svoje vytvorenie ani presúvanie samostatný objekt
Dôvodom, prečo sa k funkcii pristupuje formou vrstvy, je oddelenie. Samotné jadro typu TPdf zostáva presne také, aké je, bez pridania poľa a zásahu do podpisu rozhrania. A preto ten projekt, ktorý nepotrebuje formátovanie rozloženia zalamovaním (layout), neobsahuje (nenesie so sebou) kód určený výhradne na meranie. A zasa iný projekt, v ktorom takáto utilita chýba, len zahrnie príslušnú deklaráciu k príkazu uses a funkcie sa sprístupnia. Schopnosti rozhrania (capability) sa tým pádom implementujú s modularitou na úrovni jedinej vrstvy. Týmto prístupom možno čo najbezpečnejšie rozširovať knižnicu pre typ, ktorý nevlastníte (či netúžite meniť jeho kód na nízkej úrovni)
uses
PDFium, FPdfView, FPdfEdit,
FPdfMeasure; // the helper unit; brings MeasureText into scope on TPdf
// With the unit in scope the methods read as members of TPdf:
var
W, H: Double;
begin
Pdf.MeasureText('Subtotal', 'Helvetica', 11, W, H);
// W and H are now the rendered width and height in PDF user units
end;
Meranie bez toho, aby sme sa dotkli stránky
Meranie textových dimenzií musí fungovať nezávisle (nesmie ovplyvniť stránku). Ak funkcia odpovie nameranou šírkou, nenecháva za sebou žiadne nežiaduce vplyvy, predovšetkým preto, že na to, aby program zistil usporiadanie rozvrhnutia rozmerov (layout), funkciu vyzýva neustále v slučkách, pričom finálny vzhľad dokumentu zotrváva presne taký, aký by bol s vynechaním samotnej meracej rutiny. Za úspechom danej aplikačnej techniky je tvorba izolovaného textového objektu. Tento povie dĺžku veľkosti (rozmery) a objekt vyhodí von bez nutného viazania v pamäti pred jeho nasadením na ktorúkoľvek stranu knižnice
Sekvenciu tvoria štyri volania knižnice PDFium. Funkcia FPDFPageObj_NewTextObj vytvorí textový objekt oproti danému dokumentu po odovzdaní písma a jeho rozmerov (veľkosti). Úkon FPDFText_SetText vymedzuje priradený reťazec prislúchajúci voči objektu. Zatiaľ čo FPDFPageObj_GetBounds ohraničuje prekážky poľa celkového obdĺžnika rozmeru pre načítanie jeho súradníc z prečítania samotného prvku. Prvok FPDFPageObj_Destroy na uvoľnenie (z pamäte). A čo je kľúčové – žiaden úsek vyššie prispôsobených procesov nerobí zásahy formou odovzdávania do štruktúry stránky ako takých príkazov na umiestnenie vkladania do programovacieho API, vzhľadom k tomu, že daný objekt vznikne v izolovanom priestore, jeho zistená šírka po meraní nevyprodukuje zmeny v PDF a proces sa zruší oddelene od dokumentu s presným doručením očakávanej dĺžky veľkosti objektu od vyžiadania výstupu návratovou formou štyroch okrajových rozmerov v podobe čísel definujúcich samotný nákres ohraničenia poľa (bounding box)
To je naozaj spoľahlivý krok pre docielenie spomenutého zámeru z dôvodu, že samotný vizualizačný formát komponentu PDFium neotvára ľahko prijateľnú formálnu možnosť voľby "predkalkulovaného miesta šírky pre glyf (znak)". Metrika symbolov znakovej sady, ktorá presne sprostredkúva grafický vzhľad každého fontu (písma) viazaného priamo na vlastný spôsob dešifrovania a nahrávania grafickej sady knižnice pre prístup zo systému – a navyše nenájdeme pre ňu voľne zavolateľné rozhranie pre zverejnenie informácie od každého individuálneho načítaného objektového reťazca písmen so vzťahom k rozmerom (advance of each character). Namiesto aproximácie, ohraničenie presného bloku existujúceho skutočného prvku textu definuje (vypočítava) rovnaký funkčný podklad renderovania pri vizuálnej kompozícii pred samotným zápisom a odráža rozmer bez zaváhaní z nepresnosti výpočtov – a predbežné spracovanie pre zosnovaný blok na požiadanie podá presné parametre celistvej dimenzie spomínaných znakov od najvýraznejšieho ukazovateľa meraní, čo samotný knižničný prostriedok formálne poskytne s plným rešpektom spoľahlivosti meracieho prepočtu
// The shape of MeasureText, expressed against the verified PDFium calls.
// A text object is built, measured, and destroyed; no page is involved.
procedure TPdfMeasureHelper.MeasureText(const Text, Font: WString;
FontSize: Single; out Width, Height: Double);
var
TextObject: FPDF_PAGEOBJECT;
L, B, R, T: Single;
begin
Width := 0;
Height := 0;
if Self.Document = nil then
Exit;
TextObject := FPDFPageObj_NewTextObj(Self.Document,
FPDF_BYTESTRING(AnsiString(Font)), FontSize);
if TextObject = nil then
Exit;
try
if FPDFText_SetText(TextObject, FPDF_WIDESTRING(WideString(Text))) = 0 then
Exit;
if FPDFPageObj_GetBounds(TextObject, L, B, R, T) <> 0 then
begin
Width := R - L;
Height := T - B;
end;
finally
FPDFPageObj_Destroy(TextObject); // probe discarded, page untouched
end;
end;
Súradnice a jednotky výsledku
Priestor, známy z funkcie ohraničujúcej blokové vymedzenie grafiky pre text, vyprodukuje navrátenie štyroch okrajov – prislúchajúcej obrysovej schémy ľavej a pravej dimenzie a hornej a spodnej stopy (left, right, top, bottom), kedy presné body rozmerov vyjdú (sa určia) vzájomným odrátaním (rozdielom) hodnôt. Šírka ostáva po odpočítaní pre pravý bod hrany voči ľavému a rovnako rozmer určujúci výšku predstavuje odčítanie medzi hodnotou zo zistenej vzdialenosti vrchného s parametrom zo stopy spodnej okrajovej vrstvy (top minus bottom). Daná miera definujúca parametre reprezentuje podstatu dimenzie v "používateľských jednotkách PDF" pre obidva smery – ide pritom presne o vzdialenosť tvoriacu jeden (1) diel ako celok merateľný k mierke jeden diel zo sedemdesiatdva stotín jednotky v podobe 1/72 palcov (inch). Spomenutá súradnicová doména formátu presne zrkadlí systém pozícií a vzťažných priestorov po umiestnení do dokumentu pre oblasť vykresľovania bez tajnej prepony tvorenej pixlami alebo iným prepočtom na rozlíšenia formy zariadenia na zobrazovanie pred jej transformáciou. Získanie zosnímanej preukázanej šírky (napr. na hodnote 36 bodov - point - units) reprezentuje polovicu palca priestoru pred vizualizačnou štruktúrou po finálnom spracovaní pre zariadenie
Z-tová orientácia dokumentu v tvare určenom k nákresu vo vyhradenej línii postupuje u zobrazení pre vertikálnu smerovú dimenziu v zhode a vo formálnom tvare (the vertical axis), na čo myslel štandard zadefinovaním osi Y rastúcej (so vzostupom) pre mierku smerujúcu hore zo spodnej hranice nahor (s nárastom pre dimenzie y nahor). A pre daný zmysel smerového prúdu sa nameraný rozmer voči obrysovým ohraničeniam blokov zisťuje zhora z vrcholových okrajov nadol so vzájomným záporným prepočtom od hodnoty pre vrchný po odpočítaní najspodnejšieho okrajového stredu poľa, miesto rovnice obráteného vzorca. Je to zároveň odpoveď a kľúčová hodnota formálne odvíjajúca smer s určením dôležitej cesty pozície klesajúcim kurzorom pre formátovaný (zarovnaný zvislý) dokument či stĺpec textu pri presúvaní vo vývoji – dimenzia získanej stopy slúži na zrátanie rozmeru so základňou (k odpočítavaniu), v prípade ubiehajúcich ďalších odstavcov (nových blokov), pričom formát odskoku pri postupnom vytváraní pozície dokumentom nabehne so štruktúrou odvíjania pozície a úpravy smerovej roviny po postupne zmenšujúcom sa orientačnom stĺpci ypsilón. Krok sa nemení – a keď mierite do prístroja obrazovky v zastúpení požiadaviek miesto tlačených médií papiera, presný matematický zápis u rozmeru posúva získané body (units, po nameraní v knižnici) od vynásobenia k rozmeru pre grafické zobrazenie merítka bodov s pomerom hustoty (DPI) na pomer pri premene s hodnotou priamych 72 vo výsledku tvoriaci štruktúru po zistení výstupu bodov pixla – čím dokážete (bez pochýb formálneho prepočtu vo volaniach) pripraviť stanovenú šírkovú škálu parametrov obmedzujúcu a roztrieďujúcu prúd, čím predurčene rozdeľujete a pripravujete znakový systém skôr predtým v momente nasadenia úprav riadkov prispôsobených na zlom podľa vyhodnocovanej orientácie
Čo sa stane pri chybnom vstupe
Funkcie sa zostavili tak, aby dokázali prežiť nedostatky vo vlastnej chybe utíšením a formálnym vyradením bez hlásení – priamo bez prítomnosti požiadaviek otvorených vo fáze dokumentov alebo s neschopnosťou vytvorenia územia vizualizácie v znakovej mape ohlásia len v prísnej podobe výstupy vo variante prázdneho rozpätia hodnotami pre nulové ohraničenia priestoru výnimky. Rozmery zo strán s vracaním šírky s dĺžkou odovzdajú po inicializácii navrátenie nulovou sadou parametrov k vrcholu premenných, kým formát k odpísaniu ich naštartuje od chvíle plnohodnotného úspechu po správnom (overenom načítaní hodnotového rozmeru po obrysovom ohraničení) získaní spätnej väzby – nulový vplyv u neprítomných, chybných väzbách prázdnych reťazcov bez otvorených platných dokumentov bez rozpoznania fontových odvetví z knižnice s prepojením štruktúrovaných vizuálnych blokových obrysov do preukázateľného riešenia s generovaním výnimky či zlyhania
Konkrétne pravidlá si zvoleným (pôvodným formátovým) princípom v zosieťovanej úmernosti meracích požiadaviek plne odpovedia k sprostredkovaniu na cyklus s formátmi bežiace pre stovky či tisíce volaných sekvencií – čo neobstojí z pohľadu výstupov odosielajúcich signály prispôsobovanými udalosťami iteratívnych prázdnych prechodov. Pre obstarávanú podstatu (tzv. "náklady z odberu") prítomnosť vo voľnom zotrvávaní posúva k posudzovaniu samotného požiadaného (kontrolóra k príkazu pre podmienky u volaní užívateľským systémom programu). Pričlenená nulová (zero width) miera nezohľadňuje vlastnosti posúdeného (ani skutočného vizuálne zosnímaného reťazca znakov) miesta pre rozloženie v bloku dokumentov – jej prítomnosť vo vyhodnoteniach a porovnaniach u kontrolného rozlišovacieho prostredia kódov nesie ochranný formát z funkcie s ochrannou strážou na vloženie pred prijatím k zisteniu parametra, bez ktorej nemáte možnosť podeliť voľný ukazovateľ a roztriediť výsledky. Pokiaľ funkčný rozmer akceptujete na princípe odpovede vo vzťahu (od slova) "zlyhalo meranie" (vo vyjadrení nula s preukázateľnou garanciou), neprekvapí nejasným ohlásením. Jeho neposúdenie alebo vylúčenie by presne priradilo zhodený obrysový tvar vizuálnych blokov pre prispôsobenie do skrytých, chybne prekrytých znakov v jednom zhustenom vizuálnom systéme
Hladné zalamovanie slov (greedy word wrap) postavené na meraní
S funkciou na získanie šírky k dispozícii u zalamovania – slúži presúvanie po slove spravidla podobou funkčne pripravených malých slučiek s hladným a formálnym tokom pre formát zoraďovania prichádzajúcich hodnôt (ako tzv. greedy algorithm pre word wrap). Spočítaním úmerne k vyradeniu postupujete od rozdelenia prítomných viet, pri zachovaní radenia prispôsobovaného úseku radových odsekov riadkov prítomným krokom v zistení u každého pridávaného nasledujúceho textu posudzovanej voľby formálnej hodnoty (reťazca nového poľa po získaní s prepočtami od uloženia znakov do jedného pridávaného reťazca). Kým prepočtový stav kontrolného úseku (zostavy radeného oddielu zo znakových vetiev pripojovaných znakov textu po preverení ohraničených údajov) zodpovedá do voľných limitov hodnôt predbežného odčítaného rozsahu okrajov, naťahujete – pri prekonaní formátu či zistenom pripojenom nadbytočnom odseku prekrývajúcich vložiek obrys prispôsobeného riadka k odovzdaniu zavrhnete, odoslaním príkazu AddText ho uložení a založíte z nového obvodu vkladanie od nepresiahnutých limitov neprijatého slova pre pokračujúcu sekvenciu v poli (ďalší preskočený riadok vizualizácií do PDF). Tvorba a celková väzba prichádzajúceho signálneho posúdenia v prepočtovom modele operuje od prebratých ohraničení preukázateľným volaním úkonu požiadavky na hodnotu MeasureTextWidth pre funkčné nasmerovanie riadkových štruktúr sprostredkovaných s vizuálnym presunutím len bez prerušených zadefinovaných meraných prijatých obmedzení z overených priamo usadených rozmerových podkladov pre ohraničenia stĺpcov či riadkov v podmienkach
procedure WrapParagraph(Pdf: TPdf; const Para, Font: WString;
FontSize: Single; X, TopY, ColumnWidth, LineHeight: Double);
var
Words: TArray<string>;
Line, Trial: WideString;
I: Integer;
Y: Double;
begin
Words := string(Para).Split([' ']);
Line := '';
Y := TopY;
for I := 0 to High(Words) do
begin
if Line = '' then
Trial := Words[I]
else
Trial := Line + ' ' + Words[I];
// Measure the candidate line before drawing anything.
if (Line <> '') and (Pdf.MeasureTextWidth(Trial, Font, FontSize) > ColumnWidth) then
begin
Pdf.AddText(Line, Font, FontSize, X, Y); // flush the line that fit
Y := Y - LineHeight; // Y decreases going down
Line := Words[I]; // overflowing word starts next line
end
else
Line := Trial;
end;
if Line <> '' then
Pdf.AddText(Line, Font, FontSize, X, Y); // flush the final line
end;
Zistená skúška u slučky pracuje k preposlaniu z kontroly pokusného (overovaného radového toku znakových vkladov k riadku textu) miesto vyžadovaného premeriavania slov k posúdeniu pod prepočtami zisteného pridaného odseku spájania zo sčítaného – celková podmienená ohraničujúca dĺžka nevychádza zo súčtovej skladby pre merania od celku rozmerov vkladaných hodnôt u parametrov samostatných jednotlivých výrazov textu (slov v poli). Vo formálnom vkladanom modeli znakov medzier vzniká prenesenie vizuálu aj na pridružený priamy reálny dosah v medzerách – čím vizuálne kontrolovaný rozmer zachytí formátovací úsek pre posúvanie prenášaný voľbou po funkčnosti znakového modelu priamo pre úsek reťazca textu so slovami vrátane voľných medzier pre bezprostredný prejav znakového bloku s prepočítaným vkladom. V priraďovaní od obsluhy formálneho "hladného formátu usadzovania pravidla riadkov pre greedy algoritmy do ukladania stĺpcov vo funkčnosti s vyčerpaním plnej prijateľnej mierky pred presunom vo zlomovom mieste na predchádzajúci prepočtový textový úsek pre slová čo presahujú rozmer stĺpcového priraďovania" – pracuje totožne overené presvedčenie pred počiatočným vkladom úvodného priamo volaného AddText pri presune bez prítomného úpravou usporiadaného bloku. Prítomnosťou z vizuálnych volaní pri vykresľovaní nedochádza k náročným komplikáciám po chybách pod formálom štruktúrovaných metód; to predovšetkým zabezpečené preskúšavacie volanie určené k priamo zameraným funkciám v pomocnom triednom volaní (v objekte k zisteniu class helpera) slúži pre tento formálny model pri presnosti zozbieraných prijatých požiadaviek pre funkčný modul
Kam toto patrí
Meranie je vrstvou medzi generovaním obsahu a jeho vykresľovaním, takže sa prirodzene spája so zvyškom pracovného postupu (workflow) pre vytváranie dokumentov úplne od začiatku. Ak skladáte stránky a v prvom rade umiestňujete text, základy pre to nájdete v článku tvorba PDF dokumentov od nuly pomocou komponentu PDFium v Delphi, kde sú AddText a nastavenie stránky plne pokryté. Keď na použitom písme pre meranie záleží rovnako ako na reťazci, pretože metriky závisia od vzhľadu znakovej sady, analýza vlastností písma PDF pomocou komponentu PDFium v Delphi ukazuje, ako knižnica hlási informácie o fontoch, ktoré riadia parametre polohy poľa pre text. Obidve tieto schopnosti sú postavené na tom istom pripojení (bindingu), na module pre PDFium Component určenom pre Delphi a Lazarus, kde sa pomocník (helper) na meranie textu dodáva spolu s API dokumentu, rozhraním pre stránku a úpravu textov popísaných naprieč celým týmto blogom