A HotPDF a HTML táblákat a HTML5 paged-media profilján keresztül rendereli valódi elfoglaltsági ráccsal a rowspan és colspan kezelésére, mért sormagasságokkal karakterbecslések helyett, és minden folytatólagos oldalon megismételt fejlécsorokkal. Két helyzetben tagadja meg a fejléc ismétlését, és ezeket előre ismerni olcsóbb, mint később egy duplikált cellát debuggolni
A dokumentumosztály, amely ezt kikényszeríti, az, amelyet minden jelentéskészítő csapat előbb-utóbb szállít: egy számla vagy megfelelőségi jelentés, ahol az igazságforrás HTML, a tábla négy oldalon fut át, és a fejlécnek mindegyikén olvashatónak kell lennie. Bármi, ami kevesebb egy valódi táblaelrendezésnél, előállítja a két hibát, amelyet az olvasók azonnal észrevesznek: egy fejlécet, amely csak az első oldalon jelenik meg, és sorokat, amelyeknek a magasságát karakterből találták ki
Miért költözött a táblaképesség a HTML renderelőbe?
Mert az alternatíva elveszíti a rich textet, a rich text pedig az az ok, amiért a tartalom egyáltalán HTML. A kézenfekvő terv újrahasznosításnak tűnik: a HotPDFnek már van elrendezési DOM táblaobjektuma korrekt rácsgyal, bridzselje rá a HTML elemzőt, és a spanning ingyen jön. A gond az, hogy min rajzol az a táblaobjektum. Cellái szöveget és stílust hordoznak, a rajzolási útja sima szövegkimenetet ad, tehát bármi, amit a HTML ténylegesen tartalmazott a fonton és a színen túl, linkek, felső indexek, inline méretváltások, futásonkénti szín, odaveszik, mire az oldalra ér
A valós dokumentumokkal való találkozást túlélt irány a fordított. Vigye át a táblamotor képességeit, az elfoglaltsági rácsot, a valódi mérést, a fejlécismétlést és az oszlopsúlyozást a HTML renderelőbe, és hagyja a rich text renderelést ott, ahol már működik. Ez nagyobb változtatás, mint a híd, és ez az, amely azt biztosítja, hogy egy táblacellán belüli hyperlink hyperlink maradjon
Rowspan union-find nélkül
A spanning cellák atomi sorcsoportokat hoznak létre, de a csoportok feletti lezárás nem igényel általános disjoint-set struktúrát, mert az elfoglaltság mindig összefüggő intervallum. Egy K sorban kezdődő rowspan="3"-os cella a K-tól K+2-ig terjedő sorokat foglalja el, semmi mást, tehát a csoportinformáció soronkénti végejelre redukálódik
Az algoritmus két szándéksor. Amikor elhelyez egy K-ban kezdődő és E-ben végződő spanning cellát, jegyezze fel: GroupEnd[K] := Max(GroupEnd[K], E). Aztán járja be egyszer a sorokat visszafelé, és alkalmazza a G[R] := G[G[R]] lépést, amely az egyes sorvégeket visszafelé terjeszti az átfedő spaneken át, és egy menetben adja meg a tranzitív lezárást. Amit kap, minden sorhoz az utolsó sort, amelynek vele azonos oldalon kell maradnia, és pontosan ezt kell a lapozási lépésnek ahhoz, hogy eldöntse, hová eshet törés
A magasság elosztása a másik fele. Amikor egy spanning cellának több függőleges hely kell, mint amennyit az általa lefedett sorok jelenleg adnak, a többlet a span utolsó sorára megy, nem oszlik el egyenletesen köztük. Kezelje a spanning cellákat azután, hogy a közönséges sormagasságok kialakultak, majd töltse fel minden span utolsó sorát. A többlet egyenletes szétosztása méltányosabbnak tűnik, és láthatóan rossz kimenetet ad: azok a sorok, amelyek csak rövid, egysoros cellákat tartalmaznak, felfúvódnak, mert három sorral odébb véletlenül egy magas cella volt
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;
A RenderHTML5 opcionális szerzői stíluslapot fogad második argumentumként, és a nyomtatási szabályok ide tartoznak. Tartsa távol tőle a képernyős stíluslapot. A profil verziózott, és a HTML5ProfileMilestones jelenti, hogy az aktuális build mely képességcsoportokat valósítja meg: himParserCascade, himPagedLayout, himTablesForms és himBoundedResources, tehát az alkalmazás tudatosan foszlhat le, ahelyett hogy egy hézagot gyártás közben fedezne fel
A méretnek pontosan egyet kell értenie a rajzolással
A sormagasság csak akkor helyes, ha a tördelt sorokat mérő kód ugyanazzal a szabállyal töri őket, mint amelyik rajzolja őket. Ez nyilvánvalónak hangzik, és ez a leggyakoribb forrása azoknak a tábláknak, amelyeknek a keretei nem állnak egybe a tartalmukkal. A HotPDF mohó sorszámlálóval mér, és annak a számlálónak három konkrét pontban kell egyeznie a rich text kimeneti út tördelési szemantikájával: csak szóközön törik, sosem darabol szót, és az oszlopnál szélesebb szó saját sort kap
A második követelmény a font. A mérésnek a cella saját fontjával kell futnia, amelyet a SetFont-tal állítanak be a tényleges névvel, stílussal és mérettel a szélességfüggvény hívása előtt, nem azzal, amelyik épp aktív volt. A félkövér szöveg azonos méretben rutinszerűen több mint tíz százalékkal szélesebb a szokásosnál, ami elég ahhoz, hogy egy háromsoros cella négysoros cellává váljon. Egy tábla, amelynek fejléccellái félkövérek, a többi cellája nem, és egyetlen fonttal mérték, pontosan azokban a sorokban lesz rossz, amelyeket az olvasók először megnéznek
Ennek eltalálása megváltoztatja, mit állíthat egy tesztben. A pontos mérés megfigyelhető hatása a sorköz, nem a glifaszám: egy egysoros sor nagyjából 20 pont magas, míg ugyanennek a tartalomnak a karakterből számolt becslése két sort és nagyjából 35-öt jelez. Állítson a sorok közti függőleges távolságról. És ne feledje, hogy a PDF felhasználói terében az Y felfelé nő, tehát az a fejléc, amely egy tartalmi sor felett ül, nagyobb Y értéket visel, ami ellenkezője annak, amit a képernyőkoordináta-ösztön ír
Mikor tagadja meg a HotPDF a fejléc ismétlését?
Két esetben, amelyek mindegyike láthatóan rossz kimenetet adna, ha továbbmenne. Az első egy fejlécblokk, amely olyan spanning cellát tartalmaz, amely a fejlécen túl a tartalmi sorokba nyúlik. A fejléc ismétlése másodszor is megrajzolná azt a cellatartalmat egy olyan pozícióban, ahová már nem tartozik, tehát a fejléc egyszer rajzolódik, és a tábla nélküle folytatódik. A második egy 90 százaléknál magasabb fejléc a használható oldalmagasságból, ahol az ismétlés szinte sehol sem hagyna helyet az adatnak, és a tábla nem haladna előre
Mindkét elutasítás szándékos és tervezésből csendes, mert az alternatíva rosszabb. Ha a fejléce nem ismétlődik, pedig várta, ellenőrizze a markupban, van-e a thead határát átlépő rowspan, mielőtt a motort gyanúsítaná. Ez az egyetlen markupminta adja a meglepetések nagy részét
// Az oszlopsúlyok a markupból jönnek, tehát a nyomtatási stíluslap az a hely,
// ahol szabályozhatja őket. A szélességek súlyként kezelődnek, nem pixeleként
const
PrintStyleSheet =
'table { width: 100%; }' +
'thead th { font-weight: bold; background: #eee; }' +
'td.amount { text-align: right; }';
// Az a fejlécsor, amely a tartalomba nyúló rowspant visel, elnyomja a
// fejlécismétlést. Tartsa a spaneket egy szakaszon belül:
// <thead><tr><th rowspan="2">Item</th>...</tr></thead> rendben
// <tr><th rowspan="3">Item</th>... átnyúlik a tbodyba, nincs ismétlés
Az oszlopszélességek súlyként viselkednek, nem abszolút mérésként, és ez a viselkedés tartja használhatónak a táblát, amikor a tartalom nem egyezik a szerzői becsléssel. A 30 százalékra deklarált oszlop nagyjából a rendelkezésre álló szélesség 30 százalékát kapja, de az elosztás tiszteletben tartja az egyes oszlopok tényleges minimális szélességét, tehát egy hosszú, tördelhetetlen tokent viselő keskeny oszlop csendben nem túlfolyik a tábladobozon
Hol ül ez egy dokumentumfolyamatban
A táblamunka a tágabb paged-media profilon belül ül, és a HTML5 paged-media importút cikkben leírt lapozási szabályok, erőforrás-keretek és CSS kezelés változatlanul érvényesek a táblákat tartalmazó dokumentumokra. Ha az adata nem HTML-ként indul, a táblák egyenesen PDF-be építése cikk közvetlen építési útja teljesen kihagyja az elemzőréteget, és ugyanazt a rácsviselkedést adja API-n keresztül. És mivel a sormagasság végső soron azon múlik, hol törnek a sorok, a szövegigazítás és sortörés cikk mérésről szóló része a kísérő olvasmány mindenkinek, aki sűrű táblázatos kimenetet hangol
A hasznosítható tanulság itt egyáltalán nem a táblákról szól. Amikor egy új alrendszernek olyan képességre van szüksége, amelyet egy régi alrendszer már birtokol, kérdezze meg, melyikük birtokolja azt a dolgot, amelyet a legnehezebb újraimplementálni. A rácsaritmetika néhány tucat sor, és könnyen költözik. A rich text renderelés inline linkekkel, felső indexekkel és futásonkénti stílussal nem az, tehát a rács költözött, és a szöveg maradt. A HotPDF mindkét utat szállítja a HotPDF Delphi PDF komponens részeként, tehát a HTML bemenet és a közvetlen építés közti választás projekt döntés, nem könyvtári döntés