Filen åbner rent på din maskine. Acrobat viser den, printudsigten ser rigtig ud, hver side er der. Så går den til trykkeriet, eller ind i arkivsystemet, der modtager din månedlige batch, og den kommer tilbage afvist: RGB-billeder i et CMYK-job, ingen /Trapped-nøgle, en output intent, der ikke matcher trykket. Der var intet galt med dokumentet, nogen kunne se. Det var forkert mod en profil, og profilen blev tjekket et sted, du ikke var. Preflight er prepress-navnet for det tjek, og det reelle spørgsmål er, hvor det hører hjemme, når PDF'erne kommer ud af din egen Delphi-kode frem for fra en designers skrivebord
HotPDF giver dig ikke en preflight-funktion at kalde. Komponenten bærer et preflight-rapportvindue i sin GUI-demo, men der er ingen API bag det, en tjeneste eller et build-script kan påkalde, og at foregive andet ville sende dig ud på jagt efter en metode, der ikke findes. Det lyder som et hul, indtil man bemærker, at for filer, man selv genererer, er det at kalde en validator på sit eget output alligevel den forkerte form. Man kontrollerer allerede hver eneste egenskab, en validator ville inspicere. Den nyttige opdeling er at gøre generatoren ude af stand til at udsende en ikke-konform fil og derefter bevise det med et værktøj, man ikke selv skrev
Hvorfor man tjekker sit eget output anderledes
Traditionel preflight forudsætter en fremmeds fil. En eller anden designer, en eller anden applikation, en ukendt kæde af redigeringer producerede den, og man inspicerer den, fordi man ikke aner, hvad der er indeni. Et dokument, ens egen kode har produceret, er ikke en fremmed. Skrifttypeindlejring, farverum, output intent, metadata-blokken: ens program besluttede det hele få millisekunder, før filen ramte disken. At inspicere det bagefter for at opdage valg, man lige har truffet, er tomgangsarbejde. Det billigere træk er at begrænse de valg, så en ikke-konform fil aldrig kommer til at eksistere for at blive fanget
Der er også en troværdighedsgrund til at holde verifikationen ekstern. Et bibliotek, der velsigner sit eget output, retter sin egen eksamen. Når en kundes arkivsystem eller et trykkeris RIP afviser din fil, vejer "vores komponent siger, den er fin" ingenting. Det gør en dom fra veraPDF eller Acrobat derimod, fordi den anden side kører de samme værktøjer
Gør konformitet til en indstilling, ikke en tjekliste
Forebyggelseslaget er blot konfiguration. Sæt PDFACompliance eller PDFXCompliance før BeginDoc, og HotPDF håndhæver de tilsvarende regler for hele genereringspasset: den indlejrer skrifttyper, holder øje med brugen af DeviceRGB og DeviceCMYK mod den output intent, man har erklæret, og afviser funktioner, profilen forbyder. Modsigelserne dukker op ved EndDoc, hvor compliance-portene rejser en undtagelse frem for stille at sende noget af sted, der vil fejle længere nede i strømmen. Når filen er gemt, læser de samme egenskaber tilbage, hvad der rent faktisk blev håndhævet, hvilket er det ene faktum, din pipeline-log har mest brug for:
// Efter EndDoc: registrér de håndhævede profiler sammen med kørselsmetadata
if Pdf.PDFACompliance <> '' then
Log('Generated as PDF/A level ' + Pdf.PDFACompliance);
if Pdf.PDFXCompliance <> '' then
Log('Generated as PDF/X profile ' + Pdf.PDFXCompliance);
Sæt disse flag på den samme log-linje som input-datahashen og HotPDF-versionen. Den dag en validator og din generator er uenige om en fil, fortæller den linje dig, hvilken skabelon der producerede den, og hvilken build af biblioteket der var indlæst, og diskussionen, der ellers ville æde en eftermiddag, bliver til en grep. De output intents, ICC-profiler og tagging, der ligger bag disse flag, er beskrevet i guiden til PDF/A-, PDF/X- og PDF/UA-output med HotPDF
En billig første port for filer, du ikke selv genererede
Ikke hver eneste pipeline er rent generativ. Kunder uploader PDF'er, scannere lægger dem i en mappe, partnere vedhæfter dem til e-mail. At skubbe hver eneste af dem gennem en fuld strukturel validator spilder køtid på filer, der ikke engang vil åbne. HotPDF's Direct File API læser nok af en fils struktur til at besvare "er dette overhovedet en brugbar PDF" uden at indlæse hele objekttræet, hvilket gør det til et godt sted at fejle hurtigt:
function TriagePdf(Pdf: THotPDF; const FileName: string): Boolean;
var
Handle, Pages: Integer;
begin
Result := False;
Handle := Pdf.DAOpenFileReadOnly(FileName, '');
if Handle <= 0 then
Exit; // strukturelt ulæselig: sæt i karantæne, valider ikke
try
Pages := Pdf.DAGetPageCount(Handle);
Result := Pages > 0;
finally
Pdf.DACloseFile(Handle);
end;
end;
To fakta om dette API afgør, hvordan man pakker det ind. Genvejen med flad hukommelse gælder kun for ukrypteret input; giver man DAOpenFileReadOnly en adgangskode, falder den stille tilbage til en fuld parsing, så en fil, man ved er krypteret, bør gå gennem DecryptFile til en almindelig arbejdskopi før triage. Og DAGetPageCount betyder intet på et handle, der ikke åbnede rent, så handle-tjekket forbliver strengt, og et ikke-positivt resultat er en afvisning, ikke et nyt forsøg. Flere af disse mønstre findes i Direct File API-artiklen til store PDF-workflows
veraPDF, kørt som en del af build'en
For alt, du hævder er PDF/A eller PDF/UA, er veraPDF den validator, man skal koble ind. Den kører uden GUI, tager en batch, udsender XML eller JSON og navngiver hver fejl efter dens ISO-paragraf, så en regelfejl mod ISO 19005-1, klausul 6.2.2, peger direkte tilbage på en generatorindstilling i stedet for at lade dig gætte. At styre den fra Delphi er almindelig proceskontrol:
function RunVeraPdf(const PdfFile, ReportFile: string): Cardinal;
var
Cmd: string;
SI: TStartupInfo;
PI: TProcessInformation;
begin
Cmd := Format('cmd /c verapdf.bat --format xml "%s" > "%s"',
[PdfFile, ReportFile]);
FillChar(SI, SizeOf(SI), 0);
SI.cb := SizeOf(SI);
if not CreateProcess(nil, PChar(Cmd), nil, nil, False,
CREATE_NO_WINDOW, nil, nil, SI, PI) then
RaiseLastOSError;
try
WaitForSingleObject(PI.hProcess, 120000); // afgræns ventetiden per fil
GetExitCodeProcess(PI.hProcess, Result);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end;
Den timeout tjener sin plads. En fejlformet fil kan drive enhver parser ind i et hjørne, den aldrig kommer ud af igen, og en åben-ende ventetid inde i en køworker trækker resten af køen ned med sig. Afgræns ventetiden, giv en timeout sin egen fejlkode, og læg filen til side til et menneske. Når man læser resultatet, så parse XML'en efter regel-identifikatorer, ikke efter den menneskelæsbare tekst. Regel-ID'er overlever validator-opgraderinger; ordlyden af beskederne gør ikke, og en stabil kode er noget, en supportmedarbejder kan søge gamle sager op imod
Hvordan man kører batchen betyder lige så meget som, om hver fil består. Én proces per fil, ikke én per batch, så et giftigt input kun koster den fils timeout og intet andet. Loft antallet af validator-processer ved kerneantallet, fordi det at bygge XML-rapporten er CPU-bundet, og oversubskription bare fører til trashing. Og sæt et størrelsesloft ved indtag, fordi en to-gigabyte scannet bog vil eje køen, uanset hvor tålmodig parseren er. Intet af det er preflight i streng forstand. Det er forskellen mellem en port, der overlever måned-slut-volumen, og én, der bliver slukket den første nat, den går i stå i pipelinen klokken 2 om natten
PDF/X er, hvor dette kommer til kort. veraPDF validerer den ikke, så det arbejdende tjek er stadig Acrobats Preflight med den ISO 15930-profil, din trykker navngav. Acrobat vil have et menneske, hvilket betyder stikprøver frem for fuld dækning: den første fil fra en ny skabelon, plus et lille tilfældigt udtræk fra hver batch, mens den automatiserede port håndterer alt, der kan håndteres uden et menneske. Et stikprøvetjek, der rent faktisk kører, slår en komplet automatisering, der forbliver halvfærdig for evigt
En rapport, man stadig vil ønske sig om et år
En preflight-port betaler sig to gange. Én gang, når den standser en dårlig fil ved døren, og igen meget senere, når nogen spørger, hvorfor en bestemt fil blev lukket igennem. Det andet øjeblik er det, der bør diktere formatet, fordi det er det, hvor en tynd rapport lader dig sidde fast. For hver fil, der tjekkes, gem input-hashen, generatorens compliance-flag og biblioteksversion fra log-linjen ovenfor, validatorens navn og version, den profil, den blev tjekket mod, bestået eller ej, og de fejlede regel-ID'er med sidetal, hvor validatoren giver dem. Gem den rapport ved siden af den fil, den beskriver. Læg den i et separat system, og det system vil blive udfaset, før det arkiv, det dokumenterer
Undtagelser skal også skrives ned. Når en kunde insisterer på at sende en fil, porten ikke bryder sig om, er svaret ikke at løsne reglen for alle. Registrér hvem der godkendte den fil, på hvilket grundlag, og indtil hvilken dato, og hæft så det dispensationsbevis på dens rapport. En dispensation med et navn og en udløbsdato er en beslutning, nogen ejer. Et tjek, der er kommenteret ud "midlertidigt", er en hændelse, der venter på sin dato
Endnu en vane betaler sig selv: når en fil fejler, kopiér den ind i en navngivet regressionsmappe, før nogen rører den. Næsten hvert eneste preflight-problem, det er værd at debugge, kan spores tilbage til ét bestemt input, og de teams, der holder fast i de inputs, fikser gentagelsen på en time i stedet for at vente på, at den dukker op igen i produktion. Compliance-egenskaberne og Direct File API'et, der vises her, er en del af HotPDF Delphi Component til Delphi og C++Builder, hvis dokumentation dækker hvert kald i sin helhed