Transaktiotulostamo palauttaa 80 000-sivuisen tilioteajosi lyhyellä hylkäysviestillä: "ei ole PDF/VT, RIP ei voi välimuistittaa". Tiedosto avautuu hienosti kaikilla työpöytäsi katseluohjelmilla, värit ovat oikein ja tiedot yhdistyivät virheettömästi. Digitaalinen painokone ei kuitenkaan pyytänyt mitään näistä. Suuren nopeuden muuttuvan tiedon tulostus (VDP) elää ja kuolee sen mukaan, kykeneekö painokone tunnistamaan sivulla 1 olevan asiakaslogon tavulleen samaksi objektiksi kuin sivulla 40 000 oleva logo, renderöimään sen kerran ja käyttämään sitä uudelleen. PDF/VT on standardi, joka tekee tästä lupauksesta konetarkistettavan, ja "näyttää oikealta" on juuri se sudenkuoppa, sillä RIP-laitteen lukema rakenne on näytöllä näkymätön
PDFiumPas tuo tämän rakenteen näkyville TPdf-luokan pienen rajapinnan kautta: SaveAsPdfVT kirjoittaa sen ja ValidatePdfVT tarkistaa sen. Tämä artikkeli käsittelee sitä, mitä nämä kaksi metodia todellisuudessa kirjoittavat levylle ja tutkivat, missä suhteessa ISO 16612-2 on tiukempi kuin miltä se aluksi vaikuttaa, ja mitkä osat ovat todellisia rakenteellisia ankkureita täyden esitarkastuksen (preflight) sijaan, josta voisit laskuttaa asiakasta
Mitä PDF/VT standardoi ja miksi PDF/X on ensisijainen
PDF/VT (ISO 16612-2:2010) ei ole uusi tiedostomuoto. Se on PDF/X-tiedoston päälle pultattu optimointimetatietokerros, ja tämä järjestys on kriittinen. Standardi määrittelee kolme yhteensopivuustasoa, mutta vain kaksi niistä viittaa PDF-tiedostoon: PDF/VT-1, joka on yksittäinen itsenäinen asiakirja, ja PDF/VT-2, joka on tiedostojoukkomalli (file-set model), jossa sivut viittaavat jaettuihin ulkoisiin resursseihin. Kolmas termi, jonka saatat kohdata, PDF/VT-2s, ei ole lainkaan tiedostotason arvo; se elää liitteessä Annex A kuvatussa MIME-virtaotsikossa. Jos löydät koodia, joka leimaa arvon GTS_PDFVTVersion = "PDF/VT-2s" asiakirjan XMP-tietoihin, tuo koodi on virheellistä
Yksittäisen tiedoston ehdoton sääntö on PDF/X-perusta. ISO 16612-2 §6.2.1 vaatii jokaisen PDF/VT-1-tiedoston olevan myös validi PDF/X-4-tiedosto. PDF/VT-2-tiedostojoukon on puolestaan pykälän §6.2.2 mukaan perustuttava tasoille PDF/X-4p, PDF/X-5g tai PDF/X-5pg. Siksi PDF/VT-kirjoittaja ei voi vain lisätä paria tunnistusavainta: sen on tuotava mukanaan koko PDF/X-4-merkintäsarja, mikä tarkoittaa OutputIntent-määritystä, upotettua ICC-kohdeprofiilia, täsmääviä XMP- ja Info-tietoja, trailer-osion /ID-tunnusta eikä salausta. Ohita mikä tahansa näistä, niin sinulla on tiedosto, joka väittää olevansa PDF/VT-standardin mukainen mutta epäonnistuu heti, kun standardinmukainen lukija tarkistaa perustan. PDFiumPas käsittelee PDF/X-4-kerrosta osana PDF/VT-tallennusta, joten sinun ei tarvitse kutsua erillistä SaveAsPdfX-metodia ensin; injektori kirjoittaa molemmat kerrokset yhdellä ajolla
Tiedoston kirjoittaminen SaveAsPdfVT-metodilla
Minimaalinen kutsu ei vaadi muuta kuin aktiivisen asiakirjan, sillä TPdfVTSaveOptions.Default tarjoaa sisäänrakennetun sRGB ICC -profiilin ja yhteensopivuustason pvc1. Tallennus suorittaa sisäisesti kolme vaihetta: se poistaa mahdolliset suojaukset (selväkielisten merkintöjen vieminen salattuun objektivirtaan korruptoisi sen), se siltaa asiakirjan olemassa olevan Info-sanakirjan ja trailer-osion /ID-tunnuksen merkintäsarjaan, jotta XMP- ja Info-arvot täsmäävät, ja lopuksi lisää PDF/X-4- ja PDF/VT-objektit inkrementaalisen päivityksen kautta
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
if Pdf.LoadFromFile('statements-merged.pdf') then
begin
// Default options: built-in sRGB OutputIntent, PDF/VT-1, synthesised DPart
if Pdf.SaveAsPdfVT('statements-pdfvt.pdf') then
Writeln('PDF/VT-1 written')
else
Writeln('Save failed (document not active?)');
end;
finally
Pdf.Free;
end;
end;
Todellista tuotantotulostusta varten haluat lähes aina korvata OutputIntent-määrityksen painokoneesi omilla ominaisuuksilla yleisen sRGB-oletuksen sijaan. Tarjoa ICC-tavut ja olosuhdetunnisteet TPdfVTSaveOptions-tietueen kautta:
var
Pdf: TPdf;
Opt: TPdfVTSaveOptions;
Icc: TBytes;
begin
Pdf := TPdf.Create(nil);
try
Pdf.LoadFromFile('directmail-merged.pdf');
Icc := LoadIccProfile('GRACoL2013_CRPC6.icc'); // your own loader
Opt := TPdfVTSaveOptions.Default;
Opt.Conformance := pvc1; // pvc2 is normalised to pvc1 on write
Opt.IccProfileData := Icc;
Opt.OutputConditionIdentifier := 'CGATS21_CRPC6';
Opt.OutputCondition := 'Commercial print, coated, CRPC6';
Opt.RegistryName := 'http://www.color.org';
Opt.Title := 'Spring 2026 Direct Mail Run';
Opt.Trapped := ptvFalse; // PDF/X Info /Trapped state
Pdf.SaveAsPdfVT('directmail-pdfvt.pdf', Opt);
finally
Pdf.Free;
end;
end;
Eräs yksityiskohta tässä koodiesimerkissä on tietoinen suojakaide eikä rajoitus, josta voisi kiistellä. Asetus Opt.Conformance := pvc2 ei tuota PDF/VT-2-tiedostoa. Kirjoittaja normalisoi kaikki muut kuin pvc1-pyynnöt takaisin tasolle pvc1, sillä PDF/VT-2 on tiedostojoukkomuoto, ja yksittäistä tiedostoa kirjoittava työkalu ei fyysisesti kykene kokoamaan ulkoista resurssijoukkoa, jota pykälä §6.2.2 vaatii. Arvo pvc2 on olemassa lukupolkua varten, jotta ValidatePdfVT voi tunnistaa ja raportoida olemassa olevan tiedostojoukkoasiakirjan; se ei ole kirjoituskohde
DPart-puu: rakenne, jota RIP todellisuudessa lukee
PDF/VT-standardin ydin on Document Part (DPart) -hierarkia. Sen avulla painokone voi jakaa pitkän ajon tietueiksi, ryhmitellä tietueet vastaanottajittain tai postinipuittain ja liittää niihin Document Part -metatiedot, jotta jatkokäsittelylaitteet voivat reitittää ja laskuttaa kunkin kappaleen. ISO 16612-2 §6.5 määrittelee kytkennät: luettelo (catalog) kantaa /DPartRoot-merkintää, DPart-juurisolmu kantaa /DPartRootNode-määritystä ja kunkin hierarkiatason nimeävää /NodeNameList-luetteloa, lehtisolmut (leaf DParts) kattavat sivupuun alueita ja jokainen tiettyyn osaan kuuluva sivu osoittaa takaisin lehtisolmuunsa sivutason /DPart-merkinnän kautta
Kun lähdeasiakirjasi sisältää jo käyttökelpoisen hierarkian, SaveAsPdfVT säilyttää sen. Kun sitä ei ole, kirjoittaja syntetisoi minimaalisen hierarkian: yksittäisen asiakirjatason DPart-solmun, joka kattaa nykyisen sivupuun järjestyksessä, lisäten /DPart-takaisinviitteen jokaiseen aktiiviseen sivuobjektiin ja yksitasoisen luettelon /NodeNameList [/Document]. Ole rehellinen itsellesi siitä, mitä tämä minimaalinen puu on. Se on rakenteellinen ankkuri, joka täyttää pykälän §6.5 muotovaatimukset; se ei ole liiketoiminnallista metatietoa. Se ei voi keksii vastaanottajia, postikappaleiden rajoja tai tuote-eriä, koska näitä tietoja ei koskaan ollut lähteessä. Jos sinulla on vastaanottajakohtaista tietoa, sinun odotetaan rakentavan syvemmän DPart-puun itse ja laajentavan /NodeNameList-luetteloa luomiesi tasojen mukaisesti
Validointi, joka ulottuu avaimen olemassaoloa pidemmälle
ValidatePdfVT palauttaa TPdfVTValidationResult-tietueen, joka sisältää kolme asiaa: havaitun yhteensopivuuden (Conformance), joukon ongelmia (Issues) ja IsCompliant-apumuuttujan, joka on tosi vain, kun yhteensopivuus on todellinen taso ja ongelmajoukko on tyhjä. Ongelmaluettelo on tarkoituksellisen tarkka, joten epäonnistunut tulos kertoo, minkä kohdan missasit pelkän 'virheellinen'-viestin sijaan:
var
Pdf: TPdf;
Res: TPdfVTValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.LoadFromFile('statements-pdfvt.pdf');
Res := Pdf.ValidatePdfVT;
if Res.IsCompliant then
Writeln('PDF/VT compliant: ', VTLevelName(Res.Conformance))
else
begin
if pvviMissingDPartRoot in Res.Issues then
Writeln('DPart hierarchy missing or unusable');
if pvviMissingPdfXIdentifier in Res.Issues then
Writeln('PDF/X-4 base identifier absent');
if pvviMissingOutputIntent in Res.Issues then
Writeln('OutputIntent / ICC profile missing');
if pvviEncryptionPresent in Res.Issues then
Writeln('Encrypted - PDF/X forbids this');
end;
finally
Pdf.Free;
end;
end;
Kaksi tarkemman tarkastelun arvoista asiaa ovat yhteensopivuuden pariliitos ja DPart-puun läpikäynti, sillä molemmat olivat aiemmin liian sallivia ja niitä tiukennettiin vastaamaan spesifikaatiota. Pariliitoksen osalta validaattori tekee tarkan vastaavuustarkistuksen, ei 'mikä tahansa PDF/X käy' -tarkistusta: PDF/VT-1-tiedosto hyväksytään vain PDF/X-4-perustalla, ja PDF/VT-2-tiedosto vain perustalla PDF/X-4p, PDF/X-5g tai PDF/X-5pg. PDF/X-1a-perustalla oleva PDF/VT-1-merkintä raportoidaan virheeksi eikä sitä päästetä läpi
DPart-puun läpikäynti on paikka, jossa suurin osa tiukkuudesta sijaitsee. Ei riitä, että katalogissa on /DPartRoot-avain, sillä väärennettyä tyhjää objektia tai sellaista, jolla ei ole sivulinkkejä, ei edelleenkään voida käyttää. HasValidDPartHierarchy ja rekursiivinen ValidateDPartNode jäljittävät koko rakenteen: ne seuraavat vanhempien linkkejä, hylkäävät kaksoiskappaleet ja silmukat, valvovat että /Start ja /DParts ovat toisensa poissulkevia, ja vaativat lehtisivualueiden kattavan sivupuun syvyysjärjestyksessä siten, että kunkin sivun /DPart osoittaa sen sisältävään lehtisolmuun. Kaikki nämä sisäiset viat supistuvat yhdeksi pvviMissingDPartRoot-ongelmalipuksi julkisen enumin laajentamisen sijaan, joten käsittele tätä yhtä lippua muodossa "DPart-hierarkia on käyttökelvoton", ei kirjaimellisesti "juuriavain puuttuu"
Kolme syntaktista ansaa, joita validaattori nyt valvoo
Peräkkäiset ajot pykälän §6.5 taulukkoa Table 4 vasten paljastivat rakenteita, jotka aiemmat versiot hyväksyivät, mutta standardi ei. Nämä ovat asioita, joissa käsin rakennettu DPart-puu menee usein vikaan, joten ne on syytä tuoda nimenomaisesti esille:
/DPartson taulukoiden taulukko, ei litteä taulukko. Ulomman taulukon jokaisen elementin on oltava epäsuoran viitteen taulukko. Litteä muoto/DParts [9 0 R]hylätään; oikea muoto on/DParts [[9 0 R] [10 0 R]]. Tämä estää ei-hierarkkista rakennetta esiintymästä kelvollisena tasona/Endmerkitsee ainoastaan todellista monisivuista aluetta. Lehtisolmu DPart saa sisältää/End-merkinnän vain, kun sillä on myös/Start, ja/End-kohdan on sijoituttava sivujärjestyksessä myöhemmin kuin/Start. Degeneroitunut tapaus/Start 3 0 R /End 3 0 Rtekee nyt hierarkiasta käyttökelvottoman sen sijaan, että se luettaisiin yksisivuiseksi osaksi/NodeNameList-nimien on selviydyttävä PDF-nimen unescaping-käsittelystä XML NMTOKEN -muotoisina. Nimi kuten/Bad#20Namelaajenee nimeksi, joka sisältää välilyönnin, mikä ei ole kelvollinen tunnus (token). Toteutus suorittaa kevyen ASCII-tarkistuksen (kirjaimet, numerot,.,-,_,:ja ei-ASCII-tavut), joka havaitsee välilyönnit ja erotinvirheet hylkäämättä kuitenkaan aitoja lokalisoituja tai valmistajakohtaisia nimiä
XMP-merkinnät: kaksi tapaa saman ominaisuuden kirjoittamiseen
PDF/VT-tunnistus asuu XMP-tiedoissa pdfvtid-nimiavaruuden alla, erityisesti kentissä GTS_PDFVTVersion ja GTS_PDFVTModDate, standardien xmp:CreateDate ja xmp:ModifyDate rinnalla. Hienovaraisuus, joka aiheuttaa vääriä "puuttuu"-raportteja yksinkertaisissa lukijoissa, on se, että mikä tahansa näistä voidaan sarjallistaa kahdella tavalla: elementin tekstinä (<pdfvtid:GTS_PDFVTVersion>PDF/VT-1</pdfvtid:GTS_PDFVTVersion>) tai RDF-attribuuttina kuvaus-elementissä. PDFiumPas lukee molemmat muodot, joten tiedostoa, jonka toinen työkalu kirjoitti attribuuttityylillä, ei rangaista. Se valvoo myös pykälän §6.3 johdonmukaisuussääntöä, jonka mukaan GTS_PDFVTModDate-arvon on oltava yhtä suuri kuin xmp:ModifyDate; ristiriita nostaa virheen pvviModDateMismatch
Vielä yksi sääntö samasta pykälästä: tuntematon GTS_PDFVTVersion-arvo säilytetään muodossa pvcUnknown rather kuin palautettaisiin arvoon pvcNone. Tällä erolla on merkitystä käytännössä. pvcNone tarkoittaa "ei lainkaan PDF/VT-merkintää, tai tavallinen PDF", kun taas pvcUnknown tarkoittaa "jokin on leimannut version, jota tämä validaattori ei tunnista" (mukaan lukien PDF/VT-2s -tapaus). Näiden kahden sekoittaminen piilottaisi virheellisen tiedoston samaan laatikkoon tavallisen asiakirjan kanssa
Mihin takuu päättyy
On syytä olla tarkka siitä, mitä nämä metodit lupaavat, sillä muuttuvan tiedon tulostuksen yhteensopivuudella on suora taloudellinen merkitys. DPart- ja pariliitostarkistukset ovat tavutason rakenteellista validointia. Ne varmistavat, että optimointirunko, PDF/X-4-perusmerkinnät, OutputIntent ja XMP ovat olemassa ja sisäisesti johdonmukaisia. Ne eivät ole sisältötason PDF/X-4-esitarkastus (preflight): ne eivät varmista, että jokainen väri on ilmoitetun tulostusolosuhteen mukainen, että kaikki fontit on upotettu tai ettei kiellettyjä läpinäkyvyyden sekoitusongelmia ole päässyt mukaan. Kun kyseessä on työ, jonka lähetät sopimuspainoon, yhdistä PDFiumPas-rakenteellinen validointi erilliseen PDF/X-esitarkastusmoottoriin ja testitulostukseen, aivan kuten tekisit minkä tahansa muun yhteensopivuusväitteen kohdalla. Rakenteellinen kerros havaitsee virheet, jotka hiljaisesti rikkovat RIP-välimuistin; se on toinen puoli täydellisestä tarkistuksesta, ei sen kokonaisuus
Jos rakennat näitä tarkistuksia osaksi laajempaa julkaisuporttia, sama tavutason skannausmenetelmä tukee kirjaston muuta standardityötä, mukaan lukien objekti- ja ristiviitevirtojen validointia ennen kuin tiedosto edes päätyy esitarkastukseen, ja Form XObjectien avulla tehtävien uudelleenkäytettävien sivuleimojen jakamiskuria, joka tekee asiakirjasta RIP-ystävällisen heti alusta alkaen. Tässä kuvatut PDF/VT- ja PDF/X-tallennus- ja validointi-API:t ovat osa Delphille ja C++Builderille tarkoitettua PDFium VCL -komponenttia, jonka tuotesivulta löytyy täysi yhteensopivuusviite