Wenn PDFXCompliance auf 'X-1a' steht, prüft HotPDF die Inhaltsfarben ganz am Ende des Jobs: EndDoc ruft THotPDF.EnsurePDFX1aContentColorSpaces auf, das DeviceRGB-, CalRGB- oder ICCBased-RGB-Inhalte an jeder Stelle auf jeder Seite abweist und eine Exception wirft, welche die betroffene Ressource benennt. Die Datei wird nie als PDF/X-1a-Dokument geschrieben, das die Druckerei zurückschickt
Dieser letzte Teil ist der Punkt. Eine PDF/X-1a-Datei mit einem einzelnen herumstreunenden RGB-Logo sieht auf dem Bildschirm tadellos aus, besteht eine beiläufige Sichtprüfung und fällt dann im Preflight der Druckerei zwei Tage vor dem Maschinenslot durch. Das im eigenen Delphi-Build zu erwischen, mit einer Meldung, die dir sagt, welche Seite und welches Bild, ist deutlich billiger, als es von einem genervten Druckvorstufen-Operator zu erfahren
Warum weist PDF/X-1a RGB-Inhalte ab?
PDF/X-1a weist RGB ab, weil das Format verspricht, dass jede Farbe bereits final für eine bestimmte CMYK-Druckbedingung ist. ISO 15930-1:2001 §6.2.3 begrenzt die Inhaltsfarben auf DeviceCMYK, DeviceGray und Spot-Farben, gemeint sind Separation- und DeviceN-Räume, deren Alternates CMYK oder Gray sind. Der in der Datei eingebettete GTS_PDFX-OutputIntent nennt jene Druckbedingung, etwa FOGRA39 coated offset, und der empfangende Workflow darf die Zahlen ohne jede Farbkonvertierung direkt an die Platten schicken
RGB bricht diesen Vertrag. Ein RGB-Wert beschreibt eine Farbe relativ zu einer Anzeige oder einem Arbeitsfarbraum, kein Tintenrezept, also müsste irgendwer Downstream entscheiden, wie er zu separieren ist, und X-1a existiert gerade, um dem Empfänger diese Entscheidung abzunehmen. ISO 32000-1 §8.6 gruppiert PDF-Farbräume in Geräte-, CIE-basierte und besondere Familien, und die RGB-Mitglieder tauchen in mehr als einer Familie auf: DeviceRGB ist ein Geräterraum, CalRGB und ICCBased mit drei Komponenten sind CIE-basiert, und ein Indexed- oder Separation-Raum kann eine RGB-Basis oder -Alternative darunter verstecken. Ein Prüfer, der nur nach dem rg-Operator sucht, verpasst die meisten davon. Die spätere Ausgabe PDF/X-1a:2003 (ISO 15930-4) behält dieselbe Farbregel; beachte, dass HotPDFs 'X-1a'-Wert die PDF/X-1a:2001-Identifikation ins XMP-Paket schreibt
Wenn deine Inhalte wirklich RGB sind und so bleiben sollen, ist X-1a das falsche Ziel. HotPDF begrenzt diese Prüfung auf 'X-1a', also bleiben 'X-3' und 'X-4', die ICC-basierte und kalibrierte Farbe erlauben, unberührt
Was EnsurePDFX1aContentColorSpaces tatsächlich prüft
EnsurePDFX1aContentColorSpaces kombiniert ein Draw-Zeitpunkt-Flag mit einem rekursiven Gang durch die Ressourcen jeder Seite und läuft zuletzt im PDF/X-Tor. EndDoc setzt zuerst die allgemeinen PDF/X-Anforderungen durch: Title muss gesetzt sein, Trapped muss 'True', 'False' oder 'Unknown' sein, ein GTS_PDFX-OutputIntent muss existieren (EnsurePDFXOutputIntent), und jede Seite braucht eine TrimBox oder ArtBox (EnsurePDFXPageBoxes). Erst nach deren Bestehen läuft die Farbprüfung
Der erste Pfad ist ein dokumentweites Flag. HotPDFs RGB-Farbsetter, das Einbetten von Bitmap-Bildern und die Anmerkungs-Farbeinträge notieren die DeviceRGB-Verwendung während des Zeichnens, was Inline-rg- und RG-Operatoren abdeckt, die nie in einem Resource-Dictionary auftauchen. Der zweite Pfad geht jedes /Resources einer Seite durch und inspiziert:
- Benannte Farbräume in
/ColorSpace, inklusive der Inline-Image-AbkürzungRGBals Synonym für DeviceRGB - Das
/ColorSpacejedes Image-XObjects - Form-XObjects und tiling-Patterns, durch Rekursion in ihre eigenen verschachtelten
/Resources - Shading-Patterns und Einträge im
/Shading-Dictionary der Seite, über das/ColorSpacedes Shading - Indexed-Basisräume, Separation- und DeviceN-Alternates sowie Pattern-Basisräume, verfolgt bis zu einer Verschachtelungstiefe von 8
Drei Dinge werden abgewiesen: DeviceRGB, CalRGB und ICCBased-Räume, deren Profil-Stream N = 3 deklariert. Zwischen Form-XObjects und Patterns geteilte Resource-Dictionarys werden einmal besucht, sodass ein sich gegenseitig referenzierender Form-Satz den Gang nicht in eine Schleife schickt. Die Methode ist öffentlich auf THotPDF, im Normalgebrauch rufst du sie aber nie selbst auf, denn EndDoc macht das für dich
Eine X-1a-Seite in Delphi zeichnen, die die Prüfung besteht
Ein konformes HotPDF-X-1a-Dokument braucht einen CMYK-OutputIntent, eine TrimBox auf jeder Seite und Farbe, gesetzt nur über die CMYK-, Gray- und Spot-APIs. Das Skelett unten nutzt das FOGRA39-Profil; AddPDFXOutputIntent nimmt die Output-Condition-Kennung, einen Info-String, den ICC-Profil-Stream, seine Komponentenzahl und den alternativen Farbraum
var
Pdf: THotPDF;
Profile: TFileStream;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'brochure-x1a.pdf';
Pdf.Title := 'Spring brochure, press edition';
Pdf.Trapped := 'False';
Pdf.PDFXCompliance := 'X-1a';
Pdf.BeginDoc;
Profile := TFileStream.Create('CoatedFOGRA39.icc', fmOpenRead or fmShareDenyWrite);
try
Pdf.AddPDFXOutputIntent('FOGRA39 (ISO 12647-2:2004)',
'Coated FOGRA39 offset', Profile, 4, 'DeviceCMYK');
finally
Profile.Free;
end;
Pdf.CurrentPage.SetTrimBox(0, 0, 612, 792); // nötig auf jeder Seite
Pdf.CurrentPage.SetCMYKFillColor(0, 0.5, 0.8, 0.1);
Pdf.CurrentPage.Rectangle(72, 600, 468, 120);
Pdf.CurrentPage.Fill;
Pdf.CurrentPage.SetGrayFillColor(0.2); // DeviceGray-Text
Pdf.CurrentPage.SetFont('Arial', [], 14);
Pdf.CurrentPage.TextOut(72, 560, 0, 'Spring catalog, press edition');
Pdf.EndDoc; // Farbprüfung läuft hier
finally
Pdf.Free;
end;
end;
Jeder TColor-basierte Aufruf ist in diesem Kontext eine Falle. SetRGBFillColor, SetRGBStrokeColor und SetRGBColor nehmen alle eine GDI-Farbe entgegen und geben DeviceRGB aus, also verunreinigt eine vor Jahren für bildschirmorientierte Reports geschriebene Helferroutine einen Druckjob, sobald man sie wiederverwendet. Nimm SetCMYKFillColor, SetCMYKStrokeColor oder SetCMYKColor mit Komponenten im Bereich 0 bis 1, oder die Gray-Entsprechungen
Spot-Farben und CMYK-Verläufe
Spot-Farben sind in X-1a erlaubt, solange ihr Alternate CMYK oder Gray ist. RegisterSeparation baut den Separation-Raum und liefert seinen Ressourcennamen, und RegisterAxialGradient wählt den Shading-Farbraum nach der Komponentenzahl, die du übergibst, wobei vier Komponenten DeviceCMYK bedeuten
var
SpotCS, Ramp: AnsiString;
begin
// Spot-Tinte mit einer angenäherten CMYK-Mischung als Alternate
SpotCS := Pdf.RegisterSeparation('Corporate Red', 'DeviceCMYK',
[0, 1, 0.8, 0.05]);
Pdf.CurrentPage.SetFillColorSpace(SpotCS);
Pdf.CurrentPage.SetFillColor([1.0]); // 100% Anteil
Pdf.CurrentPage.Rectangle(72, 420, 200, 80);
Pdf.CurrentPage.Fill;
// 4 Komponenten pro Stopp: das Shading ist DeviceCMYK, nicht DeviceRGB
Ramp := Pdf.RegisterAxialGradient(72, 300, 540, 300,
[0, 0, 0, 0], [1, 0.6, 0, 0.2]);
Pdf.CurrentPage.SetFillPattern(Ramp);
Pdf.CurrentPage.Rectangle(72, 260, 468, 80);
Pdf.CurrentPage.Fill;
end;
Übergib denselben Gradient-Aufruf drei Komponenten, und du bekommst ein DeviceRGB-Shading, das der Ressourcengang unter dem Namen des Shading-Patterns ablehnt. Dasselbe gilt für eine Separation, registriert mit 'DeviceRGB' als Alternate: Der Spot-Name sieht harmlos aus, aber der Gang folgt dem Alternate und findet darunter RGB. Wie solche Spot-Tinten komponiert werden, wenn ein Viewer oder RIP auf den Alternate zurückfällt, behandelt der Artikel zu Separation- und DeviceN-Spot-Farben in Delphi rendern
Rasterbilder brauchen dieselbe Disziplin. HotPDF pinnt Flate-komprimierte Bitmaps auf DeviceRGB, während ein mit icJpeg eingebettetes JPEG seine eigene Komponentenzahl behält, also ist ein Vierkomponenten-CMYK-JPEG oder ein Graustufen-JPEG in Ordnung und ein gewöhnliches RGB-JPEG nicht. Konvertiere Artwork in deiner Imaging-Pipeline zum Druckprofil, bevor es das PDF erreicht
Warum rettet /DefaultRGB keine PDF/X-1a-Datei?
/DefaultRGB hilft bei X-1a nicht, denn die Regel handelt davon, was die Maschine empfängt, nicht davon, ob das RGB charakterisiert ist. Für PDF/A lässt HotPDF RegisterDefaultColorSpace('DefaultRGB', ...) die DeviceRGB-Verwendung absorbieren: Sobald ein Default-Farbraum DeviceRGB auf ein ICC-Profil mappt, ist der Inhalt geräteunabhängig, und die PDF/A-Konsistenzprüfung akzeptiert ihn. Entwickler, die diesen Workflow hinter sich haben, versuchen hier gern dieselbe Reparatur
EnsurePDFX1aContentColorSpaces ignoriert dieses Mapping bewusst. Ein charakterisierter RGB-Wert bleibt RGB, und der X-1a-OutputIntent ist eine CMYK-Druckbedingung, also müsste ihn trotzdem jemand konvertieren. Wenn du dir einen Unterschied zwischen den beiden Archiv- und Druckprofilen merken willst, dann diesen: PDF/A fragt, ob eine Farbe eindeutig ist, PDF/X-1a fragt, ob sie bereits Tinte ist
Die Zeichenreihenfolge, und das Seiten-Setup, das nicht zählt
Weil die Prüfung bei EndDoc über bereits geschriebene Inhalte läuft, spielt die Reihenfolge, in der du das Setup machst, keine Rolle. RGB, gezeichnet bevor PDFXCompliance zugewiesen war oder bevor der OutputIntent registriert war, wird trotzdem erwischt. Das zählt für Code, der Seiten in gemeinsamen Routinen baut und sich spät für das Ausgabeprofil entscheidet, manchmal aus einer Benutzereinstellung, gewählt, nachdem das halbe Dokument existiert
Pdf.BeginDoc;
// ... OutputIntent und TrimBox wie zuvor ...
Pdf.CurrentPage.SetRGBFillColor(clRed); // Legacy-Helfer, gibt DeviceRGB aus
Pdf.CurrentPage.Rectangle(72, 72, 200, 100);
Pdf.CurrentPage.Fill;
Pdf.PDFXCompliance := 'X-1a'; // nach dem Zeichnen entschieden
Pdf.EndDoc; // wirft trotzdem: DeviceRGB vermerkt
Ein Draw-Zeitpunkt-Flag hat eine Falle, die sich zu kennen lohnt, wenn du selbst eine ähnliche Prüfung baust. Jede neue Seite wird mit einem schwarzen Grafikzustand initialisiert, über SetRGBColor(0), was ein Paar 0 0 0 rg und 0 0 0 RG ausgibt, und dürfte jenes Seiten-Setup-Boilerplate das DeviceRGB-Flag setzen, sähe jedes Dokument RGB-verunreinigt aus, für diese Prüfung wie für die PDF/A-Farb-Konsistenzprüfung. HotPDF sichert das Flag um jene Initialisierung herum und stellt es wieder her, also zählt nur Farbe, die du tatsächlich zeichnest
Wie findest du den RGB-Inhalt, wenn EndDoc wirft?
Lies die Ortsangabe am Anfang der Exception-Meldung, denn sie sagt dir, welcher der beiden Pfade das Problem gefunden hat. Die Meldung hat die Form PDFXCompliance 'X-1a': <where> uses <what>, gefolgt von der ISO-15930-1-Referenz und dem Rat, zu CMYK oder Gray zu konvertieren oder auf X-3 oder X-4 zu wechseln. Der Validator wirft eine schlichte Exception beim ersten Verstoß, matche also auf den Text statt auf eine Exception-Klasse
document content uses DeviceRGB (rg/RG operators, RGB images or annotation colours recorded during drawing)heißt, das Draw-Zeitpunkt-Flag hat ausgeschlagen. Es gibt keine Seitennummer, denn das Flag ist dokumentweit und wird vor dem Gang geprüft. Durchsuche deinen Zeichen-Code nachSetRGB*-Aufrufen, Flate-komprimierten Bitmaps, RGB-JPEGs undTColor-Anmerkungs-Farbenpage 3 image XObject /Im2 uses DeviceRGB contentoderpage 1 shading Pattern /P1 uses DeviceRGB contentkommt aus dem Ressourcengang und zeigt auf einen exakten Ressourcenschlüsseluses an ICCBased RGB colour space (N=3)nach einerColorSpace /...-Ortsangabe ist das typische Ergebnis, ein sRGB-Profil mitRegisterICCProfilezu registrieren und es überSetFillColorSpacezu wählen, ein Pfad, den das Draw-Zeitpunkt-Flag nicht sieht- Verschachtelte Ortsangaben ketten sich, etwa
page 2 Form XObject /Fm1 ColorSpace /CS1, du kannst dem Pfad also von der Seite hinunter zu der Ressource folgen, die den RGB-Raum trägt
try
Pdf.EndDoc;
except
on E: Exception do
begin
if Pos('X-1a', E.Message) > 0 then
LogPrepressFailure(Pdf.FileName, E.Message); // dein eigener Logger
raise;
end;
end;
Weil nur der erste Verstoß gemeldet wird, ist die Reparatur eines Jobs mit mehreren RGB-Quellen iterativ: beheben, neu bauen, nächste Meldung lesen. Bei Batch-Jobs zahlt es sich aus, die volle Meldung je Datei zu loggen und eine kurze Liste bekannter Täter zu führen, etwa eine Logo-Bitmap oder einen Chart-Helfer, der noch TColor nimmt
Wo das RGB-Tor in dein Preflight gehört
EnsurePDFX1aContentColorSpaces ist ein gezieltes RGB-Tor, das innerhalb deines Builds läuft, und es ergänzt einen vollständigen PDF/X-1a-Preflight, statt ihn zu ersetzen. Es deckt die RGB-Familien ab, über den Ressourcengang von jedem /Resources der Seite und über das Draw-Zeitpunkt-Flag, das HotPDFs Farbsetter für Inline-rg- und RG-Operatoren führen; verschachtelte Farbräume werden bis Tiefe 8 verfolgt als Schutz gegen missgestaltete Zyklen, und der erste Verstoß wird je EndDoc gemeldet. Andere Farb-Familien wie Lab oder CalGray sind Sache des vollen Preflights, also jage die fertige Datei als Teil deines Builds durch einen externen Validator für das vollständige Konformitätsurteil. Das größere Bild der Konformitätsausgabe zeigt der Leitfaden zu PDF/A-, PDF/X- und PDF/UA-Ausgabe mit HotPDF, und einen Validator in eine unbeaufsichtigte Pipeline zu hängen, behandelt PDF-Preflight-Prüfungen in Delphi automatisieren
HotPDF ist eine native VCL-PDF-Komponente für Delphi und C++Builder mit PDF/X-, PDF/A- und PDF/UA-Ausgabe, CMYK- und Spot-Farb-APIs und ICC-OutputIntent-Unterstützung. Details, Lizenzierung und der Trial-Download liegen auf der Produktseite der HotPDF Delphi PDF component