Het bestand opent probleemloos op uw machine. Acrobat toont het, de afdrukvoorbeeld ziet er goed uit, elke pagina is er. Dan gaat het naar de drukkerij, of naar het archiefsysteem dat uw maandelijkse batch inneemt, en het komt verworpen terug: RGB-afbeeldingen in een CMYK-klus, geen /Trapped-key, een output-intent die niet op de pers past. Er was niets mis met het document dat iemand kon zien. Het was fout tegen een profiel, en het profiel werd ergens gecontroleerd waar u niet was. Preflight is de prepress-naam voor die controle, en de echte vraag is waar hij thuishoort wanneer de PDF's uit uw eigen Delphi-code komen in plaats van van een ontwerpers-bureaublad
HotPDF geeft u geen preflight-functie om aan te roepen. De component draagt een preflight-rapportvenster in zijn GUI-demo, maar er zit geen API achter die een service of build-script kan aanroepen, en anders doen alsof zou u op zoek sturen naar een methode die er niet is. Dat klinkt als een gat tot u opmerkt dat voor bestanden die u zelf genereert, een validator op uw eigen output aanroepen hoe dan ook de verkeerde vorm is. U beheert al elke eigenschap die een validator zou inspecteren. De bruikbare splitsing is de generator oncapabel maken een slecht bestand te emitten, en het dan bewijzen met een tool die u niet schreef
Waarom u uw eigen output anders controleert
Traditionele preflight neemt een vreemdelingsbestand aan. Een of andere ontwerper, een andere applicatie, een onbekende reeks bewerkingen produceerde het, en u inspecteert het omdat u geen idee hebt wat erin zit. Een document dat uw code produceerde is geen vreemdeling. Lettertype-inbedding, kleurruimte, output-intent, het metadatablok: uw programma besliste er allemaal over een paar milliseconden voordat het bestand de schijf raakte. Het achteraf inspecteren om keuzes te ontdekken die u net maakte is bezigheidswerk. De goedkopere zet is die keuzes te beperken zodat een niet-compliant bestand nooit bestaat om betrapt te worden
Er is ook een geloofwaardigheidsreden om verificatie extern te houden. Een bibliotheek die zijn eigen output zegent is zijn eigen examen aan het nakijken. Wanneer het archiefsysteem van een klant of de RIP van een drukkerij uw bestand verwerpt, draagt "onze component zegt dat het goed is" geen gewicht. Een vonnis van veraPDF of Acrobat wel, want de andere kant draait dezelfde tools
Maak compliance een instelling, geen checklist
De preventielaag is gewoon configuratie. Stel PDFACompliance of PDFXCompliance in vóór BeginDoc en HotPDF houdt de overeenkomstige regels aan voor de hele generatiepas: het embedt lettertypen, volgt DeviceRGB- en DeviceCMYK-gebruik tegen de output-intent die u declareerde, en weigert features die het profiel verbiedt. De tegenspraken komen bovendrijven bij EndDoc, waar de compliance-gates raisen in plaats van stilzwijgend iets te verschepen dat stroomafwaarts zal falen. Zodra het bestand is opgeslagen, lezen dezelfde eigenschappen terug wat er werkelijk werd afgedwongen, en dat is het ene feit dat uw pipeline-log het meest nodig heeft:
// Na EndDoc: leg de afgedwongen profielen vast bij de run-metadata
if Pdf.PDFACompliance <> '' then
Log('Generated as PDF/A level ' + Pdf.PDFACompliance);
if Pdf.PDFXCompliance <> '' then
Log('Generated as PDF/X profile ' + Pdf.PDFXCompliance);
Zet die vlaggen op dezelfde log-regel als de hash van de inputdata en de HotPDF-versie. De dag dat een validator en uw generator het oneens zijn over een bestand, vertelt die regel welk sjabloon het produceerde en welke build van de bibliotheek was geladen, en de ruzie die anders een middag zou kosten wordt een grep. De output-intents, ICC-profielen en tagging die achter deze vlaggen zitten worden uitgespeld in de gids voor PDF/A-, PDF/X- en PDF/UA-output met HotPDF
Een goedkope eerste poort voor bestanden die u niet zelf genereerde
Niet elke pipeline is zuiver generatief. Klanten uploaden PDF's, scanners droppen ze in een map, partners hangen ze aan e-mail. Elke daarvan door een volledige structurele validator duwen verspilt queue-tijd aan bestanden die niet eens openen. HotPDF's Direct File API leest genoeg van de structuur van een bestand om "is dit überhaupt een bruikbare PDF" te beantwoorden zonder de hele objectstructuur te laden, wat het een goede plek maakt om snel te falen:
function TriagePdf(Pdf: THotPDF; const FileName: string): Boolean;
var
Handle, Pages: Integer;
begin
Result := False;
Handle := Pdf.DAOpenFileReadOnly(FileName, '');
if Handle <= 0 then
Exit; // structureel onleesbaar: quarantaine, niet valideren
try
Pages := Pdf.DAGetPageCount(Handle);
Result := Pages > 0;
finally
Pdf.DACloseFile(Handle);
end;
end;
Twee feiten over deze API bepalen hoe u hem inpakt. De flat-memory-snelkoppeling geldt alleen voor onversleutelde input; overhandig DAOpenFileReadOnly een wachtwoord en het valt stilletjes terug op een volledige parse, dus een bestand dat u weet dat versleuteld is, moet door DecryptFile naar een gewone werkende kopie vóór triage. En DAGetPageCount betekent niets op een handle die niet probleemloos opende, dus de handle-controle blijft streng en een niet-positief resultaat is een verworpen, geen hertry. Meer van dit soort patronen leven in het Direct File API-artikel voor grote PDF-workflows
veraPDF, gedraaid als deel van de build
Voor alles wat u als PDF/A of PDF/UA claimt, is veraPDF de validator om in te bedden. Het draait headless, neemt een batch, emit XML of JSON, en noemt elke fout bij zijn ISO-clausule, dus een regel-fout tegen ISO 19005-1 clausule 6.2.2 wijst rechtstreeks terug naar een generator-instelling in plaats van u te laten raden. Het aansturen vanuit Delphi is gewone procescontrole:
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); // begrens de wachttijd per bestand
GetExitCodeProcess(PI.hProcess, Result);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end;
Die time-out verdient zijn plaats. Een misvormd bestand kan elke parser in een hoek drijven waar hij nooit uit komt, en een onbegrensde wacht binnen een queue-worker sleept de rest van de queue met zich mee omlaag. Begrens de wacht, geef een time-out zijn eigen faalcode, en leg het bestand apart voor een mens. Wanneer u het resultaat leest, parse de XML op regel-identifiers, niet op de menselijk leesbare tekst. Regel-ID's overleven validator-upgrades; de bewoording van de berichten niet, en een stabiele code is iets waartegen een support-engineer oude tickets kan doorzoeken
Hoe u de batch draait telt evenveel als of elk bestand slaagt. Eén proces per bestand, niet één per batch, zodat een giftige input u alleen de time-out van dat bestand kost en niets meer. Kap het aantal validator-processen op het core-aantal, want het bouwen van het XML-rapport is CPU-bound en oversubscription levert alleen maar thrash op. En zet een plafond op de grootte bij intake, want een gescand boek van twee gigabyte zal de queue domineren hoe geduldig de parser ook is. Niets daarvan is preflight in de strikte zin. Het is het verschil tussen een poort dat door month-end-volume heen leeft en een dat de eerste nacht dat het de pipeline om 2 uur 's nachts laat vastlopen wordt uitgezet
PDF/X is waar dit tekortschiet. veraPDF valideert het niet, dus de werkende controle is nog steeds Acrobats Preflight met het ISO 15930-profiel dat uw drukker noemde. Acrobat wil een mens, wat sampling in plaats van volledige dekking betekent: het eerste bestand van een nieuw sjabloon, plus een kleine willekeurige trekking uit elke batch, terwijl de geautomatiseerde poort alles afhandelt dat zonder mens kan worden afgehandeld. Een bemonsterde controle die werkelijk draait verslaat een volledige automatisering die voor altijd half afgemaakt blijft
Een rapport dat u over een jaar nog steeds wilt
Een preflight-poort betaalt zich tweemaal uit. Eén keer wanneer hij een slecht bestand aan de deur stopt, en nog eens veel later wanneer iemand vraagt waarom een bepaald bestand werd doorgelaten. Dat tweede moment is het moment dat de vorm moet dicteren, want het is het moment waarop een dun rapport u aan de grond laat lopen. Houd voor elk gecontroleerd bestand de input-hash bij, de compliance-vlaggen en bibliotheekversie van de generator uit de log-regel hierboven, de validator-naam en -versie, het profiel waartegen het gecontroleerd werd, de slag of faal, en de gefaalde regel-ID's met paginanummers waar de validator ze geeft. Bewaar dat rapport naast het bestand dat het beschrijft. Zet het in een apart systeem en dat systeem wordt uitgefaseerd voordat het archief dat het documenteert
Uitzonderingen moeten ook worden opgeschreven. Wanneer een klant erop staat een bestand te verschepen dat de poort niet leuk vindt, is het antwoord niet om de regel voor iedereen te versoepelen. Registreer wie dit bestand goedkeurde, op welke gronden, en tot welke datum, en hecht dan die ontheffing aan zijn rapport. Een ontheffing met een naam en een vervaldatum is een beslissing die iemand bezit. Een controle die "tijdelijk" is uitgecommentarieerd is een incident dat op zijn datum wacht
Nog één gewoonte betaalt voor zichzelf: wanneer een bestand faalt, kopieer het dan naar een genoemde regressiemap voordat iemand het aanraakt. Vrijwel elk preflight-problem dat het debuggen waard is herleidt zich tot één specifieke input, en de teams die die inputs vasthouden repareren de terugkeer in een uur in plaats van te wachten tot hij in productie weer opduikt. De compliance-eigenschappen en Direct File API die hier getoond worden zijn deel van de HotPDF Delphi Component voor Delphi en C++Builder, wiens documentatie elke aanroep volledig behandelt