HotPDF hahmontaa ladatun PDF-sivun Delphin TBitmap-objektiksi yhdellä kutsulla: RenderLoadedPageToBitmap(PageIndex, DPI). Funktio tulkitsee sivun sisältövirran ja palauttaa kutsujan omistaman 24-bittisen RGB-bittikartan valitsemallasi resoluutiolla. Tämä on juuri sitä, mitä pikkukuvapalkki, tulostuksen esikatselu tai PDF-kuvaksi-vientiputki tarvitsee. Tässä artikkelissa käydään läpi API ja sen jälkeen se osa, joka erottaa käyttökelpoisen hahmontimen lelusta: tekstin piirtäminen itse upotetuista fonttiohjelmista sen sijaan, että käytettäisiin samankaltaisia järjestelmäfontteja
Miksi PDF-sivun hahmontaminen on vaikeampaa kuin kuvan piirtäminen?
PDF-sivu ei ole valmis kuva. Se on ohjelma: sarja operaattoreita, jotka rakentavat polkuja, valitsevat fontteja, asettavat värejä ja sijoittavat glyyfejä. Tämä ohjelma suoritetaan standardin ISO 32000-1 §8 mukaisen grafiikkamallin mukaisesti. Tiedostossa itsessään ei kerrota, miltä mikään pikseli näyttää. Bittikartan luomiseksi sinun on suoritettava tämä ohjelma — ylläpidettävä nykyistä muunnosmatriisia, grafiikkatilan pinoa q/Q-operaattoreille, rajauspolkua, täyttö- ja viivaväriavaruuksia — ja rasteroitava tulos. Siksi "sivun 3 näyttäminen kuvana" vaatii sisältövirran tulkin, ei pelkkää tiedostomuodon muunnosta
HotPDF:n hahmontin, joka esiteltiin versiossa v2.253.0, is built as six decoupled units mirroring that model: an affine-matrix core for the PDF [a b c d e f] transform algebra, a graphics-state stack, a color-space resolver (DeviceRGB, DeviceGray, DeviceCMYK, Indexed), a path builder that bridges PDF path operators to GDI, a font-metrics layer that reads /Widths arrays for correct advances, and the interpreter that dispatches operators and drives the other five. Kuvan XObjectit käyvät läpi saman purkupinon, jota kirjasto käyttää tekstin/kuvien purkamiseen, joten jokainen kuvansuodatin, jonka HotPDF pystyy purkamaan — mukaan lukien JPXDecode-pakatut JPEG 2000 -kuvat — näkyy myös hahmonnetussa tulosteessa
Ladatun sivun hahmontaminen TBitmapiksi
RenderLoadedPageToBitmap ottaa nollapohjaisen sivunindeksin ja DPI-arvon, jossa 72 DPI kartoittaa yhden PDF-käyttäjäavaruuden yksikön yhdeksi pikseliksi. Se palauttaa arvon nil epäonnistuessaan (indeksi alueen ulkopuolella, puuttuvat resurssit) poikkeuksen nostamisen sijaan, jotta katseluohjelma voi ohittaa vioittuneen sivun ja jatkaa toimintaansa. Kutsuja omistaa palautetun bittikartan ja hänen on vapautettava se
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('report.pdf') > 0 then
begin
Bmp := Pdf.RenderLoadedPageToBitmap(0, 144); // page 1 at 144 DPI
if Bmp <> nil then
try
Image1.Picture.Assign(Bmp);
finally
Bmp.Free; // caller owns the bitmap
end;
end;
finally
Pdf.Free;
end;
end;
DPI-argumentti hoitaa skaalauksen kaikissa yleisissä skenaarioissa. Pikkukuvapalkki hahmonnetaan 36 tai 48 DPI:n tarkkuudella, jolloin saadaan pieniä ja nopeita bittikarttoja; näytöllä näkyvä esikatselu 96 tai 144 DPI:n tarkkuudella vastaa tyypillistä näyttötiheyttä; vientipolku 300 DPI:n tarkkuudella tuottaa painolaatuisia kuvia. Sivun kierto /Rotate-merkinnästä ja /MediaBox-origon kääntäminen (PDF asettaa origon vasempaan alakulmaan, GDI vasempaan yläkulmaan) käsitellään sivu-laite-matriisin sisällä, joten US Letter -sivu 72 DPI:n tarkkuudella palautuu täsmälleen koossa 612×792 pikseliä oikein päin
Miksi hahmonnetut PDF-pikkukuvat näyttävät vääriltä glyyfeiltä?
Väärät tai sinne päin olevat glyyfit hahmonnetussa PDF-tulosteessa tarkoittavat lähes poikkeuksetta sitä, että hahmontin korvaa fontin järjestelmäfontilla sen sijaan, että se käyttäisi tiedostoon upotettua fonttia. Ensimmäinen HotPDF-hahmontin teki juuri näin: se poisti osajoukon etuliitteen /BaseFont-nimestä (muuttaen nimen ABCDEF+Arial muotoon Arial), pyysi GDI:ltä samannimistä järjestelmäfonttia ja piirsi tekstin sen avulla. Dokumentissa, joka käyttää Arial- tai Times New Roman -fontteja vakiokoodauksella, tulos näyttää läheiseltä. Se on kuitenkin vain likiarvo, ja se rikkoutuu selkeissä tapauksissa
Upotetut osafontit ovat pahin tapaus. Osafontti saattaa sisältää vain ne neljäkymmentä glyyfiä, joita dokumentti todella käyttää, ja merkkikoodit on määritetty kyseisen tiedoston omassa järjestyksessä — koodi 1 voi olla "T", koodi 2 "h" ja niin edelleen. Järjestelmäfontti ei tiedä mitään tästä yksityisestä määrityksestä, joten teksti joko katoaa tai näkyy täysin väärinä merkkeinä. Mukautetut koodaukset, symbolifontit, viivakoodifontit ja kaikki fontit, joita ei ole asennettu hahmontavaan koneeseen, epäonnistuvat samalla tavalla. Hahmontin, joka tyytyy vain järjestelmäfonttien korvaamiseen, tuottaa pikkukuvia, jotka kyllä muistuttavat sivua — kunnes sivulla käytetään fontteja, joiden vuoksi upottaminen oli alun perin tarpeen
Upotettu glyyfihahemontaminen: piirtäminen itse fonttiohjelmasta
HotPDF kuroi tämän umpeen viiden julkaisun aikana (v2.268.0–v2.272.0) jäsentämällä upotetut fonttiohjelmat ja toistamalla niiden glyyfireunat täytettyinä GDI-vektoripolkuina. Hahmonnetun sivun teksti tulee nyt samoista reunaviivatiedoista, joita standardinmukainen katseluohjelma käyttää. Tämä tarkoittaa, että osafontit, mukautetut koodaukset ja asentamattomat fontit hahmontuvat tarkoilla muodoillaan. Kattavuus rakennettiin fonttityypin mukaan:
Type0/CIDFontType2-fonteille, joissa on upotettu TrueType-ohjelma (FontFile2), hahmontin jäsentää glyf- ja loca-taulukot suoraan: neliölliset ääriviivat muunnetaan GDI:n ymmärtämiksi kuutiollisiksi Bézier-käyriksi, peräkkäisten ohjauspisteiden väliset implisiittiset käyrällä olevat pisteet rekonstruoidaan ja yhdistelmäglyyfit toistetaan rekursiivisesti. Sekä Identity- että erilliset CIDToGIDMap-asettelut ovat tuettuja, ja CID-etenemät ottavat huomioon /W- ja /DW-leveysmerkinnät, jotta kaksitavuinen Identity-H-teksti etenee oikein
CFF-ohjelmat (FontFile3, oli kyseessä sitten CIDFontType0C, Type1C tai OpenType-kääre) saavat täydellisen Type 2 -merkkijonotulkin: viivat, käyrät, joustavat perheet, vihjemaskit sekä paikalliset/globaalit aliohjelmakutsut oikealla aliohjelmavirheellä (subroutine bias). CID-avainnetut CFF-ohjelmat kartoittavat merkkikoodit fontin merkistön (charset) kautta, mikä on tärkeää osafonteille, joiden glyyfirenkaiden järjestys eroaa CID-järjestyksestä. Myös glyyfilohkokohtainen fontti-DICT-valinta FDArray/FDSelect-taulukon kautta otetaan huomioon. Yksinkertaiset (ei-CID) TrueType-fontit selvittävät yksitavuiset koodit upotetun fontin oman cmap-taulukon kautta vankan alitaulukkoketjun avulla — ensin Unicode-muodot 4 ja 12, sitten symbolialitaulukot F000-yksityiskäyttöpeilillä ja lopuksi perinteiset Macintosh-muodot — kun taas yksinkertaiset Type1-fontit selvittyvät CFF-ohjelman sisäänrakennetun koodauksen kautta
Kaksi hienosäätöä täydentää kokonaisuuden. Ensinnäkin yksinkertaisten fonttien /Encoding-hakemistot selvitetään standardin ISO 32000-1 §9.6.6 määräämässä järjestyksessä: /Differences-taulukot ohittavat peruskoodauksen, joka taas ohittaa fonttiohjelman oman kartan — polku, josta TeX- ja PostScript-pohjaiset työkaluketjut riippuvat, ja glyyfinimet selvittyvät Adobe Glyph Listin, CFF-merkistön tai TrueType-cmap-taulukon kautta. Toiseksi Type3-fontit, joiden glyyfit ovat itsessään pieniä sisältövirtoja, toistetaan hahmontimen läpi yhdistetyllä fonttimatriisilla, fonttikoolla ja tekstikuvamatriisilla; glyyfi-avaruuden /Widths-arvot tulkitaan /FontMatrix-matriisin kautta, kuten ISO 32000-1 §9.6.5 vaatii, ja glyyfioperaatiot, jotka ilmoittavat d1-rajauslaatikon, rajataan siihen, jotta vioittunut viivakoodiglyyfi ei voi piirtää solunsa ulkopuolelle. Kun koodia ei voida kartoittaa — vioittunut ohjelma, kartoittamaton merkki — hahmontin turvautuu järjestelmäfontilla piirtämiseen kyseiselle glyyfille tekstiajon pudottamisen sijaan
Miten toistuvista hahmontamisista tehdään nopeita?
HotPDF:n tarjoama vastaus on viimeksi käytettyjen sivujen välimuisti: RenderLoadedPageToBitmapCached säilyttää jopa RenderCacheCapacity verran hahmonnettuja sivuja (oletus 8), jotka on indeksoitu sivunumeron ja DPI:n mukaan. Osuma välimuistiin palauttaa tuoreen, kutsujan omistaman kopion koskematta sisältövirtaan — tyypillisesti tuhansia kertoja nopeammin kuin sivun uudelleentulkinta. Tämä malli sopii täydellisesti katseluohjelmille: käyttäjä, joka vaihtaa kahden sivun välillä, tai koonmuutostapahtuma, joka pyytää samaa sivua samalla DPI:llä, osuu välimuistiin joka kerta
// Thumbnail strip: first pass renders, scrolling back hits the cache
for I := 0 to ThumbCount - 1 do
begin
Bmp := Pdf.RenderLoadedPageToBitmapCached(I, 48);
if Bmp <> nil then
try
ThumbList.AddThumbnail(I, Bmp);
finally
Bmp.Free;
end;
end;
// After editing a loaded page in place:
Pdf.InvalidateRenderedPageCache; // next render reflects the change
Ota huomioon muistinkulutus ennen kapasiteetin nostamista. US Letter -sivu 300 DPI:n tarkkuudella on kooltaan 2550×3300 pikseliä eli noin 25 megatavua 24-bittisenä bittikarttana, joten kahdeksan välimuistiin tallennettua sivua vientiresoluutiolla vie noin 200 megatavua. Pikkukuvatarkkuudella samat kahdeksan tietuetta maksavat reilusti alle megatavun. Aseta RenderCacheCapacity sen DPI:n mukaan, jota todella käytät välimuistissa, ja kutsu InvalidateRenderedPageCache-metodia minkä tahansa paikoillaan tehdyn muokkauksen jälkeen — välimuisti on avainnettu vain sivun ja DPI:n mukaan, eikä se voi havaita alla olevan sisällön muuttumista. Uuden dokumentin lataaminen tyhjentää sen automaattisesti
Toinen välimuisti toimii sivuvälimuistin alla: puretut kuva-XObjectit säilytetään tavubudjetoidussa tallennustilassa, jota rajoittaa ImageCacheMaxBytes (oletus 32 megatavua) ja josta poistetaan vähiten käytetyt kohteet. Jokaisella sivulla toistuva logo- tai kirjelomakekuva puretaan kerran dokumentin latausta kohden sen sijaan, että se purettaisiin jokaisen Do-operaattorin kohdalla. Tämä puolittaa hahmonnusajan ja nopeuttaa monisivuista TIFF-vientiä vastaavalla tavalla. InvalidateRenderedPageCache tyhjentää myös tämän välimuistin
Mikä hahmonnetaan edelleen likimääräisesti
Hahmontin on kohdistettu yleiseen dokumentti-PDF-osajoukoon, ja on hyödyllistä tietää, missä sen rajat kulkevat. CalRGB-, Lab- ja ICC-pohjaiset väriavaruudet käsitellään likimääräisesti ilman täyttä värihallintaa. Laitteen väriavaruudet, indeksoidut paletit ja näytteistetyt tyypin 0 värihakutaulukot ovat tuettuja, mutta painotuotantotiedosto, joka tukeutuu ICC-hahmonnustarkoituksiin, ei ole kolorimetrisety tarkka. Varjostuskuviot (sh) ja yksinkertaista alfa-kanavaa monimutkaisemmat sekoitustilat jäävät myös ulkopuolelle, ja Form XObject -rekursio on syvyysrajoitettu silmukkasuojana. Laskuille, raporteille, sopimuksille ja lomakkeille — eli teksteistä, poluista ja kuvista koostuville sivuille — tuloste on uskollinen; liukuvärejä ja läpinäkyvyysryhmiä täynnä olevalle suunnitteluvedokselle bittikarttaa tulee pitää esikatseluna, ei vedoksena
Käytännön tulkinta: jos sovelluksesi luo dokumentteja HotPDF-kirjastolla tai käsittelee tyypillisiä yritys-PDF-tiedostoja, RenderLoadedPageToBitmap toistaa ne tarkoilla upotetuilla glyyfin muodoilla, oikeilla CID-etenemillä ja oikealla sivun geometrialla. Likiarvoistukset elävät niissä grafiikkamallin kulmissa, joissa yritysasiakirjat vierailevat vain harvoin
RenderLoadedPageToBitmap, sen välimuistiin tallennettu muunnelma ja tässä kuvattu upotetun glyyfin hahmonnusputki toimitetaan osana HotPDF Component -kirjastoa Delphille ja C++Builderille — natiivi VCL-kirjasto ilman ulkoisia DLL-riippuvuuksia, joka kattaa PDF-luonnin, muokkauksen, tekstin purkamisen ja sivujen hahmontamisen samassa paketissa