HotPDF renderira HTML tablice kroz svoj HTML5 paged-media profil koristeći pravu occupancy mrežu za rowspan i colspan, izmjerene visine redaka umjesto procjena po broju znakova, i retke zaglavlja ponovljene na svakoj nastavnoj stranici. Dvije situacije natjeraju ga da odbije ponoviti zaglavlje, i poznavanje njih unaprijed je jeftinije od debugiranja duplicirane ćelije poslije
Klasa dokumenta koja ovo nameće je ona koju svaki izvještajni tim prije ili kasnije isporuči: račun ili compliance izvještaj gdje je izvor istine HTML, tablica ide preko četiri stranice, i zaglavlje mora biti čitljivo na svakoj od njih. Išta manje od pravog tabličnog rasporeda proizvodi dva kvara koje čitatelji odmah primjete: zaglavlje koje se pojavi jednom na prvoj stranici i redovi čije su visine pogođene iz broja znakova
Zašto je tablična mogućnost preselila u HTML renderer?
Zato alternativa gubi rich text, a rich text je razlog što je sadržaj uopće HTML. Očigledan plan izgleda kao ponovna upotreba: HotPDF već ima layout DOM table objekt s pravom mrežom, pa spojite HTML parser u njega i dobijete spanning za džabe. Problem je čime taj table objekt crta. Njegove ćelije nose tekst i stil, i njegov crtaći put emitira običan tekstualni izlaz, pa je sve što je HTML stvarno sadržavao izvan fonta i boje, linkovi, superskripte, inline promjene veličine, boja po runu, nestalo do trenutka kad stigne na stranicu
Smjer koji preživi kontakt sa stvarnim dokumentima je obrnuti. Premjestite mogućnosti table enginea, occupancy mrežu, stvarno mjerenje, ponavljanje zaglavlja i težinsko odmeravanje stupaca, u HTML renderer, i ostavite rich-text renderiranje tamo gdje već radi. To je veća izmjena od mosta, i to je izmjena koja čini da hyperlink unutar tablične ćelije ostane hyperlink
Rowspan bez union-find strukture
Spanning ćelije stvaraju atomske grupe redaka, ali zatvorenje nad tim grupama ne treba opću disjoint-set strukturu, jer je occupancy uvijek kontinuirani interval. Ćelija s rowspan="3" koja počinje u retku K zauzima retke K do K+2 i ništa drugo, pa se informacija grupe svodi na oznaku kraja po retku
Algoritam je dvije linije namjere. Kad postavite spanning ćeliju koja počinje u K a završava u E, zapišite GroupEnd[K] := Max(GroupEnd[K], E). Zatim prođite retke jednom unatrag i primijenite G[R] := G[G[R]], što propagira svaki kraj retka unatrag kroz preklapajuće spanove i daje tranzitivno zatvorenje u jednom prolazu. Ono što dobijete je, za svaki redak, zadnji redak koji mora ostati na istoj stranici s njim, što je točno ono što korak paginacije treba da odluči gdje smije pasti prelom
Raspodjela visine je druga polovica. Kad spanning ćelija treba više okomitog prostora nego što ga redci koje pokriva trenutno daju, višak ide u posljednji redak spana, a ne ravnomjerno po njima. Obradite spanning ćelije nakon što se obične visine redaka srede, pa potom dopunite završni redak svakog spana. Ravnomjerna raspodjela viška zvuči poštenije i proizvodi vidljivo pogrešan izlaz: redci koji sadrže samo kratke jedno-linijske ćelije se napuhaju jer se neka nepovezana ćelija tri retka gore slučajno pokazala visokom
var
Pdf: THotPDF;
Importer: THPDFHTMLImporter;
Stats: THPDFHTMLImportStatistics;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'audit-report.pdf';
Pdf.BeginDoc;
Importer := THPDFHTMLImporter.Create(Pdf);
try
Importer.Margin := 48;
Importer.BaseFontName := 'Arial';
Importer.BaseFontSize := 10;
Importer.MaxDOMNodes := 200000;
Importer.MaxLayoutOperations := 2000000;
if Importer.RenderHTML5(SourceHtml, PrintStyleSheet) then
begin
Stats := Importer.Statistics;
Writeln('tables ', Stats.TableCount,
' page breaks ', Stats.PageBreakCount);
end;
finally
Importer.Free;
end;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
RenderHTML5 uzima opcionalni author style sheet kao drugi argument, i tamo pripadaju print pravila. Držite screen style sheet izvan toga. Profil je verzioniran, i HTML5ProfileMilestones javlja koje grupe mogućnosti trenutni build implementira, himParserCascade, himPagedLayout, himTablesForms i himBoundedResources, pa aplikacija može degradirati namjerno umjesto da prazninu otkrije u produkciji
Mjerenje se mora poklapati s crtanjem, točno
Visina retka je ispravna samo kad kod koji mjeri prelomljene linije prelomi istim pravilom kao kod koji ih crta. Zvuči očigledno i najčešći je pojedinačni izvor tablica čije se granice ne poklapaju sa sadržajem. HotPDF mjeri s pohlepnim brojačem linija, i taj brojač mora odgovarati semantici prelamanja rich-text izlaznog puta u tri konkretna pogleda: lomi samo na razmacima, nikad ne dijeli riječ, i riječ šira od stupca dobiva vlastitu liniju
Drugi zahtjev je font. Mjerenje mora raditi s fontom same ćelije, postavljenim kroz SetFont sa stvarnim imenom, setom stila i veličinom prije poziva funkcije širine, a ne s onim fontom koji se slučajno našao aktivan. Podebljani tekst je rutinski više od deset posto širi od regularnog u istoj veličini, što je dovoljno da tro-linijska ćelija postane četvero-linijska. Tablica gdje su zaglavne ćelije podebljane a tjelesne nisu, izmjerena jednim fontom, bit će pogrešna točno u redcima koje čitatelji prvi pogledaju
Ispravno ovo mijenja što možete tvrditi u testu. Uočljiv učinak točnog mjerenja je prored, a ne broj glifova: jedno-linijski redak je visok otprilike 20 točaka dok procjena po broju znakova za isti sadržaj predviđa dvije linije i otprilike 35. Tvrdite okomit razmak između redaka. I sjetite se da PDF user space ima Y koji raste prema gore, pa zaglavlje koje sjedi iznad tjelesnog retka znači da je Y vrijednost zaglavlja veća, što je suprotno od onoga što instinkt ekranskih koordinata napiše
Kada HotPDF odbije ponoviti zaglavlje?
U dva slučaja, od kojih bi oba proizvela vidljivo pogrešan izlaz da je nastavio. Prvi je blok zaglavlja koji sadrži spanning ćeliju koja se proteže preko zaglavlja u retke tijela. Ponavljanje zaglavlja nacrtalo bi taj sadržaj ćelije drugi put na poziciji koja više nije njegova, pa se zaglavlje crta jednom i tablica nastavlja bez njega. Drugi je zaglavlje više od 90 posto upotrebljive visine stranice, gdje bi ponavljanje ostavilo gotovo nikakav prostor za podatke i tablica ne bi napredovala
Oba odbijanja su namjerna i tiha po dizajnu, jer je alternativa gora. Ako se vaše zaglavlje ne ponavlja a očekivali ste da hoće, provjerite markup za rowspan koji prelazi thead granicu prije nego što posumnjate na engine. Taj jedan markup obrazac objašnjava većinu iznenađenja
// Težine stupaca dolaze iz markupa, pa je print style sheet mjesto
// za njihovo upravljanje. Širine se tretiraju kao težine, ne kao pikseli
const
PrintStyleSheet =
'table { width: 100%; }' +
'thead th { font-weight: bold; background: #eee; }' +
'td.amount { text-align: right; }';
// Redak zaglavlja koji nosi rowspan koji prelazi u tijelo potiskuje
// ponavljanje zaglavlja. Držite spanove unutar jedne sekcije:
// <thead><tr><th rowspan="2">Item</th>...</tr></thead> u redu
// <tr><th rowspan="3">Item</th>... prelazi u tbody, bez ponavljanja
Širine stupaca ponašaju se kao težine, a ne kao apsolutna mjerenja, što je ponašanje koje tablicu drži upotrebljivom kad se sadržaj ne poklapa s autorovom procjenom. Stupac deklariran na 30 posto dobiva otprilike 30 posto dostupne širine, ali raspodjela poštuje minimalnu širinu koju svaki stupac stvarno treba, pa uski stupac koji nosi dugački nerazdvojivi token ne prelije tiho okvir tablice
Gdje se ovo uklapa u dokumentni pipeline
Tablični rad sjedi unutar šireg paged-media profila, i pravila paginacije, resursni budžeti i CSS rukovanje opisani u HTML5 paged-media import putu vrijede nepromijenjeno za dokumente koji sadrže tablice. Ako vaši podaci ne počinju kao HTML, ruta izravne izgradnje u građenju tablica izravno u PDF izbjegava sloj parsiranja u potpunosti i daje vam isto ponašanje mreže kroz API. A budući da visina retka u konačnici ovisi o tome gdje se linije lome, rasprava o mjerenju u tekstualnom poravnanju i prelamanju linija je pratilac za svakoga ko štimava gust tablični izlaz
Prenosiva lekcija ovdje uopće nije o tablicama. Kad novi podsustav treba mogućnost koju stari podsustav već ima, pitajte koji od ta dva posjeduje ono što je najteže ponovno implementirati. Mrežna aritmetika je par desetaka linija i lako se preseli. Rich-text renderiranje s inline linkovima, superskriptama i stiliziranjem po runu nije, pa se mreža preselila a tekst ostao. HotPDF isporučuje obje puteve kao dio HotPDF Delphi PDF komponente, pa je izbor između HTML unosa i izravne izgradnje odluka projekta, a ne biblioteke