PDFiumPas, Delphi- ja C++Builder-kääre Googlen PDFium-moottorin ympärille, tallentaa asiakirjan tarkalla PDF-versiolla 1.3:sta 1.7:ään TPdf.SaveAs-metodin PdfVersion-parametrin kautta. PDFiumin oma FPDF_SaveWithVersion-kutsu vain kirjoittaa uudelleen %PDF-M.m-otsikon, tarkistamatta, onko asiakirjan todellinen sisältö laillista tuolla versiolla. PDFiumPas sulkee tuon aukon tallennuksen jälkeisellä yhdenmukaisuuskierroksella, joka käy läpi aktiivisen ristiviittausrevisioketjun ja tarkistaa Adobe Extension Level -ilmoitukset ennen kuin tiedosto poistuu metodista
Tuo ero on merkityksellisin painotuotannossa, jossa PDF/X-profiili nimeää tarkan PDF-version, ja esitarkistustyökalu tai RIP hylkää mitä tahansa, mikä hiljaa on eri mieltä oman otsikkonsa kanssa, skenaario, joka käsitellään tulostepuolelta artikkelissa painovalmiiden PDF/X-asiakirjojen validointi PDFiumPas:lla. SaveAs paljastaa kohteen TPdfVersion-enumina, pv13:sta pv17:ään yhdessä vanhempien pv10–pv12-arvojen kanssa, plus itsenäisen TSaveOption-arvon inkrementaalisille tai täydellisille uudelleenkirjoituksille. Anna PdfVersion, ja PDFiumPas tekee kaksi työtä yhdessä kutsussa: se pyytää PDFiumia leimaamaan pyydetyn otsikon, sitten lukee juuri kirjoitetut tavut uudelleen ja kieltäytyy antamasta takaisin tiedostoa, jonka aktiivinen sisältö ei voi laillisesti olla olemassa tuolla versiolla
var
Pdf: TPdf;
begin
Pdf:= TPdf.Create(nil);
try
Pdf.FileName:= 'source.pdf';
Pdf.Active:= True;
try
Pdf.SaveAs('press-ready.pdf', saNoIncremental, pv17);
except
on E: Exception do
// E.Message names the offending feature and the version or
// extension level it actually needs, for example:
// "RichMedia annotations and RichMediaExecute actions require
// /Extensions /ADBE with /BaseVersion /1.7 and /ExtensionLevel 3
// or newer."
raise;
end;
finally
Pdf.Free;
end;
end;
Miksi tiedoston viimeinen olion määrittely on väärä asia luottaa?
Viimeinen fyysinen olio tietyllä numerolla PDF-tiedostossa ei välttämättä ole se olio, jonka standardinmukainen lukija ratkaisisi tuolle numerolle tänään. PDF, joka on käynyt läpi useita inkrementaalisia päivityksiä, ei kanna yhtä olio-kaaviota, se kantaa niiden historian kerrostettuna yhden tiedoston sisään, ja jokainen liityntäkierros voi vapauttaa olion, määritellä sen uudelleen uudella sukupolvinumerolla tai jättää sen vanhan fyysisen rungon istumaan kahden endobj-merkin väliin ilman että mikään ristiviittausmerkintä enää osoittaa siihen
PDFiumPas osui juuri tähän vikatilaan ennen kuin se seurasi xref-revisioita nimenomaisesti: myöhemmän sivu-olion uudelleenkirjoituksen orvoksi jättämä Redact-annotaatio, tai /MarkInfo-sanakirja, joka jäi fyysisesti läsnä olevaksi ilman xref-merkintää osoittamassa siihen, saattoi silti ilmestyä tavuskannauksessa ja silti laukaista versio-ominaisuustarkistuksen, joka ei enää päde asiakirjaan, jonka lukija todella avaisi. Vikasuunta oli väärä hylkäys, ei väärä hyväksyntä: tiedosto, joka oli aidosti siirtynyt ohi ominaisuudesta nykyisessä revisiossaan, saattoi silti jäädä estetyksi tallentumasta alempaan versioon sisällön vuoksi, jota kukaan ei enää voinut tavoittaa
Miten PDFiumPas määrittää, mitkä olion määrittelyt ovat todella aktiivisia?
PDFiumPas ratkaisee aktiivisen olio-joukon samalla tavalla kuin standardinmukainen lukija, käymällä läpi ristiviittausketjun tavujen skannaamisen sijaan olio-otsikoiden varalta. Ratkaisija aloittaa tiedoston viimeisestä startxref-siirtymästä ja seuraa jokaista /Prev-linkkiä taaksepäin vanhempien revisioiden läpi, jäsentäen klassisia ristiviittaustauluja, hybridi /XRefStm-linkitettyjä virtoja ja puhtaita ristiviittausvirtoja matkan varrella. Läpikäynti kulkee uusimmasta vanhimpaan ja asettaa jokaisen olionumeron ensimmäisellä kerralla, kun se nähdään, joten myöhemmän revision vapaa merkintä varjostaa oikein aiemmin kirjoitetun olion rungon, ja uudelleenmäärittely uudella siirtymällä tai sukupolvella voittaa aina sen, mitä se korvasi
Olio-virran jäsenet saavat ylimääräisen tarkistuksen, jota pelkkä siirtymähaku ei voi tarjota itsestään, mekanismi, joka käsitellään syvällisemmin artikkelissa olio- ja ristiviittausvirtojen validointi PDFiumPas:lla. /ObjStm:stä palautetun pakatun olion emovirran on oltava vahvistettu aktiiviseksi samassa läpikäynnissä, ja sen indeksin on täsmättävä jäsenen omaan sijaintiin tuon virran otsikon sisällä, ennen kuin PDFiumPas kohtelee sitä elävänä sisältönä. ISO 32000-1 osio 7.5.8.4 kuvaa jopa hybridiviittaustapauksen, jossa klassinen yhteensopivuustaulu merkitsee olion vapaaksi, samalla kun jäljen /XRefStm-merkintä samanaikaisesti määrittelee saman olion pakattuna jäsenenä muualla; PDFiumPas yhdistää täydentävän xref-virran samaan revisioon ennen kuin klassiset merkinnät sovelletaan, joten pakattu määrittely voittaa spesifikaation tarkoittamalla tavalla
Adobe Extension Level: portti version numeron yläpuolella
%PDF-1.7-otsikko lupaa vain ominaisuusjoukon, jonka ISO 32000-1 standardoi vuonna 2008, kun taas useat ominaisuudet, joihin PDF-tuottajat luottavat tänään, julkaistiin sen jälkeen Adobe-vain-lisäyksinä kerrostettuna saman version numeron päälle. Adobe rekisteröi jokaisen lisäyksen BaseVersion- ja ExtensionLevel-parina, tallennettuna asiakirjan katalogin /Extensions-sanakirjaan kehittäjän etuliitteen alla, ADBE Adoben omille laajennuksille, joten lukija voi erottaa tavallisen PDF 1.7 -tiedoston sellaisesta, joka myös toteuttaa numeroidun laajennustason. Tallentaminen pv17-versiolla ilman tuota ilmoitusta ei ole sinänsä virhe; siitä tulee sellainen vasta, kun aktiivinen sisältö todella riippuu ominaisuudesta, jota ilmoituksen on tarkoitus kattaa
Mitkä korkean version ominaisuudet laukaisevat nimenomaisen version portin?
PDFiumPas tarkistaa tietyn, spesifikaatiovetoisen listan sen sijaan, että arvaisi pelkästä version numerosta. Kuvasanakirjat, jotka kantavat nimenomaisen /SMaskInData-merkinnän tai /BitsPerComponent-arvon 16, molemmat vaativat PDF 1.5:n, kuusitoistabittisen tapauksen noudattaessa suoraan PDF Reference 1.5 -osion 4.8 kuvakomponenttisääntöjä. RichMedia-annotaatiot ja RichMediaExecute-toiminnot vaativat /BaseVersion /1.7:n ja /ExtensionLevel 3:n tai korkeamman. PRC 3D-virrat, tunnistettuina sanakirjasta, joka kantaa sekä /Type /3D- että /Subtype /PRC-merkinnät, vaativat saman perusversion mutta vain /ExtensionLevel 1:n. Geospatiaaliset Measure-sanakirjat ja Projection-annotaatiot vaativat /BaseVersion /1.7:n ja /ExtensionLevel 3:n, saman Adobe-lisäyksen, josta RichMedia riippuu
Geospatiaalinen tarkistus kantaa spesifikaation lukemiseen liittyvän yksityiskohdan, joka kannattaa tuntea, jos koskaan rakennat omaa versioportitettua logiikkaasi PDFiumPas:n päälle. ISO 32000-1 taulukko 254 merkitsee Measure-sanakirjan /Type-merkinnän valinnaiseksi, huomauttaen vain, että "jos läsnä, on oltava Measure", kun taas taulukko 311 tekee /Type:sta pakollisen 3D-virtasanakirjalle, jossa PRC-sisältö asuu. Todelliset karttatyökalujen GeoPDF-tulosteet jättävät rutiininomaisesti pois /Type-merkinnän Measure-sanakirjasta ja kirjoittavat vain /Subtype /GEO, joten PDFiumPas:n geospatiaalinen tunnistin täsmää vain /Subtype-arvoon sen sijaan, että vaatisi molempia avaimia samalla tavalla kuin sen PRC 3D -tunnistin turvallisesti voi. /Type-vaatimus molemmissa sanakirjoissa olisi päästänyt standardinmukaisen GeoPDF-sisällön luiskahtamaan portin ohi havaitsematta, päätyen tavalliseen PDF 1.7 -tiedostoon ilman laajennustasoilmoitusta sen tueksi
Alentaako PDFiumPas automaattisesti tukemattomia ominaisuuksia?
Ei yleisenä kykynä, ja tämän olettaminen on tässä vältettävä virhe. SaveAs ohjaa kohdeversion sisäisen rutiinin, ValidatePdfVersionCompliance, kautta, ja kun tuo rutiini löytää ominaisuuden, jota kohdeversio tai sen laajennustasoilmoitus ei voi tukea, SaveAs nostaa poikkeuksen, joka kantaa rutiinin virhetekstiä sen sijaan, että kirjoittaisi tiedoston; kutsuja saa tarkan, ominaisuuden nimeävän syyn takaisin, ei koskaan hiljaa uudelleenkirjoitettua asiakirjaa. Ainoa paikka, jossa PDFiumPas todella kirjoittaa sisältöä uudelleen automaattisesti, on PDF 1.3 -kohde, jossa se poistaa semanttisesti neutraalit /BM /Normal-, /CA 1- ja /ca 1-läpinäkyvyysoletukset, jotka PDFium aina kirjoittaa ExtGState-sanakirjoihin riippumatta kohdeversiosta, koska nuo tietyt arvot eivät kanna visuaalista merkitystä ja PDF 1.3 edeltää noita avaimia kokonaan
// PDF 1.3 targets rewrite the saved bytes to strip transparency
// defaults PDFium always emits, so incremental mode cannot apply
Pdf.SaveAs('legacy-archive.pdf', saIncremental, pv13);
// raises: PDF 1.3 normalization is incompatible with incremental
// save mode
Aito, ei-oletusarvoinen läpinäkyvyys ja kuvien pehmeät maskit epäonnistuvat silti suoralta kädeltä PDF 1.3 -kohteessa, koska niiden poistaminen muuttaisi sitä, miltä sivu todella näyttää, eikä PDFiumPas tee tuota päätöstä puolestasi. Kaksi liittyvää rajaa kannattaa suunnitella etukäteen ennen kuin tarkka versio menee eräputkeen. Nimenomaisen version tuloste ei koskaan kanna /Encrypt-sanakirjaa; tallennus epäonnistuu välittömästi, jos lähde on suojattu, mikä sattuu täsmäämään PDF/X- ja PDF/A-profiilien kanssa, jotka kieltävät salauksen joka tapauksessa, mutta se tarkoittaa, että salauksen purku on erillinen vaihe työnkulussasi eikä jotain, mitä SaveAs tekee puolestasi. PDFiumPas:lla ei myöskään ole julkista metodia /Extensions /ADBE-ilmoituksen kirjoittamiseen katalogiin, joten lähdetiedosto, joka sisältää RichMedia-, PRC 3D- tai geospatiaalista sisältöä mutta jolta puuttuu tuo ilmoitus, ei läpäise porttia riippumatta siitä, mitä PdfVersion-arvoa pyydät; ilmoituksen on jo oltava olemassa lähteessä, tyypillisesti koska laadintatyökalu kirjoitti sen, tai ominaisuuden on tultava pois ennen tallennusta. Vain luku -ominaisuus TPdf.PdfVersion kannattaa tarkistaa ennen kuin tarkkaa versiota edes yritetään tallentaa, koska se ratkaisee saman katalogitietoisen tehokkaan version, otsikko tai /Version-ylikirjoitus, kumpi tahansa on ajankohtainen, johon myös tallennusaikainen validaattori itse luottaa
Pdf.FileName:= 'incoming.pdf';
Pdf.Active:= True;
// PdfVersion resolves the same catalog-aware effective version the
// save-time validator uses, so a mismatch here is worth investigating
// before spending a full SaveAs attempt on it
LogSourceVersion('incoming.pdf', Pdf.PdfVersion);
Kohtele SaveAs-poikkeusta tarkan version kohteessa esitarkistusraporttina bugin sijaan: viesti nimeää tarkan lausekkeen, jota lähdeasiakirja rikkoo, mikä on juuri se tieto, jota painotalo tai arkistointiputki tarvitsee ennen kuin tiedosto menee pidemmälle. Nimenomaisen version tallennuspolku, aktiivinen xref-revisioratkaisija ja tässä kuvatut Adobe Extension Level -tarkistukset toimitetaan osana vakiomuotoista PDFiumPas-komponenttia Delphille ja C++Builderille; tuotesivulla on koko TPdf.SaveAs-viite yhdessä yhdenmukaisuus- ja lomake-API:n muun osan kanssa