Tekninen artikkeli

PDF:n looginen objektimalli: Tyypit, viittaukset ja rakenne

PDF-tiedosto on sisimmältään joukko objekteja, jotka osoittavat toisiinsa. Jos poistat pakkauksen, ristiviittausten kirjanpidon ja tavusiirtymät, jäljelle jää kaavio: pieni joukko tyypitettyjä arvoja, jotka on kytketty yhteen viittauksilla ja jotka juurtuvat yhteen objektiin, jonka lukija osaa löytää. Kaikki, mitä PDF voi ilmaista, tekstikappaleesta upotettuun fonttiin ja digitaaliseen allekirjoitukseen, rakentuu kahdeksasta primitiivisestä objektityypistä ja säännöstä, joka antaa yhden objektin viitata toiseen. Opi nämä, ja loppuformaatti on luettavissa ennemmin sommitteluna kuin mysteerinä

Tämä on PDF:n looginen kerros, joka on määritelty standardin ISO 32000-1 kohdassa 7.3, ja se sijaitsee yhden tason fyysisen tiedostoasettelun yläpuolella (otsikko, runko, ristiviittaustaulukko ja traileri, joka on oma aiheensa artikkelissa PDF-tiedoston rakenteen tekninen yleiskatsaus). Looginen malli on sitä, mitä nuo tavut tarkoittavat, kun ne on jäsennetty. Katseluohjelma lukee tiedostoa taaksepäin löytääkseen trailerin, seuraa sitä juureen, ja sieltä alkaen asiakirja avautuu objekteina, jotka viittaavat objekteihin. Tätä osaa mietit, kun selvität virheellistä sivua, kirjoitat jäsennintä tai luotat kirjaston kokoavan asiakirjan

Kahdeksan objektityyppiä, eikä mitään muuta

PDF määrittelee täsmälleen kahdeksan perusobjektityyppiä. Jokainen asiakirjan arvo on yksi niistä, mikä pitää muodon käsiteltävänä sen laajuudesta huolimatta

PDF-korttiruudukko kahdeksasta PDF-objektityypistä näytteisyntakseilla totuusarvolle, numerolle, merkkijonolle, nimelle, taulukolle, sanakirjalle, virralle ja nollalle
Kahdeksan primitiivityyppiä muodostavat koko PDF:n arvojen sanaston; sanakirja tekee rakenteellisen raskaan työn, kun taas streamit kantavat massiivisen pakatun payloadin

Totuusarvot ovat avainsanat true ja false. Ne kytkevät lippuja päälle ja pois, kuten esimerkiksi sen, tulostetaanko huomautus

Numeroita on kahta laatua, joita määritys käsittelee yhtenä tyyppinä: kokonaislukuja, kuten 42, ja reaalilukuja, kuten 3.14 tai -0.002. PDF:ssä ei ole eksponenttimerkintää, joten et koskaan näe arvoa 1e6 määritysten mukaisessa tiedostossa. Koordinaatit, fonttikoot ja kiertokulmat ovat kaikki numeroita

Merkkijonot sisältävät tavusekvenssejä, jotka on kirjoitettu joko sulkeisiin, (Hello), tai kulmasulkeisiin heksadesimaaleina, <48656C6C6F>. Molemmat merkintätavat koodaavat saman sisällön; heksadesimaali on pakotie tavuille, jotka ovat hankalia sulkeiden sisällä. Merkkijonot kuljettavat tekstiä, mutta ne ovat ensisijaisesti tavuja, millä on merkitystä sillä hetkellä, kun käsittelet mitään ASCII:n ulkopuolella

Nimet ovat jakamattomia merkkejä, jotka esitellään kauttaviivalla: /Type, /Pages, /MediaBox. Nimi ei ole merkkijono; se on tunniste, jota käytetään sanakirjan avaimena tai lueteltuna arvona, ja kaksi nimeä ovat yhtä suuret vain, jos ne vastaavat toisiaan tavu tavulta. Kauttaviiva on syntaksia, ei osa nimeä. Tämä kompastuttaa tulokkaita, jotka käsittelevät arvoja /Times-Roman ja merkkijonoa (Times-Roman) keskenään vaihdettavina; muoto ei niin tee

Taulukot ovat järjestettyjä, heterogeenisia luetteloita hakasulkeissa: [0 0 612 792] on sivun suorakulmio, ja taulukko voi sekoittaa tyyppejä vapaasti, mukaan lukien viittaukset muihin objekteihin. Sanakirjat ovat työjuhtia. Sanakirja, joka on kirjoitettu merkkien << ja >> väliin, yhdistää nimiavaimet minkä tahansa tyyppisiin arvoihin, ja lähes jokainen mielekäs rakenne PDF:ssä, sivu, hakemisto, fontti, huomautus, on sanakirja, jossa /Type-avain kertoo, mikä se on

Virrat ovat sanakirjoja, joiden perässä on raakatavuja avainsanojen stream ja endstream välissä. Sanakirja kuvailee tavuja (niiden pituuden ja mahdolliset suodattimet, kuten FlateDecode, jotka pakkaavat ne), ja tavut kuljettavat tilaa vievää hyötykuormaa: sivun sisällön ohjeita, upotettuja fonttiohjelmia, kuvia. Virta on paikka, johon PDF laittaa kaiken, mikä on liian suurta tai liian binääristä ollakseen linjassa

Kahdeksas tyyppi on null-objekti, avainsana null. Se on todellinen arvo, joka eroaa avaimen puuttumisesta. Sanakirjan merkintää, joka on asetettu null-tilaan, käsitellään ikään kuin sitä ei olisi olemassa, ja viittaus, joka ratkeaa olemattomaan objektiin, tuottaa myös arvon null virheen sijaan. Tämä anteeksiantava käyttäytyminen on tarkoituksellista: se antaa vaurioituneen tiedoston heikentyä sen sijaan, että se kieltäytyisi avautumasta. Yhdeksättä tyyppiä ei ole; kaikki, mitä PDF ilmaisee, syntyy näiden kahdeksan yhdistelmästä

Suorat arvot, epäsuorat objektit ja viittaukset

Mikä tahansa noista kahdeksasta tyypistä voi esiintyä kahdella tavalla. Suora objekti on kirjoitettu paikoilleen, kuten 612 MediaBox-taulukon sisällä. Epäsuoralle objektille annetaan identiteetti, jotta muut objektit voivat osoittaa siihen: kaksi kokonaislukua, objektinumero ja generaationumero, käärien määritelmän tunnisteiden obj ja endobj sisään:

12 0 obj
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
endobj

Tämä on objekti 12, generaatio 0, fonttisanakirja. Missä tahansa muualla tiedostossa toinen objekti viittaa siihen epäsuoralla viittauksella: samat kaksi numeroa, joita seuraa avainsana R, 12 0 R. Viittaus on osoitin. Kun sivun resurssisanakirja sanoo /Font << /F1 12 0 R >>, se nimeää objektin 12 fontiksi resurssinimen /F1 takana, kopioimatta fontin määritelmää sivulle

Generaationumero on olemassa poistoja ja uudelleenkäyttöä varten. Kun objekti vapautetaan ja sen paikka käytetään uudelleen, generaatio kasvaa, jotta vanhentunut 12 0 R ei voi viitata paikan 12 uuteen vuokralaiseen. Vasta kirjoitetut tiedostot ovat lähes kaikki generaatiota 0, mutta voimakkaasti muokattu tiedosto voi sisältää suurempia numeroita, ja jäsennin, joka jättää generaation huomiotta, lukee lopulta väärän objektin

Epäsuoruus tekee PDF:stä tehokkaan ja muokattavan. Yksi fontti, kuva tai väriavaruus voidaan määritellä kerran ja siihen voidaan viitata sadalta sivulta. Pieni muutos voidaan liittää uutena versiona, joka korvaa yksittäisen objektin koko tiedoston uudelleenkirjoittamisen sijaan. Ristiviittaustaulukko on hakemisto, joka muuttaa objektinumeron tavusiirtymäksi, joten lukija hyppää suoraan objektiin 12 0 obj ilman skannausta, mutta se on fyysinen optimointi. Loogisesti ainoa asia, joka sinun tarvitsee tietää, on se, että 12 0 R tarkoittaa "objektia, jonka tunniste on 12 0"

Hakemisto: mistä jokainen asiakirja alkaa

Viittausten ratkaisemisen on alettava jostain, ja tuo jokin paikka on trailerin /Root-merkintä, joka osoittaa asiakirjahakemistoon: objektikaavion juureen, sanakirjaan, jossa on /Type /Catalog. Lukija saavuttaa sen ensimmäisenä, koska traileri löytyy ensimmäisenä, ja sieltä käsin kaikki asiakirjan muut osat ovat saavutettavissa seuraamalla viittauksia

PDF-anatomia PDF-epäsuorasta viittauksesta, joka näyttää fonttiobjektin kaksitoista määriteltynä kerran ja saavutettavan sivun resurssisanakirjasta 12 0 R -merkinnän kautta
Objekti saa identiteettinsä objekti- ja generaatiolukujensa kautta, ja kuluttajat tavoittavat sen siellä missä tarpeen kirjoittamalla vastaavan R-viittauksen kopion sijaan

Hakemisto sisältää vain kaksi ehdottomasti vaadittua merkintää: sen /Type-arvon ja /Pages-arvon, joka on epäsuora viittaus sivupuun juureen. Loput ovat valinnaisia ja kuvaavat asiakirjan laajuista käyttäytymistä sisällön sijaan: /Outlines osoittaa kirjanmerkkipuuhun, /Names sisältää merkkijonolla avainnettuja nimipuita, /Metadata viittaa XMP-metadatavirtaan, ja /PageMode sekä /PageLayout ehdottavat, kuinka katseluohjelman tulisi avata asiakirja. Mitään niistä ei tarvita sivun renderöintiin; ne konfiguroivat sivujen ympärillä olevaa kokemusta. Hakemistosta roikkuvat kirjanmerkki-, metadata- ja huomautusrakenteet on käsitelty artikkelissa PDF:n metadata, kirjanmerkit ja huomautukset

Alla oleva kaavio näyttää, missä objektin runko sijaitsee ympäröivässä tiedostossa. Hakemisto ja sivupuu elävät tuon rungon sisällä tavallisina epäsuorina objekteina; otsikko, ristiviittaustaulukko ja traileri niiden ympärillä ovat fyysinen tukirakenne, jonka avulla lukija voi paikantaa ne

Kaavio PDF-tiedoston neljästä fyysisestä osasta: versio-otsikko, runko, joka kantaa asiakirjan objektit mukaan lukien katalogi ja sivupuu, objektien siirtymien ristiviittaustaulu ja traileri, joka osoittaa juureen

Sivupuu: sivujen tasapainoinen hierarkia

/Pages-kohdasta asiakirja haarautuu sivupuuhun, missä PDF:n valinta käyttää kaaviota litteän luettelon sijaan palkitsee. Sivuja ei tallenneta yksinkertaisena sarjana; ne roikkuvat puussa, jonka sisäiset solmut ovat sivupuusolmuja (/Type /Pages) ja jonka lehdet ovat sivuobjekteja (/Type /Page). Sisäinen solmu luettelee lapsensa /Kids-taulukossa ja tallentaa /Count-avainta käyttäen tiedon siitä, kuinka monta lehtisivua sen alapuolella on. Jokaiseen solmuun juurta lukuun ottamatta sisältyy /Parent-viittaus ylöspäin, joten puuta voi käydä läpi kumpaan tahansa suuntaan

2 0 obj                                  % sivupuun juuri
<< /Type /Pages /Kids [3 0 R 4 0 R] /Count 3 >>
endobj

3 0 obj                                  % lehtisivu
<< /Type /Page /Parent 2 0 R
   /MediaBox [0 0 612 792]
   /Resources << /Font << /F1 12 0 R >> >>
   /Contents 5 0 R >>
endobj

4 0 obj                                  % sisäinen solmu, joka ryhmittelee kaksi muuta sivua
<< /Type /Pages /Parent 2 0 R /Kids [6 0 R 7 0 R] /Count 2 >>
endobj

Tässä objekti 2 on juuri, ja sen alla on kolme sivua: lehtisivu 3 sekä kaksi muuta, jotka ovat saavutettavissa sisäisen solmun 4 kautta. Juuren /Count-arvon 3 on oltava yhtä suuri kuin sen alla olevien lehtien kokonaismäärä, ja määrä, joka on ristiriidassa todellisen rakenteen kanssa, on yleinen syy siihen, että käsin muokattu tiedosto menee pieleen. Puun tarkoitus on pääsyn paikallisuus. Lukija avatessaan tuhatsivuisen asiakirjan sivun 900 ei käy läpi 900 objektia; se laskeutuu kourallisen solmuja, koska oikein muotoiltu puu pysyy matalana ja tasapainoisena. Tällaisen puun rakentaminen käsin on tarpeeksi pikkutarkkaa, jotta sen näkeminen alusta loppuun on vaivan arvoista, minkä vuoksi läpikäynti artikkelissa PDF-asiakirjan rakentaminen alusta pitäen tekeekin juuri niin

Puu ansaitsee paikkansa myös perinnän ansiosta. Kourallinen sivuattribuutteja, /Resources, /MediaBox, /CropBox ja /Rotate, voidaan asettaa sisäiseen solmuun ja jättää pois yksittäisiltä sivuilta, jotka sitten perivät lähimmän esi-isän arvon. Aseta /MediaBox kerran juureen, ja jokainen lehti saa saman sivukoon ilman toistoa; sivu, jonka täytyy erota, ilmoittaa oman kokonsa. Tämä on se yksi paikka objektimallissa, jossa arvon merkitys riippuu objektin sijainnista puussa, ei pelkästään sen omasta sisällöstä

Mitä lehtisivu todella sisältää

Sivuobjekti on liitoskohta rakennemallin ja näkyvän sisällön välillä. Sen /Contents-merkintä viittaa yhteen tai useampaan sisältövirtaan, eli piirto-operaattoreihin, jotka maalaavat tekstiä ja grafiikkaa sivulle. Sen /Resources-sanakirja nimeää fontit, kuvat ja väriavaruudet, joihin nuo operaattorit tukeutuvat, jokaisen merkinnän ollessa epäsuora viittaus sivujen kesken jaettuun objektiin. /MediaBox antaa sivun suorakulmion pisteinä (1/72 tuumaa), ja merkinnät kuten /Rotate ja /CropBox säätävät sitä, kuinka se esitetään

Työnjako on koko malli pienoiskoossa. Sivusanakirja on rakenne: tyypitettyjä merkintöjä ja viittauksia, jotka kertovat, mikä sivu on ja millä se piirtää. Sisältövirta on ohjeita: erillinen, pakattava möykky, joka kertoo, kuinka piirtää. Fontti /F1:n takana on jaettu resurssi, joka on määritelty kerran ja johon osoitetaan kaikkialta, missä sitä käytetään. Sanakirja, virta ja viittaus tekevät yhteistyötä renderöidäkseen yhden sivun, ja samat kuviot skaalautuvat koko asiakirjaan. Tämän möykyn sisällä olevat sisältövirtakomento-operaattorit on käsitelty erikseen artikkeleissa tekstistä ja fonteista sekä grafiikasta ja visuaalisista elementeistä

PDF-kaavio PDF-sivupuusta juurisivujen solmulla, sisäisellä solmulla, lehtisivuilla, jotka kantavat vanhempien viittauksia, ja linkeillä sisältövirtaan ja jaettuihin fonttoresursseihin
Lehtisivut viittaavat vanhempaan, sisältövirtaan ja jaettuihin resursseihin, kun taas juuri seuraa kokonaismääriä /Count-kentässä ja voi periyttää attribuutteja, kuten /MediaBox, jokaiselle jälkeläiselle

Miksi tämä malli on tuntemisen arvoinen

Useimmat kehittäjät kohtaavat objektimallin vasta, kun jokin menee rikki: sivu renderöityy tyhjänä, koska sen /Contents-viittaus roikkuu irrallaan, teksti näkyy laatikkoina, koska fonttiresurssia ei koskaan upotettu, työkalu ilmoittaa /Count-arvoksi sellaisen, joka ei vastaa sen löytämiä sivuja. Jokainen näistä on väittämä kaaviosta, ja kaavion lukeminen suoraan voittaa arvaamisen. Kahdeksan tyyppiä ja viittaussääntö muodostavat riittävän pienen sanaston, jotta sen voi pitää päässään, ja kun kerran näet PDF:n objekteina, jotka osoittavat objekteihin, vialliset tiedostot lakkaavat olemasta läpinäkymättömiä

Tästä huolimatta mallin kirjoittaminen käsin on harvoin oikea valinta oppimisen ulkopuolella. Ristiviittausten siirtymien, generaationumeroiden, sivupuun laskurien ja virran pituuksien pitäminen johdonmukaisina muokkauksien yli on juuri sellaista kirjanpitoa, jota kirjasto on olemassa hoitaakseen. Tuotannossa kypsä PDF-kehityskirjasto hallitsee objektikaaviota ja antaa sinun ajatella sivuina ja sisältönä. Mallin tunteminen palkitsee silti: ymmärrät, mitä kirjasto rakentaa konepellin alla, ja miksi