PDFium Component for Delphi validerer trykklare PDF/X-dokumenter gjennom TPdf.ValidatePdfX, som implementerer ISO 15930-kontroll i to lag: åtte innholdskontroller på byte-nivå (forbudt LZW-komprimering, JavaScript, skjema-felt, OPI-referanser, en manglende TrimBox, en udefinert Trapped-nøkkel, med mer) pluss en PDFium objektmodell-gjennomgang som bruker FPDFFont_GetIsEmbedded for å verifisere skrifttypeinnbygging på hvert tekstobjekt på hver side. Resultatet er en TPdfXValidationResult-post (record) som navngir det oppdagede samsvarsnivået og lister opp hvert brudd som en type-definert enum, slik at Delphi-applikasjonen din kan fortelle en kunde nøyaktig hvorfor en fil verdt å bli avvist i trykkeriet før noen bruker tid og ressurser på å lage en trykkplate
Hvis du noen gang har sendt en jobb to et kommersielt trykkeri og fått den i retur med en avvisning på én linje — "ingen TrimBox", "skrifttyper ikke innebygd", "Trapped ikke angitt" — kjenner du kostnaden ved å finne det ut for sen. PDF/X er pre-press-motstykket til PDF/A: der arkiverings-PDF/A garanterer at et dokument rendres identisk tiår fra nå, PDF/X garanterer at et dokument separeres, avbildes og beskjæres identisk på andres RIP i morgen tidlig. De to standardene deler mekanismer (XMP-identifikasjon, OutputIntents, innebygde ICC-profiler), men besvarer ulike spørsmål, og det er grunnen til at komponenten leveres med separate validatorer for hver — PDF/A-siden dekkes i PDF/A-preflightvalidering med PDFium Component
Hva krever ISO 15930 egentlig av en trykklar PDF?
ISO 15930 eksisterer for å gjøre blind utveksling (blind exchange) mulig: en designer overleverer en fil til et trykkeri de aldri har snakket med, og trykkeriet kan produsere riktige utskrifter uten telefonsamtaler, e-poster om manglende skrifttyper eller koblede bilder som ble liggende igjen på designerens bærbare datamaskin. Enhver regel i standarden tjener dette målet. Skrifttyper må bygges inn fordi det mottakende RIP-en ikke kan antas å eie dem. Eksterne referanser er forbudt fordi filen må være komplett i seg selv. Interaktive funksjoner er forbudt fordi blekk ikke har noen onclick-behandler
PDFium Component gjenkjenner tre samsvarsfamilier og rapporterer dem gjennom TPdfXConformance-enum i valideringsresultatet: pxc1a for PDF/X-1a:2001 (ISO 15930-1, den strenge CMYK-pluss-spot-grunnlinjen på PDF 1.3/1.4), pxc3 for PDF/X-3:2002 (ISO 15930-3, som tillater RGB, Lab og ICC-styrt farge), og pxc4 for PDF/X-4:2010 (ISO 15930-7, som endelig tillater live transparens og lag på en PDF 1.6-base). En fil som ikke bærer noen PDF/X-identifikasjon i det hele tatt kommer tilbake som pxcNone, noe som i seg selv er et nyttig svar: dokumentet hevdet aldri å være trykklart, og alt annet validatoren rapporterer forklarer hva som skal til for å komme dit
De forbudt-reglene gir mening når du tenker som en RIP-leverandør. /LZWDecode er forbudt i enhver PDF/X-variant, slik at en samsvarende konsument aldri avhenger av et filter med en kompatibilitets- og lisenshistorie; Flate gjør samme jobb uten denne bagasjen. JavaScript, AcroForm-felt og /AA-ordbøker for tilleggshandlinger er forbudt fordi en utskriftsfil må være en fast beskrivelse av merker på papir — alt som kan endre utseende ved åpningstidspunktet bryter garantien om at det som ble godkjent er det som trykkes. OPI-plassholdere (Open Prepress Interface) er forbudt fordi de etter design er referanser til høyoppløselige bilder lagret et annet sted, og "et annet sted" er nøyaktig hva blind utveksling forbyr
Hvorfor avviser trykkerier PDF-er uten TrimBox?
TrimBox er den ferdige siden — rektangelet som gjenstår etter at giljotinen har kuttet. MediaBox, som hver PDF-side har, er bare selve arket: det inkluderer utfall (bleed), skjæremerker, registreringsmerker og fargestriper. Utskytingsprogramvare (imposition software) plasserer sider på et trykkark etter deres TrimBoxer; uten en må operatøren gjette hvor visittkortet ditt faktisk slutter, og en feil gjetting kutter av utfallet ditt eller etterlater en hvit stripe på en kant. Det er grunnen til at ISO 15930 krever en TrimBox (eller en ArtBox) på hver side, og hvorfor ValidatePdfX utløser pvxiMissingTrimBox når ingen /TrimBox-nøkkel finnes på noen side i dokumentet
Nøkkelen /Trapped besvarer et annet produksjonsspørsmål. Trapping er en førtrykksteknikk (prepress) der man overlapper tilstøtende farger litt, slik at små feiljusteringer i pressen ikke åpner hvite mellomrom mellom dem. Trykkeriet må vite om det arbeidet allerede er gjort: trapping av en allerede trappet fil dobler overlappene, og å hoppe over trapping på en utrappet fil risikerer synlige mellomrom. PDF/X krever derfor at Info-ordboken oppgør /Trapped /True eller /Trapped /False eksplisitt — en manglende nøkkel eller /Unknown tvinger et menneske til å inspisere filen, noe som er nøyaktig den samtalen blind utveksling var ment å eliminere. Komponenten flagger dette som pvxiTrappedNotSet
Kjøre tolagsvalidering med TPdf.ValidatePdfX
TPdf.ValidatePdfX tar ingen argumenter og returnerer en TPdfXValidationResult-post (record) med tre medlemmer: Conformance (den oppdagede PDF/X-varianten), Issues (et Pascal-sett med TPdfXValidationIssue-verdier) og en IsCompliant-hjelper. Internt serialiserer den det lastede dokumentet til en minnestrøm, kjører inspektøren på bytenivå over det, og går deretter gjennom PDFiums objektmodell for innbyggingssjekk per skrifttype. En minimal preflight-port ser slik ut:
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 checks passed')
else
begin
if pvxiMissingTrimBox in Res.Issues then
Writeln('REJECT: no /TrimBox on the pages');
if pvxiTrappedNotSet in Res.Issues then
Writeln('REJECT: /Trapped missing or /Unknown');
if pvxiPdfiumFontNotEmbedded in Res.Issues then
Writeln('REJECT: a page uses a non-embedded font');
if pvxiLzwForbidden in Res.Issues then
Writeln('REJECT: LZWDecode filter present');
end;
finally
Pdf.Free;
end;
end;
Fordi Issues er et vanlig Pascal-sett, kan du dele det opp slik arbeidsflyten din krever — behandle strukturelle problemer som harde avvisninger, behandle pvxiMissingTitle (en bør-regel i standarden, ikke en må-regel) som en advarsel, og logg resten. Den samme posttypen mater også komponentens rapportgenerator, så hvis du heller vil generere et menneskelig lesbart dokument enn å forgrene deg på enum-verdier, gjelder mønsteret i oppbygging av en batch-preflight-rapport-CLI med PDFium Component uendret for PDF/X
Hva laget på bytenivå fanger opp — og hva det går glipp av
Laget på bytenivå er en skanning av dokumentets strukturelle byte med strøm-kropper fjernet (blanket out), slik at en JPEG som tilfeldigvis inneholder byte-mønsteret /JavaScript ikke kan utløse et falskt positivt resultat. På toppen av markør-kontrollene (XMP pdfxid:GTS_PDFXVersion, OutputIntent med en innebygd ICC-profil, trailer /ID, forbudet mot kryptering), legger innholdsgjennomgangen til åtte kontroller, hver med sin egen enum-verdi:
pvxiLzwForbidden— et/LZWDecode-filter vises hvor som helst i filen (forbudt i alle PDF/X-varianter)pvxiJavaScriptForbidden— en/JavaScript-handling eller et navnetre er til stedepvxiFormFieldsForbidden— en/AcroForm-ordbok eller/XFA-oppføring eksistererpvxiAdditionalActions— en/AA-ordbok for tilleggshandlinger er til stedepvxiEmbeddedFilesForbidden—/EmbeddedFileseller en/FileAttachment-annotasjon er til stedepvxiOpiForbidden— en/OPI- eller/Alternates-oppføring refererer til utskiftbart bildeinnholdpvxiMissingTrimBox— ingen/TrimBoxfunnet på noen sidepvxiTrappedNotSet—/Trappedmangler eller er satt til/Unknown
Byteskanning er raskt og trenger ingen renderingsmotor, men det har en iboende blindsone med skrifttyper: på det nivået kan inspektøren bare bruke en grov heuristikk — den flagger et dokument når den ikke finner noe innebygd skrifttypeprogram i det hele tatt. En fil med ni innebygde skrifttyper og én systemskrifttype sneket inn ser fin ut for en byteskanning. Det ene gapet er grunnen til at det andre laget eksisterer
Innbygging per skrifttype gjennom PDFium-objektmodellen
PDFium Components objektmodell-lag besvarer skrifttyspørsmålet presist. Etter gjennomgangen på bytenivå, itererer TPdf.ValidatePdfX gjennom hver side, ber om objektlisten via FPDFPage_CountObjects, og for hvert tekstobjekt løser den opp skrifttypehåndtaket via FPDFTextObj_GetFont og spør FPDFFont_GetIsEmbedded. Én ikke-innebygd skrifttype hvor som helst i dokumentet legger til pvxiPdfiumFontNotEmbedded i problemsettet. Traverset avbrytes tidlig (short-circuits) på to nivåer — det slutter å skanne objekter på en side, og slutter å laste flere sider i det øyeblikket problemet er bekreftet — så på en katalog med brudd på 300 sider, ankommer dommen ofte etter side én
To grensemerknader verdt å vite. For det første trenger dette laget at PDFium-biblioteket er lastet og krever bygg som eksporterer FPDFFont_GetIsEmbedded; når eksporten mangler hoppes sjekken over i stedet for å feile, slik at en eldre DLL aldri produserer falske avvisninger. For det andre besvarer sjekken "innebygd eller ikke" og ingenting mer — den skiller ikke fullstendig innbygging fra subsetting, og den sjekker heller ikke glyph-dekning. Når en fil feiler og du trenger å vite hvilken skrifttype på hvilken side, fortsetter tellingsteknikkene i analyse av PDF-skrifttypeegenskaper med PDFium i Delphi akkurat der validererens boolske verdi slipper taket
Validere strømmer uten å laste inn et dokument — eller DLL-en
Inspektøren på bytenivå er også eksponert som en frittstående funksjon, ValidatePdfXCompliance(Source: TStream) i FPdfPdfx-enheten, og er ren Object Pascal uten avhengighet av PDFium DLL-en. Det gjør den distribuerbar på steder der en renderingsmotor er uønsket: en lett opplastingsport på en webserver, en CI-jobb som sjekker generert grafikk, eller en Lazarus-tjeneste på en plattform der du helst ikke vil sende med native binærfiler. Mat den med en hvilken som helst 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;
Avveiningen er eksplisitt: den frittstående banen kjører markørkontrollene og alle de åtte innholdskontrollene, men ikke PDFium-laget per skrifttype, så dens skrifttypedom faller tilbake på den grove heuristikken. En fornuftig arkitektur bruker ValidatePdfXCompliance som den rimelige første porten, og reserverer den fullstendige TPdf.ValidatePdfX for filer som passerer den
Hvor denne validatoren slutter og en fullstendig preflight begynner
Ærlighet er viktig i preflight-verktøy, så her er grensen. ValidatePdfX verifiserer identifikasjonsmarkører, strukturelle forbud, sideoppsett-nøkler, Trapped-deklarasjonen og skrifttypeinnbygging ned til individuelle tekstobjekter. Den måler ikke total blekkdekning (TOC), validerer ikke at alle fargerom er lovlige for den påståtte varianten (for eksempel X-1as CMYK-bare-regel), sjekker ikke bildens oppløsning mot linjeskjermen, og evaluerer heller ikke overtrykk (overprint) og transparens-flating — disse trenger en fargestyrt preflight-motor, og enhetens egen dokumentasjon sier at den bør parres med en slik for endelig sertifisering. Det to-lags sjekken gir deg er de 80% av avvisningene som er strukturelle og kan oppdages tidlig, fanget på millisekunder i din egen Delphi-kode i stedet for i morgendagens e-post fra trykkeriet
Begge valideringslagene, PDF/X-markør-injeksjons-API-ene for å produsere samsvarende utskrifter, og PDF/A-, PDF/UA-, PDF/E- og PDF/VT-validatorene som deler samme arkitektur, leveres i PDFium Component for Delphi og C++Builder — én komponent, fra rendering til førtrykks-kontroll