PDF/A a PDF/UA odpovedajú na dve otázky, ktoré spolu vôbec nesúvisia. Ak ich však vnímate ako jediné zaškrtávacie políčko pre prístupnosť a archiváciu, do archívu sa ľahko dostanú poškodené súbory s falošným štítkom o zhode. PDF/A zisťuje, či sa súbor spoľahlivo vykreslí aj o dvadsať rokov. PDF/UA sa zasa pýta, či ho dokážu prečítať asistenčné technológie dnes. Dokument môže bez problémov splniť jeden štandard a pri druhom úplne zlyhať. Jediným spoľahlivým rozhodnutím je preto spustiť obe kontroly, a to ešte pred samotným zápisom súboru na disk, nie až potom, keď nejaký nadväzujúci systém slepo uverí identifikátoru zhody zapísanému v metadátach. Tento identifikátor je iba vlastným vyhlásením dokumentu. Nič vo formáte nezaručuje jeho pravdivosť a aplikácia, ktorá do XMP zapíše hodnotu „PDF/A-1b“ bez reálneho overenia voči štandardu, vytvorí súbor, ktorý vyzaré ako zhodný iba pre tých čitateľov, ktorí čítajú iba jeho štítok. Knižnica losLab PDF Library (PDFlibPas) rieši tento problém pre Delphi a C++Builder integrovaním oboch validátorov priamo do knižnice, takže kontrola prebieha vnútri procesu bez nutnosti spúšťať akékoľvek externé služby.
Norma ISO 19005 (PDF/A) predstavuje zmluvu o reprodukcii. Zhodný súbor sa musí o desiatky rokov vykresliť identicky aj v softvéri, ktorý nikdy nevidel systém, v ktorom súbor vznikol. Pravidlá preto prísne obmedzujú externé závislosti: vyžaduje sa vloženie všetkých písiem (fonts), farby naviazané na vložený profil ICC OutputIntent alebo vyjadrené v priestore nezávislom od zariadenia, zákaz šifrovania v PDF/A-1, zákaz JavaScriptu a súlad XMP metadát so slovníkom informácií o dokumente. Naopak, ISO 14289 (PDF/UA) je zmluvou o sémantike. Asistenčné technológie musia prejsť dokumentom a pochopiť jeho obsah, ktorý sa nachádza v úplne inej vrstve: vyžaduje sa kompletný strom štruktúry, alternatívny text pri obrázkoch, nastavenie názvu dokumentu pre zobrazenie, nepreskakujúce úrovne nadpisov či vzťahy hlavičiek tabuliek, ktoré zostanú zachované aj po posunutí stránky.
Keďže tieto dva štandardy kontrolujú odlišné vrstvy, najproblematickejšie sú súbory, ktoré zostanú niekde uprostred. Dokument dokonale pripravený pre archív môže byť pre čítačku obrazovky úplne nemý. Krásne označený súbor zasa môže odkazovať na systémové písmo, ktoré o desať rokov nebude existovať. Publikovanie vo verejnom sektore je typickým miestom, kde sa stretávajú obe požiadavky naraz, a spracovateľská pipeline ich nemôže spojiť do jediného schvaľovacieho kroku. Zistené nedostatky totiž smerujú k iným riešiteľom. Nevložené písma sú chybou v kóde, ktorý generuje PDF, zatiaľ čo chýbajúci alternatívny text patrí autorom šablón obsahu. Správa, ktorá spája obe zistenia dokopy, sa nakoniec iba dvakrát preposiela.
Na tom, ktorú časť PDF/A si zvolíte za cieľ, záleží rovnako ako na tom, či ju dosiahnete. PDF/A-1 zamrzol na verzii PDF 1.4 a odmieta priehľadnosť (transparency) a JPEG2000, ktoré moderné výstupné reporty využívajú automaticky. PDF/A-2 (ISO 19005-2, založený na ISO 32000-1) oboje podporuje a predstavuje rozumnú predvolenú voľbu pre nový archív. PDF/A-3 ide ešte ďalej a povoľuje vložené súbory ľubovoľného typu, na čo sa spoliehajú regulované formáty elektronickej fakturácie. Tímy, ktoré v roku 2026 stále štandardizujú na PDF/A-1b, zvyčajne preberajú požiadavku spísanú pred pätnástimi rokmi. Prehodnotenie cieľovej verzie je často lacnejšie než odstraňovanie priehľadnosti z každého grafu, ktorý systém vygeneruje.
Štruktúrované nálezy v čase spracovania (ingestion time)
Vstupným bodom vo flat API je CheckFileCompliance s voľbou testu 1 pre PDF/A a 2 pre PDF/UA. Vracia popisovač (handle) zoznamu reťazcov, ktorého položky predstavujú jednotlivé nálezy, jeden na riadok. To je presne štruktúra, ktorou môže automatizovaná kontrola jednoducho prechádzať:
function GateArchiveUpload(Pdf: TPDFlib; const FileName: string): Boolean;
var
ListId, I: Integer;
begin
ListId := Pdf.CheckFileCompliance(FileName, '', 1, 0); // 1 = PDF/A
if ListId = 0 then
begin
// 0 means "no findings" OR "file unreadable" -- disambiguate before passing
Result := Pdf.LastErrorCode = 0;
Exit;
end;
for I := 0 to Pdf.GetStringListCount(ListId) - 1 do
LogFinding(FileName, Pdf.GetStringListItem(ListId, I));
Pdf.ReleaseStringList(ListId);
Result := False;
end;
O tom, či táto kontrola môže bežať bez dozoru, rozhodujú dva detaily. Prvým je návratová hodnota, ktorá môže znamenať dve protichodné veci. CheckFileCompliance vracia 0, ak je súbor plne vyhovujúci, ale aj vtedy, ak sa súbor nepodarilo vôbec otvoriť, keďže v oboch prípadoch sa prázdny zoznam výsledkov zredukuje na 0. Kontrolný mechanizmus, ktorý interpretuje 0 ako úspech, by prepustil poškodené súbory priamo do archívu. Predtým, ako uveríte nule, overte stav pomocou LastErrorCode, ako to robí vyššie uvedená funkcia. Druhý detail sa týka životného cyklu súboru. Validátor beží nad streamovacím čítačom knižnice namiesto kompletného objektového modelu dokumentu. Otvára súbor priamo so zdieľaním na čítanie a nikdy nevolá LoadFromFile, vďaka čomu dokáže spracovať aj viacgigabajtové vstupy bez budovania stromu objektov. Rovnaké otvorenie streamu však zlyhá, ak iný proces stále drží súbor na zápis, čo je presne stav prebiehajúceho nahrávania súboru. Kontrolu preto spúšťajte až po dokončení prenosu.
Streamovací návrh sa oplatí aj pri vysokom zaťažení. Každá kontrola otvára svoj vstup iba na čítanie a zdieľa ho, takže audit celej sady súborov sa dá škálovať na viacero pracovných vlákien alebo procesov s jednou inštanciou TPDFlib na jedného pracovníka bez vzájomných konfliktov. Zdrojom, ktorý si vyžaduje disciplínu, je samotný popisovač (handle). Každý nenulový výsledok z CheckFileCompliance zostáva alokovaný, kým nezavoláte ReleaseStringList. Dlho bežiaca služba, ktorá ich zabúda uvoľňovať, síce nespadne ihneď, ale dochádza v nej k pomalému úniku pamäte (memory leak).
Správy pre ľudí, porovnania (diffs) pre zostavovacie brány
Zoznam nálezov je ideálny pre automatizovanú kontrolu, ale nehodí sa do e-mailu pre tím zodpovedný za šablóny. Funkcia CreatePreflightReport vykreslí rovnakú analýzu ako čitateľný text, CreatePreflightReportEx pridáva možnosť výberu formátu správy a SavePreflightReport ju zapíše na disk, aby mohla byť súčasťou balíka s dokumentom. Mnoho zmlúv o archivácii vyžaduje túto správu ako samostatný výstupný dokument, nie iba ako interný záznam.
Funkciou z tejto rodiny, ktorá si potichu plní svoju úlohu, je ComparePreflightReports. Dodržiavanie noriem predstavuje priestor pre regresiu rovnako ako akékoľvek iné správanie aplikácie. Úprava šablóny, novo licencované firemné písmo alebo aktualizácia knižnice – to všetko môže priniesť chybu, ktorá v minulej verzii nebola, a žiadna z nich sa neohlási sama. Uchovávajte si referenčné správy (golden reports) pre vzorové dokumenty vo verzovacom systéme, po každej zmene ich vygenerujte znova a spustením ComparePreflightReports vypočítajte rozdiel. Prázdny rozdiel (diff) je cenným výsledkom zostavenia. Nečakaný nález zlyhá v zostavení (build), čo je oveľa lacnejšie miesto na odhalenie chyby než neskorší audit.
Generovanie výstupu, ktorý prejde na prvýkrát
Kontrola preflight sa oplatí pri súboroch prichádzajúcich z externého prostredia. Pre dokumenty, ktoré generuje váš vlastný kód, je hľadanie chýb až po vygenerovaní a ich dodatočné opravovanie neefektívnou cestou. PDFlibPas obsahuje režimy generovania pre oba štandardy, pričom oba môžete aktivovať pre ten istý dokument naraz:
var
Pdf: TPDFlib;
Diag: WideString;
begin
Pdf := TPDFlib.Create;
try
Pdf.NewDocument;
Pdf.SetPDFAMode(1);
Pdf.LoadOutputIntentProfile('sRGB-IEC61966-2.1.icc', 'RGB');
Pdf.SetPDFUAMode('en-US');
Pdf.SetInformation(1, 'Quarterly Statement'); // /Title: required for PDF/UA
// ... draw tagged content here ...
Diag := Pdf.GetPDFUADiagnostics;
if Diag <> '' then
Writeln('fix before shipping: ', Diag);
Pdf.SaveToFile('statement.pdf');
// the preflight that counts runs on the saved file:
Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
finally
Pdf.Free;
end;
end;
Riziko sa skrýva pri ukladaní. Viaceré opravy zhody sa vykonávajú počas serializácie dokumentu a nie pri zapnutí režimu: vynútenie príznaku tlače pri anotáciách, zápis predvoleného vzťahu AFRelationship pre vložené súbory v PDF/A-3, normalizácia poradia prepínania (tab order) a popisov formulárových polí pre PDF/UA. Dokument v pamäti nie je bajtovo identický s tým, ktorý sa zapíše na disk, preto jediné platné rozhodnutie o preflighte je to, ktoré sa vypočíta zo saved súboru. Overujte priamo súbor statement.pdf. Neodvodzujte zhodu z objektu, ktorý je stále v pamäti, pretože bajty, ktoré by ste posudzovali, nezodpovedajú bajtom, ktoré reálne expedujete.
Fakturačné scenáre, ktoré prenášajú strojovo čitateľné XML spolu s vizuálnym dokumentom, sledujú vzor ZUGFeRD a Factur-X postavený na PDF/A-3. Tieto by mali explicitne nastaviť vzťah prílohy pomocou SetPDFA3DefaultAFRelationship, keďže norma ISO 19005-3 vyžaduje, aby každý vložený súbor deklaroval svoju rolu voči dokumentu. Ak to nenastavíte, vložené XML bude iba dátovým objektom bez definovaného účelu, čo validátor zaznamená.
Nezávislí arbitri: veraPDF a Acrobat
Tvorca dokumentov by nemal byť jediným sudcom vlastného výstupu. Validátory PDFlibPas vám poskytujú rýchle a štruktúrované rozhodnutia priamo v procese, čo je ideálne pre bežný beh. Výstupná brána pre archivačnú dávku by však mala prehnať súbory cez validátor, ktorý nenapísal nikto z vášho tímu. Referenčnou implementáciou pre PDF/A spravovanou komunitou je veraPDF, a je to nástroj, ktorý väčšina archívov uvádza vo svojich akceptačných kritériách. Profily preflight v Acrobatose zasa poslúžia ako užitočný rozhodca pri nezhode medzi veraPDF a internou kontrolou. Zaznamenávajte názov validátora a jeho verziu ku každej uloženej správe. Tvrdenie, že súbor prešiel cez veraPDF, hovorí veľmi málo bez čísla buildu, s ktorým bol testovaný, keďže nástroj s každým vydaním sprísňuje svoje pravidlá.
Validátory sa na hraniciach štandardov niekedy nezhodnú, a vtedy nie je správnou odpoveďou vybrať si nástroj, ktorý sa vám viac páči. Zmenšite súbor na minimálnu vzorku, ktorá stále vyvoláva rozpor, a porovnajte ju s textom normy. Hodina takejto analýzy zvyčajne odhalí jednu z dvoch vecí: skutočnú chybu v nástroji, ktorú stojí za to nahlásiť autorom, alebo bod normy, ktorý váš tím interpretoval nesprávne, a ktorý by ste mali zapísať do poznámok o zhode, aby ho ďalší vývojár nemusel opätovne riešiť.
Šifrovaný vstup má skratku. Oba validátory síce prijímajú argument hesla, ale súbor PDF/A-1 so šifrovacím slovníkom (encryption dictionary) je už zo svojej podstaty nevyhovujúci, keďže norma ISO 19005-1 šifrovanie priamo zakazuje. Šifrovaný súbor tak môžete odmietnuť ešte pred spustením hlbšej analýzy. Zisťovanie toho, čo šifrovací slovník reálne povoľuje, je samostatnou úlohou popísanou v článku Šifrovanie PDF a audit oprávnení.
Nálezy PDF/UA takmer vždy súvisia s tým, ako bol strom štruktúry pôvodne navrhnutý. Metódy tagovania sú rozobraté v článku Budovanie sémantických stromov prístupnosti v Delphi. Archívy, ktoré vyžadujú aj digitálne podpisy, by mali túto kontrolu spojiť s postupmi v časti Podpisovanie a overovanie PAdES. Kompletná dokumentácia k rozhraniu API pre preflight sa nachádza na produktovej stránke losLab PDF Library pre Delphi.