PDFium-komponenten för Delphi validerar tryckfärdiga PDF/X-dokument via TPdf.ValidatePdfX, som implementerar ISO 15930-kontroll i två skikt: åtta innehållskontroller på byte-nivå (förbjuden LZW-komprimering, JavaScript, formulärfält, OPI-referenser, saknad TrimBox, odefinierad Trapped-nyckel med mera) samt en genomgång av PDFiums objektmodell som använder FPDFFont_GetIsEmbedded för att verifiera teckensnittsinbäddning på varje textobjekt på varje sida. Resultatet är en TPdfXValidationResult-post som anger den upptäckta överensstämmelsenivån och listar varje överträdelse som en typdefinierad enum, så att din Delphi-applikation kan berätta för en kund exakt varför en fil kommer att avvisas på tryckeriet innan någon ens har bränt en plåt
Om du någonsin har skickat ett jobb till ett kommersiellt tryckeri och fått tillbaka det med ett kort avvisande — ”ingen TrimBox”, ”teckensnitt ej inbäddade”, ”Trapped ej inställt” — känner du till kostnaden av att upptäcka detta för sent. PDF/X är prepress-motsvarigheten till PDF/A: där arkiv-PDF/A garanterar att ett dokument renderas identiskt decennier från nu, PDF/X garanterar att ett dokument separeras, bildsätts och beskärs identiskt på någon annans RIP imorgon bitti. De två standarderna delar mekanismer (XMP-identifiering, OutputIntents, inbäddade ICC-profiler) men svarar på olika frågor, vilket är anledningen till att komponenten levererar separata validerare för var och en — PDF/A-sidan täcks i PDF/A-preflightvalidering med PDFium Component
Vad kräver ISO 15930 egentligen av en tryckfärdig PDF?
ISO 15930 existerar för att göra blind exchange (blint utbyte) möjligt: en designer överlämnar en fil till ett tryckeri de aldrig har pratat med, och tryckeriet kan producera korrekt utskrift utan telefonsamtal, utan e-postmeddelanden om saknade teckensnitt och utan länkade bilder som glömdes kvar på designerns dator. Varje regel i standarden tjänar det målet. Teckensnitt måste vara inbäddade eftersom den mottagande RIP-enheten inte kan antas äga dem. Externa referenser är förbjudna eftersom filen måste vara fullständig i sig själv. Interaktiva funktioner är förbjudna eftersom bläck inte har någon onclick-hanterare
PDFium-komponenten känner igen tre överensstämmelsefamiljer och rapporterar dem via TPdfXConformance-enumet i valideringsresultatet: pxc1a för PDF/X-1a:2001 (ISO 15930-1, den strikta baslinjen CMYK-plus-spot på PDF 1.3/1.4), pxc3 för PDF/X-3:2002 (ISO 15930-3, som tillåter RGB, Lab och ICC-hanterad färg) och pxc4 för PDF/X-4:2010 (ISO 15930-7, som slutligen tillåter levande transparens och lager på en PDF 1.6-bas). En fil som inte har någon PDF/X-identifiering alls returneras som pxcNone, vilket i sig är ett användbart svar: dokumentet har aldrig påstått sig vara tryckfärdigt, och allt annat som valideraren rapporterar förklarar vad som krävs för att nå dit
Förbuden blir logiska när du tänker som en RIP-leverantör. /LZWDecode är förbjudet i alla PDF/X-varianter så att en överensstämmande konsument aldrig är beroende av ett filter med en kompatibilitets- och licenshistorik; Flate gör samma jobb utan bagaget. JavaScript, AcroForm-fält och /AA-ordböcker för ytterligare åtgärder (additional-action) är förbjudna eftersom en tryckfil måste vara en fast beskrivning av märken på papper — allt som kan förändra utseendet vid öppningstillfället bryter garantin för att det som korrekturprovats är det som trycks. OPI-platshållare (Open Prepress Interface) är förbjudna eftersom de av design är referenser till högupplösta bilder som sparats någon annanstans, och ”någon annanstans” är exakt vad blint utbyte förbjuder
Varför avvisar tryckerier PDF-filer utan en TrimBox?
TrimBox är den färdiga sidan — rektangeln som återstår efter att giljotinen klippt. MediaBox, som varje PDF-sida har, is merely the sheet: it includes bleed, crop marks, registration targets, and color bars. Imposition software positions pages on a press sheet by their TrimBoxes; without one, the operator has to guess where your business card actually ends, and a wrong guess trims off your bleed or leaves a white sliver on one edge. Det är därför ISO 15930 kräver en TrimBox (or an ArtBox) on every page, and why ValidatePdfX raises pvxiMissingTrimBox when no /TrimBox key is found on any page of the document
Nyckeln /Trapped svarar på en annan produktionsfråga. Trapping (färgsmitning) är prepress-tekniken att låta intilliggande färger överlappa något så att små tryckfelmarginaler inte öppnar vita glipor mellan dem. Tryckeriet måste veta om det arbetet redan har utförts: att lägga till trapping på en redan trapped fil dubblerar överlappningarna, och att hoppa över trapping på en fil som inte är trapped riskerar synliga glipor. PDF/X kräver därför att Info-ordboken uttryckligen anger /Trapped /True eller /Trapped /False — en saknad nyckel eller /Unknown tvingar en människa att inspektera filen, vilket är exakt det samtal som blint utbyte var tänkt att eliminera. Komponenten flaggar detta som pvxiTrappedNotSet
Kör valideringen i två skikt med TPdf.ValidatePdfX
TPdf.ValidatePdfX tar inga argument och returnerar en TPdfXValidationResult-post med tre medlemmar: Conformance (den upptäckta PDF/X-varianten), Issues (en Pascal-mängd av TPdfXValidationIssue-värden) och en IsCompliant-hjälpare. Internt validerar den det inlästa dokumentet, serialiserar det till en minnesström, kör byte-nivåinspektören över det och går sedan igenom PDFiums objektmodell för kontrollen av teckensnittsinbäddning. En minimal preflight-kontroll ser ut så här:
uses PDFium, FPdfPdfx;
procedure CheckPrintReadiness(const FileName: string);
var
Pdf: TPdf;
Res: TPdfXValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := FileName;
Pdf.Active := True;
Res := Pdf.ValidatePdfX;
Writeln('Detected conformance: ',
Ord(Res.Conformance)); // pxc1a, pxc3, pxc4, pxcNone...
if Res.IsCompliant then
Writeln('PDF/X-kontroller godkända')
else
begin
if pvxiMissingTrimBox in Res.Issues then
Writeln('REJECT: ingen /TrimBox på sidorna');
if pvxiTrappedNotSet in Res.Issues then
Writeln('REJECT: /Trapped saknas eller är /Unknown');
if pvxiPdfiumFontNotEmbedded in Res.Issues then
Writeln('REJECT: en sida använder ett ej inbäddat teckensnitt');
if pvxiLzwForbidden in Res.Issues then
Writeln('REJECT: LZWDecode-filter finns');
end;
finally
Pdf.Free;
end;
end;
Eftersom Issues är en vanlig Pascal-mängd kan du dela upp den som ditt arbetsflöde kräver — behandla strukturella problem som hårda avvisanden, behandla pvxiMissingTitle (ett BÖR i standarden, inte ett MÅSTE) som en varning och logga resten. Samma posttyp matar också komponentens rapportgenerator, så om du hellre vill skapa ett mänskligt läsbart dokument än att grena dig efter enums, gäller mönstret i att bygga en CLI för batch-preflightrapporter med PDFium Component oförändrat för PDF/X
Vad skiktet på byte-nivå fångar — och vad det missar
Byte-skanningen är snabb och behöver ingen renderingsmotor, eftersom den skannar dokumentets strukturella bytes med strömmar tömda, så att en JPEG som råkar innehålla bytemönstret /JavaScript inte kan trigga falska positiva. Utöver markörkontrollerna (XMP pdfxid:GTS_PDFXVersion, OutputIntent med en inbäddad ICC-profil, trailer-/ID, samt krypteringsförbudet) lägger innehållspasset till åtta kontroller, var och en med sitt eget enum-värde:
pvxiLzwForbidden— ett/LZWDecode-filter förekommer någonstans i filen (förbjudet i alla PDF/X-varianter)pvxiJavaScriptForbidden— en/JavaScript-åtgärd eller namnträd finnspvxiFormFieldsForbidden— en/AcroForm-ordbok eller/XFA-post finnspvxiAdditionalActions— en/AA-ordbok för ytterligare åtgärder finnspvxiEmbeddedFilesForbidden—/EmbeddedFileseller en/FileAttachment-anteckning finnspvxiOpiForbidden— en/OPI- eller/Alternates-post refererar till ersättningsbart bildinnehållpvxiMissingTrimBox— ingen/TrimBoxhittades på någon sidapvxiTrappedNotSet—/Trappedsaknas eller är satt till/Unknown
Byte-skanning är snabb och behöver ingen renderingsmotor, men den har en inneboende blind fläck med teckensnitt: på den nivån kan inspektören endast tillämpa en grov heuristik — den flaggar ett dokument när den inte hittar något inbäddat teckensnittsprogram alls. En fil med nio inbäddade teckensnitt och ett systemteckensnitt insmuget ser okej ut för en byte-skanning. Denna enda lucka är anledningen till att det andra skiktet existerar
Inbäddning per teckensnitt via PDFiums objektmodell
PDFium-komponentens objektmodellskikt besvarar teckensnittsfrågan exakt. Efter byte-nivå-passet itererar TPdf.ValidatePdfX över varje sida, frågar FPDFPage_CountObjects efter objektlistan, och för varje textobjekt tar den reda på teckensnittshandtaget via FPDFTextObj_GetFont och frågar FPDFFont_GetIsEmbedded. Ett enda ej inbäddat teckensnitt någonstans i dokumentet lägger till pvxiPdfiumFontNotEmbedded i mängden problem. Sökningen kortsluts på två nivåer — den slutar skanna objekt på en sida och slutar ladda ytterligare sidor i samma ögonblick som problemet bekräftas — så på en felaktig 300-sidig katalog kommer domen ofta redan efter sida ett
Två gränsfall som är värda att känna till. För det första behöver detta skikt att PDFium-biblioteket är laddat och kräver byggen som exporterar FPDFFont_GetIsEmbedded; när exporten saknas hoppas kontrollen över snarare än att misslyckas, så en äldre DLL producerar aldrig falska avvisanden. För det andra besvarar kontrollen ”inbäddad eller inte” och inget mer — den skiljer inte på slutgiltig inbäddning och undergruppsinbäddning (subsetting), och inspekterar inte heller glyph-täckning. När en fil misslyckas och du behöver veta vilket teckensnitt på vilken sida, tar uppräkningsteknikerna i att analysera PDF-teckensnittsegenskaper med PDFium i Delphi vid exakt där validerarens booleska värde slutar
Validera strömmar utan att ladda ett dokument — eller DLL:en
Byte-nivåinspektören exponeras också som en fristående funktion, ValidatePdfXCompliance(Source: TStream) i enheten FPdfPdfx, och den är ren Object Pascal utan beroende av PDFium DLL:en. Det gör den driftsättbar på platser där en renderingsmotor är ovälkommen: en lättviktig uppladdningsgrind på en webbserver, ett CI-jobb som granskar skapat grafiskt material, eller en Lazarus-tjänst på en plattform där du hellre inte vill leverera inbyggda binärer. Mata den med valfri sökbar ström:
uses Classes, FPdfPdfx;
function QuickPdfXGate(const FileName: string): Boolean;
var
Fs: TFileStream;
Res: TPdfXValidationResult;
begin
Fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfXCompliance(Fs);
Result := Res.IsCompliant and (Res.Conformance <> pxcNone);
finally
Fs.Free;
end;
end;
Kompromissen är tydlig: den fristående vägen kör markörkontrollerna och alla åtta innehållskontrollerna, men inte PDFium-skiktet per teckensnitt, så dess teckensnittsdom faller tillbaka på den grova heuristiken. En förnuftig arkitektur använder ValidatePdfXCompliance som den billiga första grinden och reserverar hela TPdf.ValidatePdfX för filer som klarar den
Var denna validerare slutar och en programmatisk preflight börjar
Ärlighet är viktig i preflight-verktyg, så här går gränsen. ValidatePdfX verifierar identifieringsmarkörer, strukturella förbud, sidgeometrinyklar, Trapped-deklarationen och teckensnittsinbäddning ner till enskilda textobjekt. Den mäter inte total bläcktäckning, validerar inte att varje färgrymd är laglig för den påstådda varianten (t.ex. X-1a:s CMYK-only-regel), kontrollerar inte bildupplösning mot raster eller utvärderar övertryck (overprint) och transparensutplattningsbeteende — dessa kräver en färgstyrd preflight-motor, och enhetens egen dokumentation rekommenderar att den paras ihop med en sådan för slutlig certifiering. Vad tvåskiktskontrollen ger dig är de 80 % av avvisandena som är strukturella och upptäckbara tidigt, fångade på millisekunder inuti din egen Delphi-kod istället för i morgondagens e-postmeddelande från tryckeriet
Båda valideringsskikten, API:erna för PDF/X-markörinjektion för att producera dokument enligt standarden, samt PDF/A-, PDF/UA-, PDF/E- och PDF/VT-validerarna som delar samma arkitektur, levereras i PDFium Component för Delphi och C++Builder — en komponent, från rendering till prepress-grindbevakning