Filen öppnas felfritt på din maskin. Acrobat visar den, förhandsgranskningen för utskrift ser rätt ut, varje sida finns där. Sedan går den till tryckeriet, eller till arkivsystemet som tar emot din månatliga batch, och den kommer tillbaka refuserad: RGB-bilder i ett CMYK-jobb, ingen /Trapped-nyckel, en output intent som inte matchar pressen. Inget var fel med dokumentet som någon kunde se. Det var fel mot en profil, och profilen kontrollerades någon annanstans än hos dig. Preflight är förtrycksbranschens namn för den kontrollen, och den verkliga frågan är var den hör hemma när PDF-filerna kommer ut ur din egen Delphi-kod i stället för från en designers skrivbord
HotPDF ger dig ingen preflight-funktion att anropa. Komponenten har ett preflight-rapportfönster i sin GUI-demo, men det finns inget API bakom det som en tjänst eller ett byggskript kan anropa, och att låtsas annat skulle skicka dig ut på jakt efter en metod som inte finns. Det låter som ett hål tills du märker att för filer du genererar själv är det ändå fel form att anropa en validerare på din egen utdata. Du styr redan varje egenskap en validerare skulle inspektera. Det användbara greppet är att göra generatorn oförmögen att skapa en dålig fil, och sedan bevisa det med ett verktyg du inte skrev själv
Varför du kontrollerar din egen utdata annorlunda
Traditionell preflight förutsätter en främlings fil. Någon designer, någon annan applikation, någon okänd kedja av redigeringar producerade den, och du inspekterar den för att du inte har en aning om vad som finns i den. Ett dokument din kod producerade är ingen främling. Typsnittsinbäddning, färgrymd, output intent, metadatablocket: ditt program bestämde allt det där några millisekunder innan filen träffade disken. Att inspektera det i efterhand för att upptäcka val du just gjort är onödigt arbete. Det billigare draget är att begränsa de valen så att en icke-kompatibel fil aldrig existerar för att fångas upp
Det finns också en trovärdighetsanledning att hålla verifieringen extern. Ett bibliotek som välsignar sin egen utdata rättar sitt eget prov. När en kunds arkivsystem eller ett tryckeris RIP refuserar din fil väger "vår komponent säger att det är bra" ingenting. Ett utlåtande från veraPDF eller Acrobat väger, eftersom motparten kör samma verktyg
Gör efterlevnad till en inställning, inte en checklista
Förebyggandelagret är bara konfiguration. Sätt PDFACompliance eller PDFXCompliance före BeginDoc och HotPDF håller de motsvarande reglerna för hela genereringspasset: den bäddar in typsnitt, bevakar användning av DeviceRGB och DeviceCMYK mot output intent du har deklarerat, och vägrar funktioner profilen förbjuder. Motsägelserna dyker upp vid EndDoc, där efterlevnadsspärrarna utlöser i stället för att tyst leverera något som kommer att misslyckas nedströms. När filen väl är sparad läser samma egenskaper tillbaka vad som faktiskt verkställdes, vilket är det enskilda faktum din pipelinelogg mest behöver:
// Efter EndDoc: registrera de verkställda profilerna med körningens 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);
Placera de flaggorna på samma loggrad som indatans hashvärde och HotPDF-versionen. Den dag en validerare och din generator inte håller med varandra om en fil, talar den raden om för dig vilken mall som producerade den och vilken bygg av biblioteket som var laddad, och diskussionen som annars skulle äta upp en eftermiddag blir en grep. Output intents, ICC-profiler och taggning som ligger bakom de här flaggorna beskrivs i guiden om PDF/A-, PDF/X- och PDF/UA-utdata med HotPDF
En billig första spärr för filer du inte genererade
Inte varje pipeline är rent genererande. Kunder laddar upp PDF-filer, skannrar släpper dem i en mapp, partners bifogar dem i e-post. Att driva var och en av dem genom en fullständig strukturell validerare slösar köutrymme på filer som inte ens kommer att öppnas. HotPDFs Direct File API läser tillräckligt av en fils struktur för att svara på "är det här överhuvudtaget en användbar PDF" utan att ladda hela objektträdet, vilket gör det till ett bra ställe att misslyckas snabbt på:
function TriagePdf(Pdf: THotPDF; const FileName: string): Boolean;
var
Handle, Pages: Integer;
begin
Result := False;
Handle := Pdf.DAOpenFileReadOnly(FileName, '');
if Handle <= 0 then
Exit; // strukturellt oläsbar: sätt i karantän, validera inte
try
Pages := Pdf.DAGetPageCount(Handle);
Result := Pages > 0;
finally
Pdf.DACloseFile(Handle);
end;
end;
Två fakta om det här API:et avgör hur du kapslar in det. Genvägen med platt minne gäller bara för okrypterad indata; ge DAOpenFileReadOnly ett lösenord och den faller tyst tillbaka till en fullständig tolkning, så en fil du vet är krypterad bör gå genom DecryptFile till en vanlig arbetskopia före triagen. Och DAGetPageCount betyder ingenting på ett handtag som inte öppnades rent, så handtagskontrollen förblir strikt och ett icke-positivt resultat är en refusering, inte ett omförsök. Fler av dessa mönster finns i artikeln om Direct File API för stora PDF-arbetsflöden
veraPDF, körd som en del av bygget
För allt du hävdar är PDF/A eller PDF/UA är veraPDF validatorn att koppla in. Den körs headless, tar en batch, skriver ut XML eller JSON, och namnger varje fel efter dess ISO-klausul, så ett regelfel mot ISO 19005-1 klausul 6.2.2 pekar rakt tillbaka på en generatorinställning i stället för att lämna dig att gissa. Att styra den från Delphi är enkel processkontroll:
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); // begränsa väntan per fil
GetExitCodeProcess(PI.hProcess, Result);
finally
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
end;
end;
Den timeouten tjänar sitt uppehälle. En felformad fil kan driva vilken parser som helst in i ett hörn den aldrig kommer ut ur, och en obegränsad väntan inuti en könarbetare drar ner resten av kön med sig. Begränsa väntan, ge en timeout sin egen felkod, och lägg filen åt sidan för en människa. När du läser resultatet, tolka XML:en för regelidentifierare, inte för den mänskligt läsbara texten. Regel-ID:n överlever validatoruppgraderingar; ordalydelsen i meddelandena gör det inte, och en stabil kod är något en supporttekniker kan söka gamla ärenden mot
Hur du kör batchen spelar lika stor roll som om varje fil klarar sig. En process per fil, inte en per batch, så en giftig indata kostar dig bara den filens timeout och inget annat. Begränsa antalet validatorprocesser till kärnantalet, eftersom att bygga XML-rapporten är CPU-bundet och överteckning bara tröskar sönder. Och sätt ett storlekstak vid intaget, för en tvågigabyte skannad bok kommer att äga kön oavsett hur tålmodig parsern är. Inget av det där är preflight i strikt mening. Det är skillnaden mellan en spärr som lever igenom månadsslutets volym och en som slås av den första natten den stannar upp pipelinen klockan två på morgonen
PDF/X är där det här kommer till korta. veraPDF validerar inte det, så den fungerande kontrollen är fortfarande Acrobats Preflight med ISO 15930-profilen din tryckare namngav. Acrobat vill ha en människa, vilket betyder stickprov snarare än full täckning: den första filen från en ny mall, plus ett litet slumpmässigt urval från varje batch, medan den automatiserade spärren hanterar allt som kan hanteras utan en. En stickprovskontroll som faktiskt körs slår en fullständig automation som förblir halvfärdig för evigt
En rapport du fortfarande vill ha om ett år
En preflight-spärr betalar sig två gånger. En gång när den stoppar en dålig fil vid dörren, och igen mycket senare när någon frågar varför en viss fil släpptes igenom. Det andra ögonblicket är det som borde styra formatet, eftersom det är det där en tunn rapport lämnar dig strandsatt. För varje kontrollerad fil, spara indatans hashvärde, generatorns efterlevnadsflaggor och biblioteksversion från loggraden ovan, validatorns namn och version, profilen den kontrollerades mot, godkänt eller underkänt, och de underkända regel-ID:na med sidnummer där validatorn ger dem. Lagra den rapporten bredvid filen den beskriver. Placera den i ett separat system och det systemet kommer att avvecklas innan arkivet det dokumenterar gör det
Undantag behöver skrivas ner också. När en kund insisterar på att leverera en fil spärren ogillar, är svaret inte att luckra upp regeln för alla. Registrera vem som godkände den här filen, på vilka grunder, och till och med vilket datum, koppla sedan det undantaget till dess rapport. Ett undantag med ett namn och ett utgångsdatum är ett beslut någon äger. En kontroll avkommenterad "tillfälligt" är en incident som väntar på sitt datum
En vana till betalar sig själv: när en fil misslyckas, kopiera in den i en namngiven regressionsmapp innan någon rör den. Nästan varje preflight-problem värt att felsöka spårar tillbaka till en specifik indata, och de team som behåller de indatafilerna löser återfall på en timme i stället för att vänta på att det dyker upp igen i produktion. Efterlevnadsegenskaperna och Direct File API som visas här är en del av HotPDF Delphi Component för Delphi och C++Builder, vars dokumentation täcker varje anrop i sin helhet