PDF/A a PDF/UA odpovídají na dvě otázky, které spolu nemají nic společného, a brát je jako jedno zaškrtávací políčko „přístupnost a archivace“ je způsob, jak se do archivu dostanou rozbité soubory s nálepkou shody. PDF/A se ptá, zda se soubor bude věrně vykreslovat i za dvacet let. PDF/UA se ptá, zda jej dnes dokáže přečíst asistivní technologie. Dokument může jeden z nich splnit s přehledem a u druhého propadnout, takže poctivý verdikt vzejde jedině ze spuštění obou, a to dřív, než se soubor zapíše, ne poté, co systém dál v řetězci uvěří identifikátoru shody zapečenému v metadatech. Tento identifikátor je vlastní prohlášení. Nic ve formátu nevyžaduje, aby byl pravdivý, a aplikace, která do XMP zapíše „PDF/A-1b“ bez ověření vůči normě, vyrobí soubor, jenž vypadá konformně pro každého odběratele, který čte jen tu nálepku. losLab PDF Library (PDF Library for Delphi) tuto mezeru pro Delphi a C++Builder zavírá tím, že oba validátory staví přímo do knihovny, takže kontrola běží uvnitř procesu a není třeba stavět žádnou externí službu
Dvě normy, které soubory shazují z opačných důvodů
ISO 19005 (PDF/A) je smlouva o reprodukci. Konformní soubor se musí za desítky let vykreslit identicky na softwaru, který nikdy neviděl systém, jenž jej vyrobil, a proto pravidla útočí na vnější závislosti: každé písmo vložené, barva ukotvená ve vloženém ICC OutputIntentu nebo vyjádřená v prostoru nezávislém na zařízení, žádné šifrování v PDF/A-1, žádný JavaScript, metadata XMP souhlasící se slovníkem informací o dokumentu. ISO 14289 (PDF/UA) je naproti tomu smlouva o sémantice. Asistivní technologie musí dokument projít a odnést si z něj význam, a ten sídlí ve zcela jiné vrstvě: úplný strom struktury, alternativní text u obrázků, název dokumentu nastavený pro zobrazení, úrovně nadpisů, které nepřeskakují, vztahy záhlaví tabulek, jež přežijí i poté, co stránka zmizí z obrazovky
Protože každá z těch dvou norem hlídá jinou vrstvu, kousnou vás právě soubory, které leží mezi nimi. Archivně dokonalý dokument může být pro čtečku obrazovky němý. Nádherně otagovaný dokument může odkazovat na desktopové písmo, jež za deset let existovat nebude. Publikování ve veřejném sektoru je typickým místem, kde oba požadavky dopadnou naráz, a tamní pipeline je nesmí sloučit do jediné brány. Nálezy putují k různým lidem. Nevložená písma jsou vadou kódu, který PDF generuje, zatímco chybějící alternativní text patří tomu, kdo vlastní obsahové šablony, a zpráva, která obojí míchá, se prostě přepošle dvakrát
To, na kterou část PDF/A cílíte, je stejně důležité jako to, zda ji trefíte. PDF/A-1 je zamrzlé na PDF 1.4 a odmítá průhlednost i JPEG2000, po čemž obojím moderní reportovací výstup bez přemýšlení sahá. PDF/A-2 (ISO 19005-2, postavené na ISO 32000-1) přijímá obojí a je rozumnou výchozí volbou pro nový archiv. PDF/A-3 jde dál a povoluje vložené soubory libovolného typu, o což se opírají regulované formáty elektronické fakturace. Tým, který se v roce 2026 pořád standardizuje na PDF/A-1b, obvykle vleče požadavek, jejž kdosi sepsal před patnácti lety, a znovu vyjednat cílovou část bývá levnější než vyškrtat průhlednost z každého grafu, který systém vydá
Strukturované nálezy už při příjmu
Vstupním bodem plochého API je CheckFileCompliance s volbou testu 1 pro PDF/A a 2 pro PDF/UA. Vrací handle seznamu řetězců, jehož položkami jsou jednotlivé nálezy, jeden na řádek, což je přesně tvar, jaký automatická brána potřebuje procházet:
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 znamená „žádné nálezy“ NEBO „soubor nelze číst“ -- rozlište před pokračováním
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, zda tohle poběží bez dozoru, rozhodují dva detaily. Prvním je návratová hodnota, která znamená dvě protikladné věci. CheckFileCompliance vrací 0, když je soubor plně konformní, a také když soubor nešlo vůbec otevřít, protože vnitřně se prázdný seznam výsledků v obou případech scvrkne na 0. Brána, jež 0 čte jako průchod, propustí poškozené nahrávky rovnou do archivu, takže tu nulu rozlište pomocí LastErrorCode dřív, než jí uvěříte, přesně jak to dělá brána výše. Druhý detail se týká toho, kde je soubor ve svém životním cyklu. Kontrolní modul běží nad proudovým čtecím modulem knihovny místo nad plným modelem dokumentu, otevírá soubor přímo se sdílením pro čtení a nikdy nevolá LoadFromFile, díky čemuž dokáže rozžvýkat i mnohagigabajtový vstup bez stavby objektového stromu. Totéž proudové otevření selže, dokud jiný proces drží soubor pro zápis, a probíhající nahrávání je přesně tento stav. Bránu zařaďte až po dokončení přenosu
Proudový návrh se vyplatí znovu při zátěži. Každá kontrola otevírá svůj vstup jen pro čtení a sdílí jej pro čtení, takže audit celého korpusu se škáluje napříč pracovními vlákny či procesy s jednou instancí TPDFlib na pracovníka a bez vzájemné soutěže. Zdrojem, který vyžaduje disciplínu, je samotný handle. Každý nenulový výsledek CheckFileCompliance zůstává alokovaný, dokud nezavoláte ReleaseStringList, a dlouho běžící brána, jež je zapomene uvolnit, nespadne, jen pomalu krvácí pamětí, dokud někdo nezačne pátrat proč
Zprávy pro lidi, rozdíly pro brány sestavení
Seznam nálezů má správný tvar pro bránu a špatný tvar pro e-mail týmu, který spravuje šablony. CreatePreflightReport vykreslí tutéž analýzu jako čitelný text, CreatePreflightReportEx přidává volbu formátu zprávy a SavePreflightReport ji zapíše na disk, aby mohla putovat uvnitř dodávaného balíku dokumentů. Řada archivních smluv z takové zprávy dělá samostatný dodávaný výstup, nejen interní artefakt
Členem téhle rodiny, který si své místo zaslouží nenápadně, je ComparePreflightReports. Shoda je regresní plocha jako každé jiné chování. Úprava šablony, nově licencované firemní písmo nebo povýšení knihovny mohou každé zavést nález, jenž tam minulé vydání nebyl, a žádné z nich se samo neohlásí. Držte referenční zprávy pro sadu reprezentativních dokumentů ve verzovacím systému, po každé změně je znovu vygenerujte a rozdíl spočítejte pomocí ComparePreflightReports. Prázdný rozdíl je artefakt vydání, který stojí za uschování. Překvapivý nález shodí sestavení, což je mnohem levnější místo, kde jej objevit, než audit
Výstup, který projde napoprvé
Preflight se vyplácí u souborů přicházejících odjinud. U dokumentů, které vyrábí váš vlastní kód, je hledání porušení až po generování a jejich zpětné záplatování ta pomalá cesta. PDF Library for Delphi nese pro každou normu režim na straně generování a oba lze zapnout pro tentýž dokument:
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: vyžadováno pro PDF/UA
// ... zde vykreslete tagovaný obsah ...
Diag := Pdf.GetPDFUADiagnostics;
if Diag <> '' then
Writeln('fix before shipping: ', Diag);
Pdf.SaveToFile('statement.pdf');
// preflight, na kterém záleží, běží nad uloženým souborem:
Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
finally
Pdf.Free;
end;
end;
Past se skrývá v okamžiku ukládání. Několik oprav kvůli shodě proběhne během serializace dokumentu, ne ve chvíli, kdy režim zapnete: vynucení příznaku tisku u anotací, zápis výchozího AFRelationship u vložených souborů v PDF/A-3, normalizace pořadí tabulátoru a popisů polí formuláře kvůli PDF/UA. Dokument sedící v paměti není bajt po bajtu totožný s tím, který dosedne na disk, takže jediný verdikt preflightu, jenž má cenu, je ten spočítaný z uloženého souboru. Ověřujte samotný statement.pdf. Neodvozujte shodu z objektu, který je stále v paměti, protože bajty, jež byste posuzovali, nejsou bajty, které jste vydali
Fakturační scénáře, jež vedle vizuálního dokumentu nesou strojově čitelné XML, sledují vzor ZUGFeRD a Factur-X, který stojí na PDF/A-3. Ty by měly vztah přílohy nastavit výslovně přes SetPDFA3DefaultAFRelationship, protože ISO 19005-3 vyžaduje, aby každý vložený soubor deklaroval svou roli vůči dokumentu. Nechte to nenastavené a vložené XML je jen blob bez uvedeného účelu, čehož si validátor všimne
Nezávislí rozhodčí: veraPDF a Acrobat
Producent by neměl být jediným soudcem svého vlastního výstupu. Kontrolní moduly PDF Library for Delphi vám dají rychlé strukturované verdikty uvnitř procesu, což je přesně to, co chcete na horké cestě, ale vydávací brána archivní dávky by výstup měla přesto prohnat validátorem, kterého nikdo z vašeho týmu nepsal. veraPDF je komunitně udržovaná referenční implementace pro PDF/A a nástroj, jejž archivy ve svých akceptačních kritériích jmenují nejčastěji, takže je to ten, s nímž se srovnávat. Preflightové profily Acrobatu se hodí jako rozhodčí ve chvíli, kdy se veraPDF a kontrola uvnitř procesu neshodnou. Vedle každé uložené zprávy zaznamenejte název validátoru i jeho verzi. Tvrzení, že soubor prošel přes veraPDF, říká bez čísla sestavení, které jej pustilo, jen velmi málo, protože nástroj svá pravidla mezi vydáními utahuje
Validátory se na okrajích norem opravdu rozcházejí, a když k tomu dojde, není odpovědí vybrat si nástroj, který se vám líbí. Zmenšete soubor na minimální vzorek, jenž ten rozpor stále vyvolává, a přečtěte si jej proti textu normy. Hodina takové práce obvykle vynese jedno ze dvou: buď skutečnou chybu nástroje, kterou stojí za to nahlásit jeho autorům, nebo ustanovení, jež váš tým čte špatně a měl by si je zapsat do poznámek o shodě, aby to příští člověk neřešil znovu
Zašifrovaný vstup má zkratku. Oba kontrolní moduly berou argument s heslem, jenže soubor PDF/A-1 se šifrovacím slovníkem už konformní není, protože ISO 19005-1 šifrování bez výjimky zakazuje, takže zašifrované podání lze odmítnout ještě před jakoukoli hlubší analýzou. Zjistit, co vlastně šifrovací slovník uděluje, je úloha sama pro sebe a věnuje se jí audit šifrování a oprávnění v PDF
Nálezy PDF/UA se téměř vždy vracejí k tomu, jak byl strom struktury vůbec vytvořen, a tagovací techniky za tím žijí v článku stavba stromů struktury tagovaného PDF v Delphi. Archivy, které navíc vyžadují digitální podpisy, by měly tuto bránu spárovat s postupem popsaným v článku podepisování a validace PAdES. Kompletní referenční příručka preflightového API žije na produktové stránce losLab PDF Library for Delphi