PDFlibPas produceert PDF/X-drukbestanden vanuit Delphi via één aanroep, TPDFlib.SetPDFXMode, die PDF/X-1a:2003, PDF/X-3:2003 of PDF/X-4 kiest. De aanroep schrijft de XMP-pdfxid-identificatie, voegt een GTS_PDFX-output intent toe, declareert /Trapped /False, zet de PDF-versie vast en weigert vanaf dat moment tekenaanroepen die de gekozen part verbiedt. CheckFileCompliance met test 3 controleert het opgeslagen bestand
Dat is het korte antwoord. Het langere telt, want drukkerijen wijzen bestanden niet af omdat ze lelijk zijn, ze wijzen ze af in de preflight, meestal op een vrijdag, meestal om iets dat de genererende code had kunnen opvangen: een RGB-logo in een X-1a-opdracht, een font waarnaar verwezen is in plaats van ingebed, een pagina zonder snedemaat. PDF/X bestaat om die fouten structureel te maken in plaats van visueel, en de bibliotheekkant van het werk is om te voorkomen dat u ze in eerste instantie produceert
Welke PDF/X-part moet een Delphi-toepassing kiezen?
Kies PDF/X-4 tenzij het ontvangende workflow anders zegt, en kies PDF/X-1a als dat zo is. De drie parts verschillen langs precies drie assen: kleur, transparantie en de basis-PDF-versie, en elke as komt uit op een gate binnen PDFlibPas:
- PDF/X-1a:2003 (ISO 15930-4): PDF 1.4-syntaxis, uitsluitend CMYK, grijs en steunkleuren, geen ICC-kleur, geen transparantie. Het bestand is al gescheiden naar drukkleuren, dus de drukker doet helemaal geen kleurconversie
- PDF/X-3:2003 (ISO 15930-6): nog steeds PDF 1.4 en nog steeds geen transparantie, maar kleurbeheerde ruimtes zijn toegestaan, en device-RGB wordt geaccepteerd als de output intent zelf een RGB-conditie beschrijft
- PDF/X-4 (ISO 15930-7): PDF 1.6-syntaxis, met live transparantie en optional content (lagen). Dit is de part waar moderne RIP's voor gebouwd zijn, want het afvlakken van transparantie op de uitweg is waar veel van de oude X-1a-pijn vandaan kwam
X-1a is nog overal in advertentieaanlevering en in oudere drukworkflows die een bestand willen dat ze zonder nadenken kunnen belichten. X-4 is de betere technische keuze zodra de drukkerij hem accepteert: de transparantie blijft intact, en de kleurbeslissingen gebeuren in de RIP met het echte drukprofiel in plaats van in uw code. De modusnummers zijn respectievelijk 1, 2 en 3, en GetInformation(203) rapporteert de actieve modus terug. PDFlibPas definieert ook hogere modusnummers voor de PDF/X-6-familie op PDF 2.0, die andere versie- en output-intent-regels volgen en hier buiten beschouwing blijven
Wat SetPDFXMode in het bestand schrijft
TPDFlib.SetPDFXMode regelt de identificatie en de standaardtekst die een PDF/X-lezer eerst controleert, zodat toepassingscode alleen het echte drukprofiel en de inhoud hoeft aan te leveren. Concreet doet een geslaagde aanroep vier dingen:
- Schrijft de editiestring in XMP als
pdfxid:GTS_PDFXVersion(PDF/X-1a:2003,PDF/X-3:2003ofPDF/X-4). De 2003-edities identificeren de part volledig via die string, dus er wordt geen aparte conformantie-eigenschap geschreven - Voegt een output intent toe als het document er geen heeft en zet het subtype op
/S /GTS_PDFX, het subtype dat PDF/X-lezers zoeken (ISO 32000-1 §14.11.5 definieert het output-intent-woordenboek) - Zet
/Trapped /Falsein het documentinformatiewoordenboek, want de schrijver trapt nooit en PDF/X eist dat de trapping-staat gedeclareerd wordt in plaats van onbekend te blijven - Zet de versiebasis vast: 1.4 voor X-1a en X-3, 1.6 voor X-4
Bij het opslaan gebeuren nog twee reparaties. Elke pagina zonder TrimBox krijgt er één gelijk aan zijn MediaBox, want PDF/X eist een gedeclareerd eindformaat op elke pagina (ISO 32000-1 §14.11.2 behandelt de paginagrenzen), en annotaties krijgen de printvlag die de standaard verwacht. De TrimBox-fallback is een vangnet, geen opmaakbeslissing. Een full-bleed-opdracht heeft een echte trimbox nodig binnen een grotere mediabox, en de gids over TrimBox-, BleedBox- en CropBox-defaults in PDFlibPas legt uit hoe u die boxen instelt en hoe overerving u kan verrassen
uses
PDFlibrary;
procedure BuildX1aAd(const OutFile, PressProfile: string);
var
Pdf: TPDFlib;
begin
Pdf := TPDFlib.Create;
try
if Pdf.SetPDFXMode(1) <> 1 then // 1 = PDF/X-1a:2003
raise Exception.CreateFmt('PDF/X mode refused (error %d)',
[Pdf.LastErrorCode]);
// Vervang het standaardprofiel door de echte drukconditie
if Pdf.LoadOutputIntentProfile(PressProfile, 'DeviceCMYK') <> 1 then
raise Exception.Create('Could not load the CMYK output profile');
// Embed = 1 bedt het volledige fontprogramma in; PDF/X accepteert 0 niet
if Pdf.AddTrueTypeFont('Arial {1252}', 1) = 0 then
raise Exception.Create('Font could not be loaded for embedding');
Pdf.SetTextSize(24);
Pdf.SetFillColorCMYK(0, 1, 1, 0); // procesrood, geen RGB
Pdf.DrawText(72, 720, 'Spring catalog, page 1');
Pdf.SaveToFile(OutFile);
finally
Pdf.Free;
end;
end;
De volgorde in die schets is bewust. LoadOutputIntentProfile vervangt het profiel van een output intent die al bestaat, dus hij moet draaien nadat SetPDFXMode er een heeft aangemaakt. De aanroep kan ook geen intent uit het niets toveren: op een document zonder output intent geeft hij simpelweg 0 terug
Waarom moet de standaard-output intent worden vervangen?
De output intent die SetPDFXMode voor modus 1 tot 3 toevoegt, declareert DeviceCMYK, maar de ICC-bytes erachter zijn het meegeleverde sRGB-profiel van de bibliotheek met het aantal componenten herschreven naar 4. Die default bestaat voor achterwaartse compatibiliteit en is genoeg om het bestand structureel PDF/X te maken, maar het ingebedde profiel beschrijft geen enkele pers. Een preflight-tool die de profielheader inspecteert, ziet een RGB-profiel met een CMYK-label, en een drukker die op de intent vertrouwt voor proofing krijgt onzin
Behandel LoadOutputIntentProfile(FileName, 'DeviceCMYK') dus als verplicht voor echt drukwerk en geef het ICC-profiel door dat uw drukpartner voor het papier en de pers noemt. TPDFlib.LoadOutputIntentProfile verwisselt de DestOutputProfile-stream en werkt /N bij, en laat de rest van het intent-woordenboek onaangetast. Met name de output condition identifier en de beschrijvende strings van de standaardintent voeren nog sRGB-achtige waarden, dus als uw drukkerij op de identifier matcht in plaats van op het ingebedde profiel, stem dan vooraf af wat zij controleren voordat u verzendt. Dat is een echte leemte in de defaults uit het 2003-tijdperk, niet iets dat uw code verkeerd deed
Valkuil één: de versie die u niet koos
Een nieuw PDFlibPas-document begint op de schrijfdefault van PDF 1.5, wat boven de 1.4-basis ligt die PDF/X-1a en PDF/X-3 vereisen. TPDFlib.SetPDFXMode lost dat in het gewone geval geruisloos op: als de opslagversie niet is vastgezet, verlaagt hij de documentversie naar de part-basis en gaat door. De eerste implementatie weigerde in plaats daarvan, en elke SetPDFXMode(1) op een vers document gaf 0 terug — een goed voorbeeld van een regel die op papier klopt en in de praktijk onbruikbaar is
De weigering bestaat nog steeds voor het ene geval waarin hij terecht is. Als er eerder iets LockSaveVersion heeft aangeroepen met een versie boven de basis, geeft SetPDFXMode 0 terug met LastErrorCode 601, want de aanroeper heeft de versie met opzet vastgezet en de bibliotheek overrulet dat niet. In gedeelde document-setup-code, waar een helper de versie om ongerelateerde redenen vastzet, gaat een X-1a-opdracht hier precies dood:
Pdf := TPDFlib.Create;
try
Pdf.LockSaveVersion('1.7'); // gezet door een generieke "huisdefaults"-helper
if Pdf.SetPDFXMode(1) = 0 then
// LastErrorCode = 601: 1.7 is vastgezet, PDF/X-1a heeft 1.4 nodig.
// Sla de lock over voor drukwerk. PDF/X-4 is hier geen uitweg:
// zijn 1.6-basis ligt ook onder de 1.7-lock en faalt op dezelfde manier.
LogError('PDF/X refused, error %d', [Pdf.LastErrorCode]);
finally
Pdf.Free;
end;
Dezelfde gate verklaart een verwante beperking. PDF/X-modus is een schakelaar bij documentcreatie: SetPDFXMode werkt op een nieuw document en geeft 0 terug op een document dat uit een bestand is geladen, want de bibliotheek kan niet instaan voor inhoud die zij niet geschreven heeft. Een bestaande PDF naar PDF/X converteren is een ander klusje dat inspectie en reparatie vraagt, geen vlag
Valkuil twee: gates die geruisloos weigeren
Zodra een PDF/X-modus actief is, weigert PDFlibPas elke inhoudsaanroep die de gekozen part verbiedt, op het moment dat u hem doet, in plaats van het bestand later te laten struikelen in de preflight. De weigeringen betreffen device-RGB-vullingen en lijnen (heel X-1a; X-3 en X-4 tenzij de output intent RGB is), ICC-kleuren in X-1a, transparantie en blend modes in X-1a en X-3, optional content in X-1a en X-3, JavaScript-acties, ingebedde bestandsbijlagen, het LZW-beeldfilter, Standard 14-fonts die ongeëmbed zouden blijven en public-key-versleuteling. Wachtwoordversleuteling via Encrypt wordt niet afgevangen bij creatie, maar de validator vlagt elk versleuteld bestand, dus houd drukwerk onversleuteld
Wat de weigeringen niet delen, is een foutcode, en dat is de valkuil. De kleurruimte-gates in SetFillColor, SetLineColor, de ICC-kleuraanroepen en EncryptPublicKey zetten LastErrorCode op 601, de bibliotheekconformantiecode die ook de PDF/A-gates gebruiken. De transparantie-, JavaScript-, bijlage-, LZW- en AddStandardFont-gates geven simpelweg 0 terug en laten LastErrorCode onaangetast, wat betekent dat hij nog een waarde van een eerdere aanroep kan bevatten. Code die na een reeks tekenaanroepen alleen LastErrorCode controleert, mist de helft van de weigeringen, dus test elke returnwaarde:
procedure Require(Ok: Integer; const What: string);
begin
if Ok = 0 then
raise EPrintConformance.CreateFmt('%s refused under PDF/X', [What]);
end;
Require(Pdf.SetFillColorCMYK(0, 0, 0, 1), 'CMYK fill');
Require(Pdf.SetTransparency(40), 'transparency'); // 0 in X-1a / X-3
Require(Pdf.AddLinkToJavaScript(72, 72, 120, 20,
'app.alert(1)', 0), 'JavaScript link'); // 0 in elke part
Fonts verdienen een eigen waarschuwing. AddStandardFont geeft 0 terug onder PDF/X, want de bibliotheek levert de Standard 14-outlines niet mee en kan ze dus niet inbedden. AddTrueTypeFont is anders: in PDF/A-modus promoveert hij Embed = 0 voor u naar een volledige embed, maar in PDF/X-modus doet hij dat niet, dus een systeemfont waarnaar slechts verwezen wordt gaat het bestand in en alleen de validator vangt het. Geef zelf 1 (volledig) of 2 (subset) door, of roep één keer SetEmbedAllFonts(1) aan bij de setup zodat een verdwaalde 0 er niet doorheen glipt
Hoe controleert u een PDF/X-bestand voordat het naar de drukker gaat?
Draai CheckFileCompliance met ComplianceTest = 3 op het opgeslagen bestand. TPDFlib.CheckFileCompliance geeft 0 terug als hij geen bevindingen heeft genoteerd, en anders een string-list-handle waarvan de items regels zijn met het voorvoegsel PDFX-. De PDF/X-audit leest het bestand via dezelfde streaminglezer als de PDF/A- en PDF/UA-preflight in PDFlibPas, en controleert de regels die een druk-preflight eerst controleert:
- Het bestand is niet versleuteld, de XMP voert een bekende
GTS_PDFXVersion, en de PDF-versie overschrijdt de part-basis niet - Er bestaat precies één output intent, het subtype is
GTS_PDFX, en hij voert een bestemmingsprofiel en een output condition identifier - Het informatiewoordenboek declareert
/Trapped - Elke pagina heeft een TrimBox die binnen de MediaBox ligt, en een BleedBox omsluit, wanneer aanwezig, de TrimBox
- Elk op een pagina gebruikt font heeft een ingebed programma, waarbij Type0-fonts via hun descendant font worden gecontroleerd
- Geen verboden annotatietypes (RichMedia, Screen, 3D, Movie, Sound, FileAttachment), geen JavaScript-openactie of document-level JavaScript, geen ingebedde bestanden en nergens in de objectgrafiek een LZWDecode-filter
function PreflightPDFX(Pdf: TPDFlib; const FileName: string;
Report: TStrings): Boolean;
var
ListId, I: Integer;
begin
ListId := Pdf.CheckFileCompliance(FileName, '', 3, 0); // 3 = PDF/X
Result := ListId = 0;
if Result then
Exit;
try
for I := 1 to Pdf.GetStringListCount(ListId) do // items zijn 1-based
Report.Add(Pdf.GetStringListItem(ListId, I));
finally
Pdf.ReleaseStringList(ListId);
end;
end;
Wees duidelijk over wat die slaging betekent. De PDFlibPas-validator controleert de structurele regels hierboven, en dat zijn de regels die fouten van de generator vangen. Het is geen kleurechte preflight: hij controleert geen inktdekking, geen beeldresolutie en niet of het ingebedde profiel matcht met de conditie waarop uw drukker draait. Gebruik hem als gate in uw build- of exportpijplijn en laat de persspecifieke controles over aan het preflight-profiel van de drukkerij — dat draaien zij sowieso
FAQ
Ondersteunt PDFlibPas PDF/X-4-transparantie?
Ja. In SetPDFXMode(3) staat PDFlibPas transparantie, blend modes en optional content groups toe en schrijft een PDF 1.6-bestand. Diezelfde aanroepen geven 0 terug onder PDF/X-1a en PDF/X-3
Kan PDFlibPas een bestaande PDF naar PDF/X converteren?
Nee. SetPDFXMode geldt alleen voor documenten die in de huidige TPDFlib-sessie zijn aangemaakt en geeft 0 terug voor een geladen bestand. U kunt elke bestaande PDF alsnog auditen met CheckFileCompliance en test 3
Welke foutcode geeft een geweigerde PDF/X-aanroep terug?
Kleurruimte- en public-key-versleutelingsweigeringen zetten LastErrorCode op 601. Andere gates, zoals transparantie, JavaScript en Standard 14-fonts, geven alleen 0 terug, dus test altijd het functieresultaat
PDF/X-uitvoer, de PDF/X-validator en de rest van de druk- en archiveringstoolset horen bij PDFlibPas, de native Object Pascal-PDF-bibliotheek van losLab voor Delphi. Zie de productpagina van de PDFlibPas Delphi PDF Library voor edities, platforms en de volledige API-referentie