Alat za skupnu prethodnu provjeru (batch preflight) je konzolni program bez prozora, usmjeren na mapu s PDF datotekama, koji provjerava svaku od njih u odnosu na standarde usklađenosti koje navedete te ostavlja strojno čitljiv dokaz o onome što je pronašao. Nitko ne sjedi i ne promatra to. Radi u dva ujutro pod cron ili Windows Task Scheduler, ili kao provjera (gate) u CI cjevovodu, a sljedeća osoba koju zanima njegov ispis je ili planer (scheduler) koji čita izlazni kod ili revizor koji otvara izvješće tjednima kasnije. To mijenja značenje riječi "točno". Mehanizam za prethodnu provjeru komponente PDFium Component, PDF biblioteke s izvornim kodom za Delphi, C++Builder i Lazarus, čini same pozive za validaciju gotovo trivijalnima. Posao koji odlučuje hoće li se alat isplatiti nalazi se oko tih poziva: koji ste profil provjerili, što je izlazni kod rekao planeru i postoji li izvješće, koje bi uhvatilo pogrešku, još uvijek kada ga netko krene tražiti
Ugovor: što planer zapravo može vidjeti
CI pokretač ili Windows Task Scheduler vide točno dvije stvari iz vašeg alata: izlazni kod i datoteke koje je ostavio za sobom. Linije zapisa, boje konzole, ispis napretka: sve to služi za čovjeka koji to gleda uživo, a u dva ujutro nema nikoga. Stoga fiksirajte rječnik izlaznih kodova prije nego što dotaknete API, i neka ostane dosadan:
0: svaka datoteka je u skladu sa svakim traženim profilom1: barem jedna datoteka proizvela je nalaze validacije2: sam alat nije uspio na barem jednoj datoteci (oštećeni ulaz, zaključavanje, rušenje)
Razlika između kodova 1 i 2 je ona koju timovi preskaču, a kasnije požale. Oštećeni PDF koji se ne može otvoriti nije neuspješna validacija. Spojite li to u kod 1, hrpa oštećenih skenova pojavit će se na vašim nadzornim pločama kao iznenadni pad usklađenosti, šaljući nekoga u potjeru za regresijom standarda koja se nikada nije dogodila, dok je stvarna priča pokvareni skener u prethodnoj fazi procesa
Još dvije stavke pripadaju ugovoru. Prva je vremensko ograničenje (timeout) po datoteci. Patološki PDF, tisuće stranica s duboko ugniježđenim strukturama objekata, može zadržati jedan prolaz validacije minutama, a noćni prozor nema strpljenja za to. Prekinite obradu te datoteke u zadano vrijeme, brojite to kao neuspjeh alata i nastavite sa skupnom obradom. Druga je mapa za karantenu: premjestite svaki ulaz s isteklim vremenom ili koji se ne može otvoriti sa strane umjesto da ga ostavite na mjestu. Tijekom nekoliko mjeseci ta mapa tiho nakuplja najgore dokumente koje vaši stvarni kupci šalju, a taj je korpus vrijedniji za testiranje izdanja nego bilo koji sintetički uzorak koji biste mogli ručno napisati
Odabir standarda i zašto je razina usklađenosti važna
Enumeracija TPdfPreflightStandard pokriva obitelji koje se pojavljuju u praksi: ppsPdfA za arhivsku usklađenost prema ISO 19005, ppsPdfUa za pristupačnost prema ISO 14289, ppsPdfX za razmjenu ispisa, plus ppsPdfE, ppsPdfR i ppsPdfVT za inženjerstvo, rasterske radove i radove s varijabilnim podacima. Unutar obitelji mehanizam čita razinu usklađenosti koju dokument tvrdi i izvješćuje je po standardu u rezultatu ConformanceName. Imenovanje obitelji rijetko je dovoljno, jer je razina mjesto gdje leži stvarna razlika. PDF/A-2b obećava vizualnu reprodukciju i ništa više. PDF/A-3a dodaje zahtjev za označavanje logičke strukture i omogućuje ugrađene izvorne datoteke, što je puno viši prag koji treba proći za skenirani materijal koji uopće nema stablo oznaka (tag tree). Pogriješite li u bilo kojem smjeru, skupna obrada će vam lagati. Ako vaša politika zadržavanja zapravo želi PDF/A-2b, a vi rušite datoteke zbog nedostatka oznaka strukture, izvješće se puni nalazima koje nitko nikada neće popraviti. Prihvatite li bilo koju PDF/A oznaku bez provjere razine, odobravate dokumente koji ispunjavaju slabiji prag nego što ste obećali. Mandati pristupačnosti od strane vladinih kupaca sve više slažu PDF/UA povrh svega ovoga, što ne dodaje nikakav trošak izvođenju jer BuildPdfPreflightReport (iz jedinice FPdfPreflightReport) uzima skup standarda:
Report := BuildPdfPreflightReport(Pdf, [ppsPdfA, ppsPdfUa]);
Jedan poziv procjenjuje oba standarda i vraća jedan konsolidirani zapis izvješća
Zašto prazan popis nalaza ne znači prolaz
Izvješće nabraja nalaze po standardu, a prazan popis problema znači samo "nisu pronađeni problemi u standardima koji su se zapravo izvodili." To je uža tvrdnja od "datoteka je u skladu sa standardom do kojeg vam je stalo", a jaz između to dvoje je mjesto gdje skupna prethodna provjera tiho trune. Tipfeler u konfiguraciji koji ispušta ppsPdfA iz skupa proizvodi potpuno isti prazan popis problema kao istinski čista datoteka. Stoga tretirajte tišinu kao sumnjivu. Prođite kroz Report.Results i potvrdite dvije stvari za svaki standard koji ste namjeravali provjeriti: da unos rezultata za njega uopće postoji i da je njegova oznaka IsCompliant, poduprta sa Status = pfsPass, istinita. Noćni posao koji poistovjećuje "nema nalaza" s "spremno za arhivu" bez ikakve potvrde koji su standardi procijenjeni klasičan je način na koji mapa s neusklađenim datotekama prolazi mjesecima, sve dok vanjski revizor ne otvori jednu pomoću veraPDF i cijela arhiva ne dođe u pitanje
Druga zamka krije se u tome što nalaz uopće jest. Svaki TPdfPreflightIssue nosi Code, Category, Description i Recommendation, i on imenuje pravilo koje je prekršeno, a ne stranicu ili objekt. To je dizajnerski odabir s posljedicama na petlju povratnih informacija (feedback loop). Izvješće govori timu koji proizvodi datoteke koja klasa kvara postoji, neugrađeni font ili nedostajući XMP identifikator, a pronalaženje specifičnog problematičnog objekta posao je alata za ispravljanje (remediation) nizvodno, a ne validatora. Izgradite svoje potrošače izvješća prema stabilnim vrijednostima Code, a nikada prema ljudski čitljivom tekstu opisa, koji se može preformulirati između izdanja bez upozorenja
Datoteke izvješća za strojeve i za osobu na dežurstvu
Zapis izvješća ispisuje iste nalaze u pet formata: SaveJsonToFile, SaveCsvToFile, SaveHtmlToFile, SaveTextToFile i SaveMarkdownToFile, svaki s odgovarajućom funkcijom u stilu ToJson kada želite string u memoriji, a ne na disku. Oduprite se porivu da odaberete samo jedan. Pišite JSON za cjevovod (pipeline), kako bi ga CI mogao priložiti zapisu posla i raščlaniti kodove problema i statuse po standardima bez struganja teksta (text scraping). Pišite HTML za čovjeka koji dobije dojavu, jer se otvara u svakom pregledniku bez ikakvih dodatnih alata. Ta dva zajedno koštaju jednu dodatnu liniju po datoteci i štede vašeg dežurnog inženjera najgoreg zadatka u skupnoj obradi, a to je obrnuti inženjering (reverse engineering) sirovog JSON blob-a u dva ujutro kako bi se saznalo koja se datoteka pokvarila. Jedna disciplina važnija je od odabira formata: izvedite svaki naziv izvješća iz naziva ulazne datoteke, nikada iz vremenske oznake (timestamp), inače će se dva paralelna izvođenja ispreplesti s izvješćima koja više ne možete povezati s njihovim ulazima
Pragovi ozbiljnosti (severity thresholds) pripadaju konfiguraciji, a ne kodu. Zabilješka bez alternativnog opisa je težak kvar (hard failure) za PDF/UA portal za podnošenje i napomena koja se može zanemariti za internu arhivu, a ipak je to identičan nalaz u oba slučaja. Izložite razinu za pad (fail-on) po profilu kako bi se pravila mogla promijeniti bez ponovnog prevođenja (recompile) te utisnite razinu koja je bila na snazi u sam sažetak posla. Sljedećeg kvartala nitko se neće sjećati pod kojim pragom se provodila skupna obrada prošlog listopada, a sažetak je jedino mjesto gdje to sjećanje preživljava
Izoliranje datoteka kako jedan loš PDF ne bi mogao potopiti skupinu
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;
U toj petlji žive tri promišljena izbora. Svježi TPdf po datoteci jamči da jedan dokument koji kvari stanje mehanizma ne može otrovati datoteke koje ga slijede. Eksplicitna provjera Active zaslužuje svoje mjesto jer Active := True guta pogreške pri učitavanju umjesto da ih pokreće; ispustite provjeru i skraćena datoteka odlutat će u poziv validacije prije nego što ne uspije negdje nizvodno s obmanjujućom porukom. Unutarnji try..except s namjerom živi unutar dosega pojedine datoteke, tako da jedna iznimka (exception) povećava brojač grešaka, a petlja se nastavlja. Želite čista izvješća za 4.999 dobrih datoteka, čak i kada je 5.000-ta datoteka uništena. Oba formata izvješća ispisuju se na disk prije nego što se presuda zbroji, što znači da dokazi preživljavaju čak i ako se greška kasnije u logici sažetka pogrešno zbroji
Mapiranje izlaznog koda tada se svodi na nekoliko redaka u projektnoj datoteci:
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.
Što prethodna provjera (preflight) neće učiniti za vas
Mehanizam otkriva; on ne popravlja. Nalaz o neugrađenom fontu ili prostoru boja ovisnom o uređaju radni je nalog za onoga tko proizvodi datoteke, a validator nema načina da to zakrpi na mjestu. Zato planirajte petlju povratnih informacija namjerno. Izvješća moraju sletjeti na mjesto gdje ih tim za proizvodnju zapravo čita, inače će se isti nalazi ponavljati svake noći dok netko konačno ne upita zašto se stopa usklađenosti nikada ne poboljšava. Također se isplati unakrsno provjeriti (cross-check) uzorak presuda s neovisnim validatorom, veraPDF za PDF/A ili Acrobatovim preflightom za PDF/X, prije nego što ih vanjski revizor unakrsno provjeri umjesto vas. Kad se dva mehanizma ne slažu oko stvarne korisničke datoteke, taj dokument nije smetnja; to je točno slučaj regresije koji je nedostajao vašem testiranju izdanja (release testing). Sačuvajte ga, imenujte i pokrenite pri svakom prevođenju (build)
Vrijedi znati još jedno uparivanje. Isti mehanizam za validaciju pokreće interaktivne provjere u korisničkom sučelju (UI) za pregled, pa ovaj CLI bez sučelja (headless) i radno okruženje za provjeru prihvata PDF-a usmjereno na analitičare mogu dijeliti jedan rječnik validacije umjesto da se s vremenom razilaze. A budući da [ppsPdfA, ppsPdfUa] procjenjuje pristupačnost u istom prolazu, PDF/UA strana skupne obrade čisto se podudara s radom na strani preglednika poput izrade pristupačnog PDF čitača u Delphiju. Profili, formati izvješća i potpuni API za prethodnu provjeru dokumentirani su na stranici proizvoda za komponentu PDFium Component