PDFlibPas antaa Delphi- ja C++Builder-kehittäjille kolme toimintotyyppiä navigointiin, joka jättää nykyisen sivun taakse: GoToR (Go To Remote) avaa tietyn sivun toisesta PDF-tiedostosta, GoToE (Go To Embedded) avaa PDF-tiedoston, joka on upotettu nykyisen asiakirjan sisään, ja Launch ajaa ulkoisen ohjelman tai avaa tiedoston käyttöjärjestelmän kuoren kautta. Kaikki kolme asuvat ISO 32000-1 §12.6.4:ssä, Action Types -osiossa, joka myös määrittelee arkipäiväisen GoTo-toiminnon, ja jokainen niistä kantaa oman ansansa varomattomalle: sivunumero, joka tarkoittaa eri asiaa riippuen siitä, mikä kutsu sen rakentaa, kohde, joka on nimi eikä tiedostopolku, ja pari merkkijonoparametria, jotka näyttävät identtisiltä mutta palvelevat kahta eri katseluohjelmaa
Mikään tästä ei ole hypoteettista. Tekninen viitepaketti — pääkäsikirja, spesifikaatio-PDF, jota jälleenmyyjä päivittää omalla aikataulullaan, kalibrointityökalu asennettuna molempien rinnalle — nojaa juuri tällaiseen asiakirjojen väliseen kytkentään: ristiviittaus, jonka on osuttava spesifikaatiotiedoston sivulle 5, datalehti, joka kannattaa toimittaa käsikirjan sisällä sen vieressä olemisen sijaan, linkki, joka luovuttaa suoraan kalibrointityökaluun. Tämä artikkeli on peilikuva artikkelista kirjanmerkki- ja annotaatiotoimintojen lukeminen takaisin olemassa olevasta PDF:stä: tuo osa käsittelee GoToR-, Launch- tai GoToE-toiminnon kuluttamista, jonka joku muu tuottaja on jo kirjoittanut tiedostoon; tämä käsittelee samojen kolmen toimintotyypin rakentamista alusta, mukaan lukien kenttätason säännöt, joita PDFlibPas soveltaa ennen kuin se sitoo yhtäkään tavua
Kolme tapaa PDF-toiminnolle jättää nykyinen sivu
PDFlibPas erottaa paikallisen navigoinnin kaikesta muusta toiminnon /S-avaimella, ja GoToR, GoToE ja Launch ovat kolme alityyppiä, joiden kohde istuu nykyisen sivun ulkopuolella: GoToR ISO 32000-1 §12.6.4.3:n alla, GoToE §12.6.4.4:n alla, ja Launch §12.6.4.5:n alla, kaikki laajemman §12.6.4 Action Types -osion sisällä, joka myös määrittelee arkipäiväisen GoTo-toiminnon. Tavallisen GoTo-toiminnon kohde nimeää sivuolion, joka on jo olemassa asiakirjan sisällä, joten PDFlibPas voi validoida sen välittömästi; GoToR ja GoToE eivät voi tehdä sitä samalla tavalla, koska ulkoista tiedostoa ei ehkä ole edes olemassa tällä koneella, eikä upotetun tiedoston sivumäärä ole mitään, mitä isäntäasiakirja seuraa, joten molemmat kantavat ratkaisematonta viittausta kovan linkin sijaan — tiedostospesifikaatio plus kohde GoToR:lle, upotetun tiedoston nimi plus kohdesivu GoToE:lle — kun taas Launch pudottaa kohdekäsitteen kokonaan ja vain nimeää jotain, mitä käyttöjärjestelmä ajaa tai avaa. Tuo jako näkyy kahtena kutsuperheenä kirjoituspuolella: korkean tason, yhden kutsun rakentajat kuten AddLinkToFile, AddLinkToFileEx, AddLinkToEmbeddedPDF ja AddLinkToLocalFile luovat sivun kuumapistelinkkiannotaation ja sen toiminnon yhdessä, kattaen useimmat todelliset asettelut — tekstirivi tai kuvake, jota lukija klikkaa — kun taas matalamman tason asettajat kuten SetActionRemoteDestinationEx, SetActionLaunchOptions ja niiden AddActionNext*-vastineet kiinnittävät tai korvaavat toiminnon johonkin, jonka kahva sinulla jo on: olemassa oleva kirjanmerkki, lomakekenttälaukaisin, tai asiakirja- tai sivutason elinkaaritapahtuma. Molemmat perheet päätyvät kirjoittamaan samat sanakirjamuodot; ero on siinä, missä seisot kutsuessasi niitä, ja, kuten seuraava osio käsittelee, mitä sivunumero tarkoittaa silloin
Miten rakennat GoToR-linkin, joka avaa sivun toisesta PDF-tiedostosta?
GoToR-toiminto tarvitsee kaksi asiaa — tiedostospesifikaation ja kohteen tuon tiedoston sisällä — ja PDFlibPas paljastaa kaksi eri kutsua toisen osan toimittamiseen, kummallakin oma sivunumerointikäytäntönsä. AddLinkToFile ja AddLinkToFileEx, korkean tason sivun kuumapisterakentajat, validoivat Page- tai DestPage-argumenttinsa suurempana kuin nolla, saman 1-pohjaisen numeroinnin, jota PDFlibPas käyttää kaikkialla muualla, mukaan lukien SelectPage. SetActionRemoteDestinationEx, matalamman tason asettaja, jota käytetään kiinnittämään tai korvaamaan GoToR-toiminto jollekin, jonka kahva sinulla jo on, validoi sen sijaan DestPage:n suurempana tai yhtä suurena kuin nolla, ja kirjoittaa sen suoraan toiminnon nimenomaiseen kohdetaulukkoon ilman säätöä: se haluaa kohdeasiakirjan raa'an, nollapohjaisen sivuindeksin, numeroinnin, jonka ISO 32000-1 määrittelee etäiselle nimenomaiselle kohteelle. Kutsu matalan tason asettajaa samalla luvulla, jonka antaisit korkean tason rakentajalle, ja linkki avautuu yhden sivun liian aikaisin
var
Lib: TPDFlib;
ActionID: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('manual.pdf', '') = 1 then
begin
Lib.SelectPage(12);
// Page is 1-based here, same as SelectPage above: this opens
// the fifth page of specs.pdf.
Lib.AddLinkToFile(72, 700, 200, 16, 'specs.pdf', 5, 0, 0, 0);
// A later maintenance pass repoints the same link at a
// reorganized file. SetActionRemoteDestinationEx edits the
// action directly, and DestPage here is the zero-based index
// PDF itself uses for a remote explicit destination -- "the
// fifth page" is now 4, not 5.
ActionID := Lib.GetAnnotActionID(1);
Lib.SetActionRemoteDestinationEx(ActionID, 'specs-2026.pdf',
4, Ord(dkFit), 0, 0, 0, 0, 0, 0, -1);
end;
finally
Lib.Free;
end;
end;
SetActionRemoteDestinationEx:n loput argumentit ovat yhtä kirjaimellisia. ValueMask on bittijoukko — 1 vasemmalle, 2 yläreunalle, 4 oikealle, 8 alareunalle, 16 zoomille — ja PDFlibPas tarkistaa sen DestType:ä vasten ennen minkään kirjoittamista: dkFitR-kohteen on toimitettava täsmälleen 15 (kaikki neljä reunaa, ei zoomia), dkFit:n ja dkFitB:n on toimitettava 0, ja dkFitH/dkFitV hyväksyvät vain yhden relevantin koordinaattinsa. Bitit, jotka jätät asettamatta muuten pätevän maskin sisällä, eivät jää pois taulukosta; ne kirjoitetaan nimenomaisena PDF-null-arvona, minkä ISO 32000-1 tulkitsee "pidä mikä tahansa arvo, joka katseluohjelmalla jo on" tuolle koordinaatille — laillinen tapa sanoa "hyppää tälle sivulle, jätä zoomaus rauhaan" eikä unohdus. Zoom itse tallennetaan murto-osana antamastasi arvosta, joten kutsu, joka pyytää 150 prosenttia, antaa taulukolle tallennetun arvon 1.5, ja pätevä syöttöalue on 0–6400
Miten linkität PDF:ään, joka on upotettu omaan asiakirjaasi?
AddLinkToEmbeddedPDF rakentaa GoToE-toiminnon, ja sen kohdeargumentti, EmbeddedFileName, on nimi eikä polku: sen on täsmättävä Title-merkkijonoon, joka jo välitettiin EmbedFile:lle, kun liite tehtiin, koska tuo otsikko on kirjaimellinen avain, jonka PDFlibPas tallentaa asiakirjan /EmbeddedFiles-nimipuuhun, ja GoToE ratkaisee etsimällä tuota nimeä, ei koskettamalla tiedostojärjestelmää uudelleen. Funktio vain tarkistaa, että EmbeddedFileName ei ole tyhjä ja TargetPage on vähintään 1 — anna nimi, jota ei koskaan todella upotettu, ja kutsu silti palauttaa onnistumisen, toiminto silti kirjoitetaan, ja linkki yksinkertaisesti epäonnistuu ratkeamaan jokaiselle lukijalle, joka klikkaa sitä
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.NewDocument;
Lib.NewPage;
// The Title argument becomes the key PDFlibPas stores in the
// document's EmbeddedFiles name tree -- that string, not
// "datasheet.pdf", is the target GoToE resolves against.
if Lib.EmbedFile('Datasheet', 'datasheet.pdf', 'application/pdf') = 1 then
Lib.AddLinkToEmbeddedPDF(72, 700, 200, 16, 'Datasheet', 3, 0, 0);
Lib.SaveToFile('manual.pdf');
finally
Lib.Free;
end;
end;
Tässä pinoutuu kaksi versiolattiaa, ei yksi. EmbedFile tarvitsee PDF 1.4:n /EmbeddedFiles-nimipuulle, ja AddLinkToEmbeddedPDF nostaa erikseen lattian PDF 1.6:een itse GoToE-toimintotyypille, joten tehokas minimi mille tahansa asiakirjalle, joka käyttää tätä ominaisuutta, on 1.6, ei 1.4. Huomaa myös, että TargetPage täällä on 1-pohjainen, tavallinen PDFlibPas-käytäntö — tarkoituksellinen kontrasti nollapohjaiselle DestPage:lle, jonka edellinen osio juuri käsitteli, ja muistutus siitä, että mikä sivunumerointijärjestelmä pätee, riippuu toimintotyypistä ja tietystä kutsusta, ei yhdestä kattavasta säännöstä. Toiminnon kohdesanakirja voi myös kantaa /R-merkinnän arvolla C lapselle tai P vanhemmalle, tukien kahden hypyn ketjua upotettuun tiedostoon tai takaisin ulos sen säiliöön, vaikka AddLinkToEmbeddedPDF rakentaa vain koskaan lapsisuunnan, koska se on se, joka on järkevä asiakirjalle, joka tekee upotuksen eikä ole upotettava
Launch-toiminnot: yksi FileName, kaksi merkkijonokohdetta, jotka eivät ole vaihdettavissa
SetActionLaunchOptions kirjoittaa Launch-toiminnon tiedostokohteen kahteen eri avaimeen yhdestä FileName-argumentista, ja nuo kaksi avainta kantavat kahdenlaista merkkijonoa. Ylimmän tason /F-avain saa tiedostospesifikaatiosanakirjan, rakennettuna saman polunmuunnoksen kautta, jota PDFlibPas käyttää GoToR:lle, mikä on siirrettävä muoto, jonka ISO 32000-1 §7.11.3 määrittelee tiedostospesifikaatiosanakirjalle. /Win-alisanakirja, kun PDFlibPas kirjoittaa sellaisen, saa oman /F-avaimensa asetettuna raakaan FileName-arvoon täsmälleen sellaisena kuin se välitettiin, ilman minkäänlaista muunnosta, koska /Win /F on dokumentoitu ISO 32000-1 §12.6.4.5:ssä tavallisena Windows-polkumerkkijonona, joka on tarkoitettu vain Windows-katseluohjelman luettavaksi. Anna siirrettävä, jo muunnettu polku odottaen molempien avainten päätyvän identtisiksi, ja /Win-kopio kantaa mitä tahansa, minkä annoit funktiolle, koskemattomana
var
Lib: TPDFlib;
ActionID: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('manual.pdf', '') = 1 then
begin
Lib.SelectPage(1);
Lib.AddLinkToLocalFile(72, 660, 220, 16, 'calibrate.exe', 0);
ActionID := Lib.GetAnnotActionID(1);
// Operation 0 leaves this as a normal open -- pass 1 to ask a
// Windows viewer to print instead. Parameters and
// DefaultDirectory only ever reach /Win /P and /Win /D, never
// the top-level /F.
Lib.SetActionLaunchOptions(ActionID, 'calibrate.exe',
'/silent /profile:default', 'C:\Tools\Calibration', 0, -1);
end;
finally
Lib.Free;
end;
end;
Kohtele Launchia näistä kolmesta korkeimman kitkan toimintona, koska sen koko tarkoitus on ohjelman ajaminen tai tiedoston avaaminen PDF-hiekkalaatikon ulkopuolella, ja jokainen valtavirran katseluohjelma kohtelee sitä sen mukaisesti. Adobe Acrobatin Enhanced Security estää tai kysyy Launch-toimista oletuksena, ellei kohde istu nimenomaisesti luotetussa sijainnissa, ja useimmat yritys-Acrobat-käyttöönotot jättävät tuon suojan päälle. Launch-toiminto julkisuudelle annetussa asiakirjassa ei siis ole luotettava laukaisin: suunnittele sen olevan estetty, kysytty tai hiljaa ohitettu millä tahansa katseluohjelmalla, joka avaa tiedoston, ja säästä se suljetuille ympäristöille, joissa myös hallitset katseluohjelman luottamusasetuksia — sisäinen kioski, hallittu yritysjakelu, asiakirja, joka ei koskaan poistu koneelta, jota hallinnoit
PDF/A-portti: miksi GoToR- ja Launch-kutsut voivat palauttaa nollan
SetActionRemoteDestinationEx ja SetActionLaunchOptions kieltäytyvät molemmat suoralta kädeltä, kun kohdeasiakirja on missä tahansa PDF/A-yhdenmukaisuustilassa: molemmat tarkistavat asiakirjan PDF/A-tilan ensimmäisenä ehtonaan ja poistuvat tuloksella 0 ennen kuin koskettavat toimintoa, ilman poikkeuksen nostamista. Tämä on tarkoituksellista. PDF/A:n rajoitukset interaktiivisille toiminnoille sulkevat pois nimenomaan Launchin, koska arkistointitiedoston varustaminen kyvyllä ajaa mielivaltainen ohjelma on juuri sellaista ympäristöriippuvaista käytöstä, jota pitkän aikavälin arkistointimuodot ovat olemassa estämään, ja PDFlibPas soveltaa samaa konservatiivista porttia etäsiirtoasettajaan samassa koodipolussa. Käytännön seuraus on helppo ohittaa kehityksen aikana: identtinen kutsu, joka toimii tavallisessa PDF:ssä, kääntyy, ajautuu ja hiljaa ei tee mitään asiakirjassa, joka on ladattu PDF/A-yhdenmukaisuustaso asetettuna, joten tarkista paluuarvo sen sijaan, että oletat onnistumisen — 0 täällä ei ole virheellisen syötteen virhe, se on kirjaston kieltäytyminen pyynnöstä, joka on ristiriidassa asiakirjan oman yhdenmukaisuusväitteen kanssa
Mihin GoToR, GoToE ja Launch sopivat laajemmassa PDFlibPas-työnkulussa
Tämän artikkelin kolme toimintotyyppiä eivät kaikki ulotu samoihin paikkoihin. Rinnakkaisartikkeli asiakirja- ja sivutason elinkaaritoimintolaukaisimista käsittelee SetDocumentAction- ja SetPageAction-metodeja, jotka voivat kiinnittää GoToR- tai Launch-toiminnon laukaisimeen kuten WillClose jaetun PDF_ACTION_BUILDER_REMOTE_DESTINATION- ja PDF_ACTION_BUILDER_LAUNCH-vakioiden kautta — sama rakentaja, joka myös kattaa tavallisen URI- tai JavaScript-laukaisimen. GoToE:lla ei ole tällaista vakiota eikä lainkaan polkua tuohon geneeriseen rakentajaan; AddLinkToEmbeddedPDF on ainoa tapa, jolla PDFlibPas rakentaa sellaisen, mikä tekee siitä tiukasti sivun kuumapistetoiminnon, ei koskaan asiakirja- tai sivutason laukaisinta. Missä GoToR ja Launch todella ulottuvat geneeriseen rakentajaan, kompromissi on hallinta: se rakentaa GoToR:n, joka osoittaa vain nimettyyn etäkohteeseen, ja Launch-toiminnon, jolla on vain tiedostonimi ja parametrit, kun taas nimenomainen sivu-ja-sovitustyyppi-osoitus ja Windows-spesifiset käynnistysasetukset, jotka tässä artikkelissa käsitellään, tavoitetaan vain suoraan SetActionRemoteDestinationEx- ja SetActionLaunchOptions-funktioiden kautta
Yksi turvallisuusominaisuus kannattaa tuntea ennen ylläpitotyökalun rakentamista näiden asettajien ympärille. SetActionRemoteDestinationEx ja SetActionLaunchOptions rakentavat koko korvaavan toiminnon ensin luonnossanakirjaan, ja poistavat ja kopioivat /F-, /D- tai /Win- ja /NewWindow-avaimet elävään toimintoon vasta, kun tuo luonnoskopio validoituu — joten kutsu, joka epäonnistuu validoinnissa, olipa kyse alueen ulkopuolisesta ValueMask:sta tai tyhjästä FileName:sta, jättää alkuperäisen toiminnon, ja minkä tahansa /Next-ketjun, joka siihen jo roikkuu, täysin koskemattomaksi puoliksi ylikirjoitetun sijaan. Se on merkityksellistä, koska sekä GoToR- että Launch-toiminnot voivat istua /Next-ketjun sisällä, joka on rakennettu AddActionNextRemoteDestinationEx-, AddActionNextLaunchEx- tai yleisemmällä AddActionNextEx-funktiolla, antaen yhden laukaisimen laukaista JavaScript-lokimerkinnän ja sitten etähypyn peräkkäin. GoToR:n, GoToE:n ja Launchin rakentaminen tässä kuvatulla tavalla on osa PDFlibPas:aa, natiivia PDF-kirjastoa Delphille ja C++Builderille