Transakcijska tiskarna vam 80.000-stranski tek izpiskov vrne z enovrstično zavrnitvijo: "ni PDF/VT, RIP ne more predpomniti." Datoteka se brez težav odpre v vsakem pregledovalniku na vaši mizi, barve so pravilne, podatki so združeni pravilno. Nič od tega pa ni tisto, kar je zahteval digitalni tiskarski stroj. Visokohitrostno tiskanje s spremenljivimi podatki živi ali umre glede na to, ali tiskarski stroj prepozna, da je blok z logotipom stranke na strani 1 bajt za bajtom isti objekt kot na strani 40.000, ga izriše enkrat in ga nato znova uporabi. PDF/VT je standard, ki to obljubo naredi strojno preverljivo, in "videti je pravilno" je točno past, saj je struktura, ki jo bere RIP, na zaslonu nevidna
PDFiumPas to strukturo izpostavi prek majhne površine na TPdf: SaveAsPdfVT jo zapiše, ValidatePdfVT jo preveri. Ta članek obravnava, kaj ti dve metodi dejansko zapišeta na disk in kaj pregledata, kje je ISO 16612-2 strožji, kot se sprva zdi, in kateri deli so poštena strukturna sidra namesto popolnega preflight preverjanja, ki bi ga lahko zaračunali stranki
Kaj PDF/VT standardizira in zakaj je PDF/X na prvem mestu
PDF/VT (ISO 16612-2:2010) ni nova oblika datoteke. Gre za plast optimizacijskih metapodatkov, pritrjeno na datoteko PDF/X, in ta vrstni red nosi breme. Standard definira tri ravni skladnosti, vendar samo dve izmed njih poimenujeta datoteko PDF: PDF/VT-1, en sam samozadosten dokument, in PDF/VT-2, model nabora datotek, kjer strani sklicujejo skupne zunanje vire. Tretji žeton, ki ga lahko vidite, PDF/VT-2s, pa sploh ni vrednost na ravni datoteke; živi v glavi toka MIME, opisani v prilogi A. Če najdete kodo, ki v XMP dokumenta vtisne GTS_PDFVTVersion = "PDF/VT-2s", je ta koda napačna
Neizpogajljivo pravilo za eno datoteko je osnova PDF/X. ISO 16612-2 §6.2.1 zahteva, da je vsaka datoteka PDF/VT-1 tudi veljavna datoteka PDF/X-4. Nabor datotek PDF/VT-2 pa mora po §6.2.2 temeljiti na PDF/X-4p, PDF/X-5g ali PDF/X-5pg. Zato zapisovalnik PDF/VT ne more samo pripeti nekaj identifikacijskih ključev: s seboj mora nositi celoten nabor označevalcev PDF/X-4, kar pomeni OutputIntent, vdelan destinacijski ICC profil, ustrezne vnose XMP in dokumentnega Info, trailer /ID, ter brez šifriranja. Izpustite karkoli od tega in dobite datoteko, ki trdi, da je PDF/VT, a pade v trenutku, ko skladni porabnik preveri osnovo. PDFiumPas plast PDF/X-4 obravnava kot del shranjevanja PDF/VT, zato prej ne kličete ločenega SaveAsPdfX; injektor obe plasti zapiše v enem prehodu
Zapis datoteke s SaveAsPdfVT
Minimalni klic ne potrebuje ničesar razen aktivnega dokumenta, ker TPdfVTSaveOptions.Default zagotovi vgrajen ICC profil sRGB in skladnost pvc1. Shranjevanje interno poteka v treh korakih: odstrani vso varnost (vbrizgavanje navadnih označevalcev v šifriran object stream bi ga pokvarilo), premosti obstoječi slovar Info dokumenta in trailer /ID v nabor označevalcev, tako da se vrednosti XMP in Info ujemajo, nato pa skozi incremental update pripne objekte PDF/X-4 in PDF/VT
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;
Za resnični produkcijski izhod skoraj vedno želite OutputIntent prepisati z značilnostjo vašega tiskarskega stroja, ne z generičnim nadomestkom sRGB. Bajte ICC in identifikatorje pogojev podajte prek TPdfVTSaveOptions:
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;
Ena podrobnost v tem izseku je namerna varovalka, ne omejitev, o kateri bi se lahko prepirali. Nastavitev Opt.Conformance := pvc2 ne ustvari datoteke PDF/VT-2. Zapisovalnik vsako zahtevo, ki ni pvc1, normalizira nazaj na pvc1, ker je PDF/VT-2 format nabora datotek, zapisovalnik ene datoteke, ki pripne en izhodni dokument, pa fizično ne more sestaviti nabora zunanjih virov, ki ga zahteva §6.2.2. Vrednost pvc2 obstaja za bralno pot, da lahko ValidatePdfVT prepozna in prijavi obstoječ dokument nabora datotek; ni cilj za zapis
Drevo DPart: struktura, ki jo RIP dejansko bere
Jedro PDF/VT je hierarhija Document Part (DPart). Prav ta omogoča, da tiskarski stroj dolg tek razdeli na zapise, zapise združi po prejemnikih ali poštnih svežnjih in pripne Document Part Metadata, da lahko nadaljnja oprema vsak kos usmeri in obračuna. ISO 16612-2 §6.5 določa povezave: katalog nosi /DPartRoot, korensko vozlišče DPart nosi /DPartRootNode in /NodeNameList, ki poimenuje vsako raven hierarhije, listni DPart pokriva razpone drevesa strani, vsaka stran, ki pripada delu, pa prek vnosa na ravni strani /DPart kaže nazaj na svoj list
Kadar izvorni dokument že vsebuje uporabno hierarhijo, jo SaveAsPdfVT ohrani. Kadar je ni, zapisovalnik sintetizira minimalno: en sam DPart na ravni dokumenta, ki po vrsti pokrije trenutno drevo strani, s povratnim sklicem /DPart, pripetim vsakemu živemu objektu strani, in z enonivojskim /NodeNameList [/Document]. Bodite pošteni do sebe glede tega, kaj to minimalno drevo je. Gre za strukturno sidro, ki zadosti zahtevam oblike iz §6.5; ni poslovni metapodatek. Ne more si izmisliti prejemnikov, meja poštnih kosov ali produktnih serij, ker teh informacij v viru nikoli ni bilo. Če imate podatke po prejemnikih, se od vas pričakuje, da zgradite globlje drevo DPart in ustrezno razširite /NodeNameList, da se ujema z ravnmi, ki jih ustvarite
Validacija, ki gre dlje od same prisotnosti ključev
ValidatePdfVT vrne zapis TPdfVTValidationResult s tremi stvarmi: zaznano Conformance, množico Issues in pomočnik IsCompliant, ki je true samo takrat, ko je skladnost resnična raven in je množica težav prazna. Enumeracija težav je namenoma natančna, zato neuspešen rezultat pove, kateri člen ste zgrešili, namesto da bi zgolj rekel "neveljavno":
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;
Dve preverjanji, ki ju je vredno razumeti v globino, sta parjenje skladnosti in sprehod po DPart, ker sta bili obe nekoč preveč prizanesljivi in sta bili zaostreni, da se ujemata s specifikacijo. Na strani parjenja validator dela natančno ujemanje, ne pa "katerikoli PDF/X je dovolj": datoteka PDF/VT-1 je sprejeta samo na osnovi PDF/X-4, datoteka PDF/VT-2 pa samo na PDF/X-4p, PDF/X-5g ali PDF/X-5pg. Označevalec PDF/VT-1 na osnovi PDF/X-1a se prijavi, ne pa spusti skozi
Sprehod po DPart je mesto, kjer živi največ strogosti. Ni dovolj, da katalog vsebuje ključ /DPartRoot, ker ponarejen prazen objekt ali objekt brez povezav na strani še vedno ni uporaben za porabo. HasValidDPartHierarchy in rekurzivni ValidateDPartNode sledita celotni strukturi: sledita nadrejenim povezavam, zavračata podvojene otroke in cikle, uveljavljata, da sta /Start in /DParts medsebojno izključna, ter zahtevata, da listni razponi strani pokrijejo drevo strani v globinskem vrstnem redu in da /DPart na vsaki strani kaže na list, ki jo vsebuje. Vse te notranje napake se sesedejo v en sam bit težave pvviMissingDPartRoot namesto širitve javne enumeracije, zato to zastavico razumite kot "hierarhija DPart je neuporabna", ne dobesedno kot "korenski ključ manjka."
Tri sintaktične pasti, ki jih validator zdaj uveljavlja
Zaporedni prehodi skozi §6.5, tabela 4, so razkrili oblike, ki so jih prejšnje različice sprejele, standard pa ne. To so točno vrste napak, ki jih ročno zgrajeno drevo DPart naredi narobe, zato jih je vredno izrecno izpostaviti:
/DPartsje polje polj, ne plosko polje. Vsak element zunanjega polja mora biti sam polje posrednih sklicev. Ploski/DParts [9 0 R]se zavrne; skladna oblika je/DParts [[9 0 R] [10 0 R]]. To prepreči, da bi se nehierarhična struktura pretvarjala za veljavno raven/Endoznačuje samo resničen večstranski razpon. Listni DPart lahko nosi/Endsamo, kadar ima tudi/Start, in/Endmora v vrstnem redu drevesa strani pasti pozneje kot/Start. Degenerirani/Start 3 0 R /End 3 0 Rzdaj naredi hierarhijo neuporabno, namesto da bi se bral kot enostranski del/NodeNameListimena morajo po odstranitvi ubežnih zaporedij v PDF preživeti kot XML NMTOKEN. Ime, kot je/Bad#20Name, se razširi v ime s presledkom, kar ni veljaven žeton. Implementacija naredi lahek ASCII-preverjalnik (črke, števke,.,-,_,:, plus bajti, ki niso ASCII), kar ujame napake s presledki in ločili, ne da bi zavrnilo legitimna lokalizirana ali dobaviteljsko specifična imena
Označevalci XMP: dva načina zapisa iste lastnosti
Identifikacija PDF/VT živi v XMP pod imenskim prostorom pdfvtid, natančneje v GTS_PDFVTVersion in GTS_PDFVTModDate, poleg standardnih xmp:CreateDate in xmp:ModifyDate. Podrobnost, ki pri naivnih bralnikih povzroča lažna poročila o "manjka", je ta, da se lahko katerikoli od teh zapisov serializira na dva načina: kot besedilo elementa (<pdfvtid:GTS_PDFVTVersion>PDF/VT-1</pdfvtid:GTS_PDFVTVersion>) ali kot RDF-atribut na elementu description. PDFiumPas bere obe obliki, zato datoteka, ki jo je drugo orodje zapisalo v atributnem slogu, ni kaznovana. Uveljavlja tudi pravilo doslednosti iz §6.3, da mora biti GTS_PDFVTModDate enako xmp:ModifyDate; neujemanje sproži pvviModDateMismatch
Še eno pravilo iz istega člena: neznana vrednost GTS_PDFVTVersion se ohrani kot pvcUnknown, namesto da bi se zložila nazaj v pvcNone. Ta razlika je operativno pomembna. pvcNone pomeni "sploh ni označevalca PDF/VT, to je navaden PDF", medtem ko pvcUnknown pomeni "nekaj je vtisnilo različico, ki je ta validator ne prepozna" (med njimi primer PDF/VT-2s). Če bi to dvoje zlili, bi napačno oblikovana datoteka končala v istem košu kot navaden dokument
Kje se jamstvo konča
Vredno je natančno določiti mejo tega, kar te metode obljubljajo, ker je skladnost pri tiskanju s spremenljivimi podatki povezana z resničnim denarjem. Preverjanja DPart in parjenja so strukturna validacija na ravni bajtov. Potrdijo, da so optimizacijsko ogrodje, osnovni označevalci PDF/X-4, OutputIntent in XMP prisotni ter notranje dosledni. Niso pa vsebinsko preverjanje PDF/X-4: ne preverjajo, da je vsaka barva znotraj deklariranega izhodnega pogoja, da so vse pisave vdelane ali da se ni izmuznil kak prepovedan robni primer prosojnega mešanja. Za opravilo, ki ga pošiljate na pogodbeni tiskarski stroj, združite strukturno validacijo PDFiumPas z namenskim preflight motorjem PDF/X in testnim odtisom, tako kot bi zdravorazumsko preverili katerokoli drugo trditev o skladnosti. Strukturna plast ujame napake, ki tiho zlomijo predpomnjenje RIP; je polovica popolnega preverjanja, ne pa celota
Če ta preverjanja vgrajujete v širšo izdajno zaporo, isti pristop pregleda na ravni bajtov podpira tudi drugo delo knjižnice s standardi, vključno z validiranjem tokov objektov in medsklicev še preden datoteka sploh doseže preflight, ter disciplino skupnih objektov za ponovno uporabne žige strani s Form XObjects, zaradi katere je dokument sploh prijazen do RIP. API-ji za zapis in validacijo PDF/VT in PDF/X, opisani tukaj, so del komponente PDFium VCL za Delphi in C++Builder, katere stran izdelka vsebuje celoten referenčni pregled skladnosti