De PDFium Component voor Delphi valideert drukklare PDF/X-documenten via TPdf.ValidatePdfX, wat ISO 15930-controles implementeert in twee lagen: acht inhoudscontroles op byte-niveau (verboden LZW-compressie, JavaScript, formuliervelden, OPI-referenties, een ontbrekende TrimBox, een niet-ingestelde Trapped-sleutel en meer) plus een PDFium-objectmodelanalyse die FPDFFont_GetIsEmbedded gebruikt om lettertype-insluiting (font embedding) te verifiëren op elk tekstobject van elke pagina. Het resultaat is een record van het type TPdfXValidationResult dat het gedetecteerde conformiteitsniveau noemt en elke overtreding vermeldt als een getypeerde enum, zodat uw Delphi-applicatie een klant precies kan vertellen waarom een bestand bij de drukkerij zal worden geweigerd nog voordat er een drukplaat wordt gemaakt
Als u ooit een opdracht naar een commerciële drukkerij hebt gestuurd en deze terugkreeg met een afwijzing van één regel — "geen TrimBox", "lettertypen niet ingesloten", "Trapped niet ingesteld" — dan kent u de kosten van een late ontdekking. PDF/X is the tegenhanger voor pre-press van PDF/A: waar archief-PDF/A garandeert dat een document er over tientallen jaren identiek uitziet, PDF/X garandeert dat een document morgenochtend identiek scheidt, belicht en snijdt op de RIP van iemand anders. De twee standaarden delen mechanismen (XMP-identificatie, OutputIntents, ingesloten ICC-profielen) maar beantwoorden verschillende vragen. Daarom leest het component aparte validators voor elk — de PDF/A-kant wordt behandeld in PDF/A preflight-validatie met de PDFium Component
Wat vereist ISO 15930 eigenlijk van een drukklare PDF?
ISO 15930 bestaat om een blinde uitwisseling (blind exchange) mogelijk te maken: een ontwerper overhandigt een bestand aan een drukker die hij nog nooit heeft gesproken, en de drukker kan de juiste uitvoer produceren zonder telefoontje, zonder e-mail over een ontbrekend lettertype en zonder gekoppelde afbeelding die op de laptop van de ontwerper is achtergebleven. Elke regel in de standaard dient dat doel. Lettertypen moeten worden ingesloten omdat er niet van kan worden uitgegaan dat de ontvangende RIP deze bezit. Externe verwijzingen zijn verboden omdat het bestand in zichzelf compleet moet zijn. Interactieve functies zijn verboden omdat inkt geen onclick-handler heeft
De PDFium Component herkent drie conformiteitsfamilies en rapporteert deze via de enum TPdfXConformance in het validatieresultaat: pxc1a voor PDF/X-1a:2001 (ISO 15930-1, de strikte CMYK-plus-steunkleur baseline op PDF 1.3/1.4), pxc3 voor PDF/X-3:2002 (ISO 15930-3, die RGB, Lab en ICC-beheerde kleuren toestaat), en pxc4 voor PDF/X-4:2010 (ISO 15930-7, die ten slotte live transparantie en lagen toestaat op een PDF 1.6 basis). Een bestand dat helemaal geen PDF/X-identificatie bevat, komt terug als pxcNone, wat op zelfs een nuttig antwoord is: het document heeft nooit beweerd drukklaar te zijn, en al het andere dat de validator rapporteert legt uit wat er nodig is om dat wel te worden
De verboden zijn logisch als u denkt als een RIP-leverancier. /LZWDecode is verboden in elke PDF/X-variant, zodat een conformerende consument nooit afhankelijk is van een filter met een geschiedenis van compatibiliteit en licenties; Flate doet hetzelfde werk zonder die ballast. JavaScript, AcroForm-velden en /AA additional-action dictionaries zijn verboden omdat een drukbestand een vaste beschrijving moet zijn van markeringen op papier — alles wat het uiterlijk bij het openen kan veranderen, verbreekt de garantie dat wat is goedgekeurd ook is wat wordt gedrukt. OPI (Open Prepress Interface) placeholders zijn verboden omdat ze inherent verwijzingen zijn naar afbeeldingen met een hoge resolutie die ergens anders zijn opgeslagen, en "ergens anders" is precies wat blinde uitwisseling verbiedt
Waarom weigeren drukkerijen PDF's zonder TrimBox?
De TrimBox is de afgewerkte pagina — de rechthoek die overblijft nadat de papiersnijder snijdt. De MediaBox, die elke PDF-pagina heeft, is louter het vel papier: deze omvat afloop (bleed), snijtekens, paskruisen en kleurenbalken. Insluitsynchronisatiesoftware (imposition software) positioneert pagina's op een drukvel aan de hand van hun TrimBoxes. Zonder TrimBox moet de operator raden waar uw visitekaartje daadwerkelijk eindigt, en een verkeerde gok snijdt uw afloop weg of laat een witte rand achter aan één kant. Dat is de reden waarom ISO 15930 een TrimBox (of een ArtBox) op elke pagina vereist, en waarom ValidatePdfX de fout pvxiMissingTrimBox rapporteert wanneer er op geen enkele pagina van het document een /TrimBox-sleutel wordt gevonden
De sleutel /Trapped beantwoordt een andere productievraag. Trapping (overvloeien) is de pre-press techniek waarbij aangrenzende kleuren elkaar licht overlappen, zodat kleine registratie-afwijkingen op de pers geen witte kieren tussen de kleuren veroorzaken. De drukker moet weten of dat werk al is gedaan: het 'trappen' van een al getrapt bestand verdubbelt de overlappen, en het overslaan van trapping bij een niet-getrapt bestand riskeert zichtbare kieren. PDF/X vereist daarom dat de Info-dictionary expliciet /Trapped /True of /Trapped /False vermeldt — een ontbrekende sleutel of /Unknown dwingt een mens tot inspectie van het bestand, wat precies het soort overleg is dat blinde uitwisseling moest elimineren. Het component markeert dit als pvxiTrappedNotSet
De validatie in twee lagen uitvoeren met TPdf.ValidatePdfX
TPdf.ValidatePdfX neemt geen argumenten aan en retourneert een record van het type TPdfXValidationResult met drie leden: Conformance (the gedetecteerde PDF/X-variant), Issues (een Pascal-set van TPdfXValidationIssue-waarden) en een helper IsCompliant. Intern serialiseert het het geladen document naar een geheugenstream, voert de inspecteur op byte-niveau erop uit en doorloopt vervolgens het PDFium-objectmodel voor de lettertype-insluitingscontrole. Een minimale preflight-poort ziet er als volgt uit:
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;
Omdat Issues is een gewone Pascal-set is, kunt u deze indelen naar de behoeften van uw workflow — behandel structurele problemen als harde afwijzingen, behandel pvxiMissingTitle (een SHOULD in de standaard, geen MUST) als een waarschuwing en log de rest. Hetzelfde recordtype voedt ook de rapportgenerator van het component, dus als u liever een door mensen leesbaar document genereert in plaats van te splitsen op enums, is het patroon in het bouwen van een batch preflight-rapport CLI met de PDFium Component ongewijzigd van toepassing op PDF/X
Wat de laag op byte-niveau vangt — en wat hij mist
De laag op byte-niveau is een token-scan over de structurele bytes van het document waarbij de body van de streams is leeggemaakt, zodat een JPEG die toevallig het bytepatroon /JavaScript bevat, geen vals positief resultaat kan veroorzaken. Bovenop de marker-controles (XMP pdfxid:GTS_PDFXVersion, OutputIntent met een ingesloten ICC-profiel, trailer /ID, het versleutelingsverbod) voegt de inhoudscontrole acht controles toe, elk met een eigen enum-waarde:
pvxiLzwForbidden— er verschijnt ergens in het bestand een/LZWDecode-filter (verboden in alle PDF/X-varianten)pvxiJavaScriptForbidden— er is een/JavaScript-actie of -namenboom aanwezigpvxiFormFieldsForbidden— er bestaat een/AcroForm-dictionary of/XFA-invoerpvxiAdditionalActions— er is een/AA(additional-actions) dictionary aanwezigpvxiEmbeddedFilesForbidden— er is/EmbeddedFilesof een/FileAttachment-annotatie aanwezigpvxiOpiForbidden— een/OPI- of/Alternates-invoer verwijst naar vervangbare afbeeldingsinhoudpvxiMissingTrimBox— er is op geen enkele pagina een/TrimBoxgevondenpvxiTrappedNotSet—/Trappedis afwezig of ingesteld op/Unknown
Het scannen op byte-niveau is snel en vereist geen rendering-engine, maar het heeft een inherent blinde vlek bij lettertypen: op dat niveau kan de inspecteur alleen een grove heuristiek toepassen — hij vlagt een document wanneer hij helemaal geen ingesloten lettertypeprogramma vindt. Een bestand met negen ingesloten lettertypen en één stiekem tussengevoegd systeemlettertype ziet er prima uit voor een byte-scan. Dat enkele gat is de reden dat de tweede laag bestaat
Lettertype-insluiting per lettertype via het PDFium-objectmodel
De objectmodel-laag van de PDFium Component beantwoordt de lettertypevraag exact. Na de controle op byte-niveau doorloopt TPdf.ValidatePdfX elke pagina, vraagt FPDFPage_CountObjects om de objectenlijst, en lost voor elk tekstobject de lettertype-handle op via FPDFTextObj_GetFont en vraagt FPDFFont_GetIsEmbedded op. Eén niet-ingesloten lettertype waar dan ook in het document voegt pvxiPdfiumFontNotEmbedded toe aan de set met problemen. De doorloop breekt op twee niveaus vroegtijdig af — hij stopt met het scannen van objecten op een pagina en stopt met het laden van verdere pagina's op het moment dat het probleem is bevestigd — dus bij een afwijkende catalogus van 300 pagina's komt het oordeel vaak al na pagina één
Twee randvoorwaarden die het waard zijn om te weten. Ten eerste heeft deze laag de geladen PDFium-bibliotheek nodig en vereist builds die FPDFFont_GetIsEmbedded exporteren; wanneer de export afwezig is, wordt de controle overgeslagen in plaats van als gefaald gemarkeerd, zodat een oudere DLL nooit fantoomafwijzingen produceert. Ten tweede beantwoordt de controle alleen de vraag "ingesloten of niet" en niets meer — hij maakt geen onderscheid tussen volledige insluiting en subsetting, en controleert de dekking van de glyphs niet. Wanneer een bestand faalt en u moet weten welk lettertype op welke pagina het betreft, sluiten de opsommingstechnieken in het analyseren van PDF-lettertype-eigenschappen met PDFium in Delphi exact aan waar de boolean van de validator ophoudt
Streams valideren zonder een document — of the DLL — te laden
De inspecteur op byte-niveau is ook beschikbaar als een op zichzelf staande functie, ValidatePdfXCompliance(Source: TStream) in de unit FPdfPdfx, en is pure Object Pascal zonder afhankelijkheid van de PDFium DLL. Dat maakt het inzetbaar op plaatsen waar een rendering-engine ongewenst is: een lichtgewicht upload-poort op een webserver, een CI-taak die gegenereerd artwork controleert, of een Lazarus service op een platform waar u liever geen native binaries levert. Voed het met een willekeurige seekable stream:
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;
De afweging is expliciet: het stand-alone pad voert de marker-controles en alle acht inhoudscontroles uit, maar niet de PDFium-laag per lettertype, waardoor het oordeel over lettertypen terugvalt op de grove heuristiek. Een verstandige architectuur gebruikt ValidatePdfXCompliance als de goedkope eerste poort en reserveert de volledige TPdf.ValidatePdfX voor bestanden die daarvoor slagen
Waar deze validator eindigt en een volledige preflight begint
Eerlijkheid is belangrijk bij preflight-gereedschappen, dus hier ligt de grens. ValidatePdfX verifieert identificatie-markers, structurele verboden, pagina-geometrie-sleutels, de Trapped-declaratie en lettertype-insluiting tot aan individuele tekstobjecten. Het meet niet de totale inktdekking, valideert niet of elke kleurruimte legaal is voor de geclaimde variant (bijvoorbeeld de CMYK-only regel van X-1a), controleert de resolutie van afbeeldingen niet tegen het rasterscherm, en evalueert overdruk- en transparantie-afvlakkingsgedrag niet — die vereisen een preflight-engine met kleurbeheer, en de documentatie van de unit zelf raadt aan deze hiermee te combineren voor de definitieve certificering. Wat de validatie in twee lagen u biedt, is dat 80% van de afwijzingen structureel zijn en vroegtijdig kunnen worden gedetecteerd, binnen milliseconden opgevangen in uw eigen Delphi-code in plaats van in de e-mail van de drukker morgen
Beide validatielagen, de PDF/X-marker injectie API's voor het produceren van conforme uitvoer, en de PDF/A, PDF/UA, PDF/E en PDF/VT-validators die dezelfde architectuur delen, worden geleverd in de PDFium Component voor Delphi en C++Builder — één component, van rendering tot pre-press bewaking