PDF Library for Delphi renderöi HTML:ää PDF-sivulle todellisella kaksiulotteisella asettelulla: display: flex ja display: grid mitataan ja sijoitetaan sen sijaan, että ne alennettaisiin pinotuiksi lohkoiksi, ja alaviitteet varataan sen laatikon alaosaan, joka kantaa niiden viittauksen, numeroinnin pysyessä jatkuvana palstojen ja sivujen yli. Sisäänmenopisteet ovat tutut, DrawHTMLTextBox yhdelle laatikolle ja DrawHTMLStory monipalstaiselle virtaukselle
Tällä on merkitystä, koska HTML on tapa, jolla useimmat raporttisisällöt saapuvat nykyään. Mallit kirjoitetaan ihmisten toimesta, jotka kirjoittavat CSS:ää, kojelaudat suunnitellaan kortteina, ja renderöijä, joka hiljaa romahduttaa flex-rivin neljäksi pinotuksi lohkoksi, tuottaa dokumentin, joka ei muistuta suunnittelua lainkaan. Ennen kuin tämä kyky oli olemassa, ainoa kaksiulotteinen säiliö, jota moottori mittasi, oli taulukko, joten jokainen korttiasettelu täytyi kirjoittaa uudelleen käsin taulukkona
Mikä muuttui asettelumallissa?
Aiempi pääsilmukka ylläpiti yksittäistä rivilaatikkoa ja eteni alaspäin sivulla. Tämä malli käsittelee inline-sisällön ja pinotut lohkot täydellisesti eikä pysty ilmaisemaan säiliötä, jonka lapset mitoitetaan suhteessa toisiinsa. Taulukot olivat ainoa poikkeus, omalla kaksivaiheisella mittauksellaan
Flex ja grid lisäävät kumpikin rajoitetun mittauskierroksen säiliön lasten yli, ja tärkeä sana on rajoitettu. Flex-säiliö mittaa enintään 256 suoraa lasta kiinteään taulukkoon. Grid käyttää enintään 64 kertaa 64 solun käyttöastematriisia deterministiseen automaattiseen sijoitteluun. Nämä katot ovat olemassa, jotta vihamielinen tai generoitu tyylitiedosto ei voi ajaa rajoittamatonta rekursiota tai neliöllistä sijoittelumuistia, mikä on todellinen huoli, kun HTML tulee mallista, jota asiakas muokkaa
Miten flex-kohteet saavat kokonsa
Rivisuunnassa säiliö laskee yhteen jokaisen kohteen perustan sekä sen kasvu- ja kutistumispainot, sitten jakaa jäljelle jäävän tilan, positiivisen tai negatiivisen, näiden painojen mukaan. flex-wrap-asetuksella jokainen rivi ratkaistaan itsenäisesti, joten rivi, joka katkeaa kahdeksi riviksi, jakaa vapaan tilan riviä kohden koko säiliön sijaan. Sarakesuunnassa sama pääakselin jakautuminen ajetaan joko eksplisiittistä korkeutta tai sisällön korkeutta vasten
justify-content, align-items, gap ja käänteiset suunnat toimivat jo mitatun geometrian päällä. Ne siirtävät laatikoita; ne eivät koskaan käynnistä kohteen sisällön uudelleenmittausta. Tämä erottelu on se, mikä estää monimutkaista kojelautaa mittaamasta lapsiaan useita kertoja
uses
PDFlibrary;
var
Lib: TPDFlib;
Html, Remainder: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.NewDocument;
Lib.SetPageSize('A4');
Lib.NewPage;
Html :=
'<div style="display:flex; gap:12px;">' +
' <div style="flex:2 1 0; background:#f4f6f8; padding:8px;">' +
' <b>Revenue</b><br/>EUR 4,182,300</div>' +
' <div style="flex:1 1 0; background:#f4f6f8; padding:8px;">' +
' <b>Margin</b><br/>18.4%</div>' +
' <div style="flex:1 1 0; background:#f4f6f8; padding:8px;">' +
' <b>Backlog</b><br/>92 days</div>' +
'</div>';
Remainder := Lib.DrawHTMLTextBox(40, 40, 515, 120, Html);
if Remainder <> '' then
Log('content did not fit - carry the remainder to the next box');
Lib.SaveToFile('dashboard.pdf');
finally
Lib.Free;
end;
end;
Palautusarvo on jatkomerkkijono, joka on tapa, jolla jokainen HTML-piirron sisäänmenopiste raportoi, mikä ei mahtunut. Anna se seuraavalle laatikolle tai seuraavalle sivulle, ja virtaus jatkuu siitä, mihin se pysähtyi
Grid-sijoittelu ja mitä ura voi olla
Grid-uraa hyväksyvät kiinteät pituudet, prosenttiosuudet, fr-yksikkö, yksinkertaiset repeat()-lausekkeet ja minmax(). Automaattinen sijoittelu täyttää käyttöastematriisin deterministisesti, joten sama HTML tuottaa aina saman järjestelyn. Eksplisiittisten koordinaattien sallitaan mennä päällekkäin, mikä on tarkoituksellista: suunnittelu, joka kerrostaa merkin kortin päälle, ilmaisee tarkoitusta, ei virhettä. Kun vain yksi akseli annetaan eksplisiittisesti, sijoittelu etsii vain toista akselia
Kohteet, jotka kattavat useita rivejä, antavat mitatun korkeutensa takaisin kattamilleen riveille, keskiarvoistettuna niiden yli, mikä estää korkeaa kattavaa kohdetta puristamasta yksittäistä riviä samalla, kun se jättää naapurinsa lyhyiksi:
Html :=
'<div style="display:grid; grid-template-columns:repeat(3, 1fr); ' +
' gap:10px;">' +
' <div style="grid-row:span 2; background:#eef;">Site plan</div>' +
' <div>Inspector</div>' +
' <div>Date</div>' +
' <div style="grid-column:2 / span 2;">Findings summary</div>' +
'</div>';
Remainder := Lib.DrawHTMLTextBox(40, 180, 515, 260, Html);
Flex ja grid -lapset renderöidään saman HTML-renderöijän kautta kuin kaikki muukin, mikä on ominaisuus, joka tekee tästä ominaisuudesta käyttökelpoisen erillisen maailman sijaan. Fontit, CSS-kaskadi, linkit, kuvat, taulukot ja lisää sisäkkäisiä flex- tai grid-säiliöitä käyttäytyvät kaikki flex-kohteen sisällä täsmälleen kuten ylätasolla, ja ulompi asettelusuunnitelma tallentaa lopulliset teksti- ja suorakulmiokomennot, joten toistuva piirto käyttää uudelleen olemassa olevaa mittausvälimuistia
Miksi alaviitteet ovat sivutusongelma?
Alaviite ei ole sisältöä, joka virtaa viittauksensa sisältävän kappaleen jälkeen; se on sisältöä, jonka täytyy esiintyä samaan laatikon alaosaan kuin sen viittaus. Tämä kääntää tavanomaisen mittausjärjestyksen, koska runkotekstille käytettävissä oleva tila riippuu nyt sisällöstä, jota ei ole vielä aseteltu
Renderöijä siis mittaa muistiinpanon, kun se kohtaa viittauksen, ja vähentää muistiinpanon alueen nykyisen rajoitetun laatikon runkokorkeusbudjetista. Jos viittaus, tähänastinen runkoteksti ja muistiinpano eivät kaikki mahdu, alaviitteen merkki ja kaikki sen jälkeinen siirtyvät jatkomerkkijonoon yhdessä. Tämä sääntö on se, mikä estää kaksi klassista virhettä: muistiinpanon, joka tulostuu päällekkäin runkotekstin kanssa, ja muistiinpanon, joka jää jumiin sivulle, jonka viittaus on edellisellä
Rajoitetussa laatikossa muistiinpanon alue on kiinnitetty alaosaan erotinviivalla sen yläpuolella. Rajoittamattomassa mittauksessa, jossa ei ole laatikon korkeutta, johon kiinnittyä, muistiinpanon alue seuraa välittömästi rungon jälkeen. Numerointi kannetaan laajennuskentässä jatkopinossa, joten DrawHTMLTextBox ja DrawHTMLStory pitävät sekvenssin käynnissä palstojen ja sivujen yli, ja jatkomerkkijono, joka on tuotettu ennen tuon kentän olemassaoloa, jatkuu silti oikein
// Monipalstaisen tarinan sisällä olevat alaviitteet pitävät yhtä jatkuvaa sekvenssiä
Html := LoadTemplate('chapter.html'); // käyttää float:footnote-merkintöjä
Remainder := Lib.DrawHTMLStory(40, 40, 515, 700,
2, // palstat
16, // väli pisteinä
20, // tämän tarinan enimmäissivumäärä
Html);
if Remainder <> '' then
Log('story exceeded its page budget');
Käytännön ohjeita mallien kirjoittajille
Suunnittele dokumentoitujen kattojen sisällä. Flex-säiliö, jossa on enemmän kuin 256 suoraa lasta, on lähes aina datataulukko flex-asussa, ja taulukkopolku mittaa sen joka tapauksessa paremmin. Grid, joka on suurempi kuin 64 kertaa 64, on laskentataulukko, ja sama neuvo pätee. Monipalstaiselle runkotekstille palsta- ja tavutuskäyttäytyminen, joka kuvataan artikkelissa tavutus ja tasapainotetut tekstipalstat, hallitsee, miltä virtaus näyttää kunkin palstan sisällä
Mittaa ennen piirtämistä, kun asettelun täytyy mahtua. GetHTMLTextHeight raportoi korkeuden, jonka tietty leveys tarvitsisi, mikä on halpa tapa päättää yhden asettelun ja toisen välillä ennen musteen sitoutumista. Ja kohtele ei-tyhjää jatkomerkkijonoa normaalina eikä poikkeuksellisena: se on mekanismi, jolla pitkä sisältö sivuttuu, ei virhesignaali
Kun HTML tulee raporttimoottorista käsin kirjoitettujen mallien sijaan, tietoaineistovetoinen reitti artikkelissa tietoaineiston raporttimoottori sopii tähän hyvin, tuottaen merkinnän, jonka flex ja grid sitten järjestävät. Ja kun saman sisällön täytyy myös poistua PDF:stä uudelleen, semanttinen vientipolku artikkelissa PDF:n vienti Markdowniksi ja DOCX:ksi sulkee kiertomatkan
HTML-asettelu, raporttien luonti ja semanttinen vienti ovat osa yhtä kirjastoa Delphille, C++Builderille ja Free Pascalille; täydellinen ominaisuusluettelo on sivulla PDF Library for Delphi -sivulla