Nástroj pro dávkový preflight je konzolový program bez okna, nasměrovaný na složku s PDF soubory, který každý z nich zkontroluje podle vámi zadaných standardů shody a zanechá za sebou strojově čitelný důkaz o tom, co zjistil. Nikdo nesedí a nesleduje to. Běží ve dvě hodiny ráno pod cronem nebo Plánovačem úloh Windows a další osobou, která se o jeho výstup zajímá, je buď plánovač čtoucí návratový kód, nebo auditor otevírající zprávu o týdny později. To mění význam slova „správný“. Preflight jádro v PDFium Component, což je PDF knihovna se zdrojovým kódem pro Delphi, C++Builder a Lazarus, dělá ze samotných validačních volání téměř triviální záležitost. Práce, která rozhoduje o tom, zda si nástroj zaslouží svou existenci, spočívá kolem těchto volání: jaký profil jste zkontrolovali, co návratový kód řekl plánovači a zda zpráva, která by odhalila chybu, stále existuje, když ji někdo hledá
Kontrakt: co plánovač skutečně vidí
CI runner nebo Plánovač úloh Windows z vašeho nástroje vidí přesně dvě věci: návratový kód (exit code) a jakékoli soubory, které po sobě zanechal. Řádky v protokolu, barvy v konzoli, výstup průběhu: to vše je pro člověka, který to sleduje naživo, a ve dvě ráno to není nikdo. Předtím, než se dotknete API, tak si stanovte slovník návratových kódů a nechte ho nudný:
0: každý soubor vyhovoval každému požadovanému profilu1: alespoň jeden soubor vyprodukoval validační nálezy2: samotný nástroj selhal na alespoň jednom souboru (poškozený vstup, zámek, pád)
Rozdíl mezi kódy 1 a 2 je to, co týmy přeskakují a později toho litují. Poškozené PDF, které nelze otevřít, není chybou validace. Zahrňte to pod kód 1 a hromada poškozených skenů se objeví ve vašich dashboardech jako náhlý kolaps shody, což někoho pošle hledat regresi ve standardech, ke které nikdy nedošlo, zatímco skutečností je rozbitý skener na začátku procesu
Do kontraktu patří ještě další dvě položky. První je časový limit pro každý soubor. Patologické PDF, tisíce stránek s hluboce vnořenými strukturami objektů, dokáže zadržet jeden validační průchod na celé minuty a noční dávkové okno na to nemá trpělivost. Ukončete úlohu tohoto souboru po uplynutí lhůty, započítejte to jako selhání nástroje a nechte dávku pokračovat. Druhou položkou je karanténní adresář: přesuňte každý vstup s vypršeným časovým limitem nebo neotevíratelný vstup stranou, místo abyste ho nechali na místě. Během několika měsíců tento adresář tiše nashromáždí ty nejhorší dokumenty, které vaši skuteční zákazníci posílají, a tento korpus má pro testování vydání větší cenu než jakýkoli syntetický vzorek, který byste mohli napsat ručně
Výběr standardů a proč záleží na úrovni shody
Výčet TPdfPreflightStandard pokrývá rodiny, které se objevují v praxi: ppsPdfA pro archivní shodu s ISO 19005, ppsPdfUa pro přístupnost podle ISO 14289, ppsPdfX pro tiskovou výměnu, plus ppsPdfE, ppsPdfR a ppsPdfVT pro inženýrskou práci, rastry a variabilní data. V rámci rodiny modul přečte úroveň shody, kterou dokument deklaruje, a oznámí ji pro každý standard ve výsledném poli ConformanceName. Pojmenování rodiny málokdy stačí, protože právě v úrovni spočívá skutečný rozdíl. PDF/A-2b slibuje vizuální reprodukovatelnost a nic víc. PDF/A-3a přidává požadavek na logické strukturování pomocí tagů a umožňuje vložené zdrojové soubory, což je mnohem vyšší laťka pro překonání u naskenovaného materiálu, který vůbec nemá strom tagů. Udělejte to špatně v jakémkoli směru a dávka vám bude lhát. Pokud vaše retenční politika ve skutečnosti vyžaduje PDF/A-2b, ale vy zamítáte soubory kvůli chybějícím strukturálním tagům, zpráva se zaplní nálezy, které nikdo nikdy neopraví. Pokud přijmete jakýkoli štítek PDF/A bez kontroly úrovně, podepíšete dokumenty, které splňují nižší laťku, než jste slíbili. Požadavky na přístupnost od vládních nákupčích k tomu všemu stále častěji přidávají PDF/UA, což nepřidává žádné náklady na běh, protože metoda BuildPdfPreflightReport (z jednotky FPdfPreflightReport) přijímá množinu standardů:
Report := BuildPdfPreflightReport(Pdf, [ppsPdfA, ppsPdfUa]);
Jedno volání vyhodnotí oba standardy a vrátí jediný konsolidovaný záznam zprávy
Proč prázdný seznam nálezů neznamená úspěšné absolvování
Zpráva vyjmenovává nálezy pro každý standard a prázdný seznam problémů znamená pouze „ve standardech, které skutečně proběhly, nebyly zjištěny žádné problémy“. To je užší tvrzení než „soubor odpovídá standardu, na kterém vám záleží“, a propast mezi nimi je místo, kde dávkový preflight tiše hnije. Překlep v konfiguraci, který odstraní ppsPdfA z množiny, vyprodukuje přesně ten samý prázdný seznam problémů jako skutečně čistý soubor. Proto považujte mlčení za podezřelé. Projděte kolekci Report.Results a ověřte dvě věci u každého standardu, který jste chtěli zkontrolovat: že pro něj záznam s výsledkem vůbec existuje a že jeho příznak IsCompliant, podpořený hodnotou Status = pfsPass, má hodnotu true. Noční úloha, která klade rovnítko mezi „žádné nálezy“ a „připraveno k archivaci“, aniž by kdy potvrdila, které standardy byly hodnoceny, je klasickým způsobem, jak složka s nevyhovujícími soubory proplouvá celými měsíci, dokud některý z nich externí auditor neotevře ve veraPDF a celý archiv není zpochybněn
Druhá past se skrývá v tom, čím samotný nález vlastně je. Každý TPdfPreflightIssue nese Code, Category, Description a Recommendation, a pojmenovává pravidlo, které bylo porušeno, nikoli stránku nebo objekt. To je návrhové rozhodnutí s důsledky pro smyčku zpětné vazby. Zpráva říká produkujícímu týmu, *jaká třída vady* existuje, například nevložené písmo nebo chybějící identifikátor XMP, a nalezení konkrétního nevyhovujícího objektu je úkolem nástroje pro nápravu v další fázi, nikoli úkolem validátoru. Sestavte konzumenty svých zpráv oproti stabilním hodnotám pole Code, a nikdy vůči lidsky čitelnému textovému popisu, který může být mezi verzemi bez varování přeformulován
Soubory zpráv pro stroje a pro osobu v pohotovosti
Záznam zprávy zapisuje stejné nálezy v pěti formátech: SaveJsonToFile, SaveCsvToFile, SaveHtmlToFile, SaveTextToFile a SaveMarkdownToFile, každý s odpovídající funkcí ve stylu ToJson, když chcete řetězec v paměti místo na disku. Odolejte nutkání vybrat jen jeden. Zapisujte JSON pro pipeline, takže CI systém jej může připojit k záznamu o úloze a analyzovat kódy problémů i stavy jednotlivých standardů bez scrapování textu. Zapisujte HTML pro člověka, který dostane upozornění (pager), protože se to otevře v libovolném prohlížeči bez nutnosti jakýchkoli nástrojů. Oba dohromady stojí jeden řádek kódu navíc pro každý soubor a ušetří vašemu technikovi v pohotovosti ten nejhorší úkol v dávkovém zpracování, kterým je zpětné analyzování syrového JSON blobu ve dvě hodiny ráno, aby zjistil, který soubor proces zlomil. Jedna disciplína však záleží více než výběr formátu: odvozujte každý název zprávy z názvu vstupního souboru, nikdy z časového razítka (timestamp), jinak se dva souběžné běhy prolnou do zpráv, které už nedokážete spárovat zpět s jejich vstupy
Prahové hodnoty závažnosti patří spíše do konfigurace než do kódu. Anotace bez alternativního popisu je hrubým selháním pro podávací portál PDF/UA a ignorovatelnou poznámkou pro interní archiv, i když jde v obou případech o naprosto identický nález. Vystavte úroveň pro selhání (fail-on) pro každý profil jako parametr, takže se tato politika může měnit bez rekompilace, a úroveň, která byla v platnosti, vtiskněte přímo do shrnutí úlohy. Příští čtvrtletí si už nikdo nebude pamatovat, pod jakým prahem běžela loňská říjnová dávka, a shrnutí je to jediné místo, kde tato vzpomínka přežije
Izolace souborů, aby jeden špatný PDF nepotopil dávku
procedure RunPreflightBatch(const InputDir, ReportDir: string;
out FilesWithFindings, ToolFailures: Integer);
var
SR: TSearchRec;
Pdf: TPdf;
Report: TPdfPreflightReport;
begin
FilesWithFindings := 0;
ToolFailures := 0;
if FindFirst(InputDir + '*.pdf', faAnyFile, SR) = 0 then
try
repeat
Pdf := TPdf.Create(nil); // fresh instance per file: no state bleed
try
try
Pdf.FileName := InputDir + SR.Name;
Pdf.Active := True;
if not Pdf.Active then // load failures are silent, not raised
raise EPdfError.Create('Cannot open ' + SR.Name);
Report := BuildPdfPreflightReport(Pdf, [ppsPdfA, ppsPdfUa]);
Report.SaveJsonToFile(ReportDir + ChangeFileExt(SR.Name, '.json'));
Report.SaveHtmlToFile(ReportDir + ChangeFileExt(SR.Name, '.html'));
if Report.TotalIssueCount > 0 then
Inc(FilesWithFindings);
except
on E: Exception do
begin
Inc(ToolFailures); // exit-code-2 territory, not a validation verdict
WriteLn(ErrOutput, SR.Name + ': ' + E.Message);
end;
end;
finally
Pdf.Free;
end;
until FindNext(SR) <> 0;
finally
FindClose(SR);
end;
end;
V této smyčce žijí tři záměrná rozhodnutí. Nová instance TPdf pro každý soubor zaručuje, že jeden dokument, který by poškodil stav jádra, nemůže otrávit soubory, které po něm následují. Explicitní kontrola vlastnosti Active si vyslouží své místo, protože Active := True tiše polyká chyby při načítání, místo aby vyvolal výjimku; jakmile tento strážný blok odstraníte, nedokončený (truncated) soubor se přesune do validačního volání, než selže kdesi později se zavádějící zprávou. Vnitřní blok try..except se záměrně nachází uvnitř oboru platnosti jednoho souboru, takže jedna výjimka pouze zvýší počítadlo selhání a smyčka může pokračovat. Chcete mít čisté zprávy pro těch 4999 dobrých souborů i tehdy, když je soubor číslo 5000 roztrhaný na kusy. A oba formáty zpráv se zapisují na disk předtím, než se vyhodnotí verdikt, což znamená, že důkazy přežijí i v případě, že chyba v pozdější logice shrnutí provede nesprávný výpočet
Mapování návratových kódů se pak smrskne na několik řádků v souboru projektu:
begin
RunPreflightBatch(ParamStr(1), ParamStr(2), Findings, Failures);
if Failures > 0 then
Halt(2)
else if Findings > 0 then
Halt(1);
// falling through exits with 0: every file conformed
end.
Co za vás preflight neudělá
Modul (engine) detekuje; neopravuje. Nález týkající se nevloženého písma nebo barevného prostoru závislého na zařízení je pracovním příkazem pro kohokoli, kdo tyto soubory produkuje, a validátor nemá žádný způsob, jak to záplatovat na místě. Naplánujte si tedy smyčku zpětné vazby opravdu promyšleně. Zprávy musejí dopadat tam, kde si je tým, co soubory produkuje, skutečně přečte, jinak se stejné nálezy budou objevovat každou noc, dokud se někdo konečně nezeptá, proč se úroveň shody nikdy nezlepšuje. Vyplatí se také zkontrolovat vzorek verdiktů s nezávislým validátorem – veraPDF pro PDF/A nebo preflight z aplikace Acrobat pro PDF/X – dříve, než je zkontroluje externí auditor za vás. Pokud se dva enginy neshodnou u skutečného souboru zákazníka, pak tento dokument není jen pouhou nepříjemností; je to přesně ten regresní případ, který vašemu testování vydání chyběl. Ponechte si ho, pojmenujte ho a spusťte jej při každém buildu
Stojí za to znát ještě jedno provázání. Totéž validační jádro pohání i interaktivní kontroly v uživatelském rozhraní recenzí (review UI), takže toto bezhlavé CLI i pracovní stanice pro analytiky (PDF intake review workbench) mohou sdílet jediný validační slovník namísto toho, aby se časem od sebe vzdálily. A protože [ppsPdfA, ppsPdfUa] vyhodnocuje přístupnost v tom samém průchodu, stránka dávky z pohledu PDF/UA přesně navazuje na práci na straně prohlížeče, jako je například vytvoření přístupné čtečky PDF v Delphi. Profily, formáty zpráv a kompletní preflight API jsou dokumentovány na produktové stránce pro PDFium Component