Quand PDFXCompliance est posé à 'X-1a', HotPDF valide la couleur du contenu tout à la fin du travail : EndDoc appelle THotPDF.EnsurePDFX1aContentColorSpaces, qui rejette tout contenu DeviceRGB, CalRGB ou ICCBased RGB n'importe où sur n'importe quelle page et lève une exception qui nomme la ressource fautive. Le fichier n'est jamais écrit comme document PDF/X-1a qu'un imprimeur renverra
Ce dernier point est tout l'enjeu. Un fichier PDF/X-1a avec un logo RGB égaré a l'air parfait à l'écran, passe une relecture rapide, puis échoue au preflight chez l'imprimeur deux jours avant le créneau presse. L'attraper dans votre build Delphi, avec un message qui vous dit quelle page et quelle image, coûte bien moins cher que de l'apprendre d'un opérateur prépresse agacé
Pourquoi le PDF/X-1a rejette-t-il le contenu RGB ?
Le PDF/X-1a rejette le RGB parce que le format promet que chaque couleur est déjà finale pour une condition d'impression CMYK précise. L'ISO 15930-1:2001 §6.2.3 limite la couleur du contenu à DeviceCMYK, DeviceGray et les colorants tons directs, c'est-à-dire les espaces Separation et DeviceN dont les alternates sont CMYK ou Gray. L'OutputIntent GTS_PDFX embarqué dans le fichier nomme cette condition d'impression, par exemple FOGRA39 offset couché, et le workflow de réception a le droit d'envoyer les chiffres directement aux plaques sans aucune conversion de couleur
Le RGB casse ce contrat. Une valeur RGB décrit une couleur relative à un écran ou un espace de travail, pas une recette d'encre, donc quelqu'un en aval devrait décider comment la séparer, et le X-1a existe précisément pour retirer cette décision au récepteur. L'ISO 32000-1 §8.6 range les espaces couleur du PDF dans les familles device, CIE-based et spéciales, et les membres RGB apparaissent dans plus d'une famille : DeviceRGB est un espace device, CalRGB et ICCBased à trois composantes sont CIE-based, et un espace Indexed ou Separation peut cacher une base ou un alternate RGB en dessous. Un vérificateur qui ne cherche que l'opérateur rg en rate la plupart. L'édition ultérieure PDF/X-1a:2003 (ISO 15930-4) garde la même règle de couleur ; notez que la valeur 'X-1a' de HotPDF écrit l'identification PDF/X-1a:2001 dans le paquet XMP
Si votre contenu est réellement RGB et doit le rester, le X-1a est la mauvaise cible. HotPDF circonscrit ce contrôle à 'X-1a' seulement, donc 'X-3' et 'X-4', qui tolèrent la couleur ICC-based et calibrée, ne sont pas concernés
Ce que EnsurePDFX1aContentColorSpaces contrôle réellement
EnsurePDFX1aContentColorSpaces combine un drapeau au moment du dessin avec un parcours récursif des ressources de chaque page, et il tourne en dernier dans la barrière PDF/X. EndDoc applique d'abord les exigences générales PDF/X : Title doit être posé, Trapped doit valoir 'True', 'False' ou 'Unknown', un OutputIntent GTS_PDFX doit exister (EnsurePDFXOutputIntent), et chaque page exige un TrimBox ou ArtBox (EnsurePDFXPageBoxes). Seulement après que ces contrôles passent, le contrôle de couleur tourne
Le premier chemin est un drapeau à l'échelle du document. Les setters de couleur RGB de HotPDF, l'embarquement d'images bitmap et les entrées de couleur d'annotations enregistrent l'usage DeviceRGB pendant que vous dessinez, ce qui couvre les opérateurs rg et RG inline qui n'apparaissent jamais dans un dictionnaire de ressources. Le second chemin parcourt les /Resources de chaque page et inspecte :
- Les espaces couleur nommés dans
/ColorSpace, dont l'abréviationRGBdes images inline comme synonyme de DeviceRGB - Le
/ColorSpacede chaque Image XObject - Les Form XObjects et Patterns de mosaïque, en récursant dans leurs propres
/Resourcesimbriquées - Les Shading Patterns et les entrées du dictionnaire
/Shadingde la page, via le/ColorSpacedu shading - Les espaces de base Indexed, les alternates Separation et DeviceN, et les espaces de base de Pattern, suivis jusqu'à une profondeur d'imbrication de 8
Trois choses sont rejetées : DeviceRGB, CalRGB, et les espaces ICCBased dont le flux de profil déclare N = 3. Les dictionnaires de ressources partagés entre Form XObjects et patterns sont visités une seule fois, pour qu'un jeu de formes se référençant mutuellement n'envoie pas le parcours en boucle. La méthode est publique sur THotPDF, mais en usage normal vous ne l'appelez jamais vous-même, car EndDoc le fait pour vous
Dessiner une page X-1a en Delphi qui passe le contrôle
Un document HotPDF X-1a conforme exige un OutputIntent CMYK, un TrimBox sur chaque page, et de la couleur posée uniquement via les API CMYK, Gray et tons directs. Le squelette ci-dessous utilise le profil FOGRA39 ; AddPDFXOutputIntent prend l'identifiant de condition de sortie, une chaîne d'info, le flux de profil ICC, son nombre de composantes, et l'espace alternate
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); // requis sur chaque page
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); // texte DeviceGray
Pdf.CurrentPage.SetFont('Arial', [], 14);
Pdf.CurrentPage.TextOut(72, 560, 0, 'Spring catalog, press edition');
Pdf.EndDoc; // le contrôle de couleur tourne ici
finally
Pdf.Free;
end;
end;
Chaque appel à base de TColor est un piège dans ce contexte. SetRGBFillColor, SetRGBStrokeColor et SetRGBColor prennent tous une couleur GDI et émettent du DeviceRGB, donc une routine helper écrite il y a des années pour des rapports orientés écran souillera un travail d'impression dès qu'elle est réutilisée. Utilisez SetCMYKFillColor, SetCMYKStrokeColor ou SetCMYKColor avec des composantes entre 0 et 1, ou les équivalents Gray
Tons directs et dégradés CMYK
Les colorants tons directs sont admis en X-1a tant que leur alternate est CMYK ou Gray. RegisterSeparation construit l'espace Separation et renvoie son nom de ressource, et RegisterAxialGradient choisit l'espace couleur du shading d'après le nombre de composantes que vous passez, quatre composantes signifiant DeviceCMYK
var
SpotCS, Ramp: AnsiString;
begin
// Encre ton direct avec une construction CMYK approximative comme alternate
SpotCS := Pdf.RegisterSeparation('Corporate Red', 'DeviceCMYK',
[0, 1, 0.8, 0.05]);
Pdf.CurrentPage.SetFillColorSpace(SpotCS);
Pdf.CurrentPage.SetFillColor([1.0]); // teinte 100%
Pdf.CurrentPage.Rectangle(72, 420, 200, 80);
Pdf.CurrentPage.Fill;
// 4 composantes par arrêt : le shading est DeviceCMYK, pas 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;
Passez trois composantes au même appel de dégradé et vous obtenez un shading DeviceRGB, que le parcours de ressources rejette sous le nom du pattern de shading. Même chose pour une Separation enregistrée avec 'DeviceRGB' comme alternate : le nom du ton direct a l'air inoffensif, mais le parcours suit l'alternate et trouve du RGB en dessous. La façon dont de telles encres ton direct sont composées quand un viewer ou un RIP retombe sur l'alternate est traitée dans l'article sur le rendu des tons directs Separation et DeviceN en Delphi
Les images raster exigent la même discipline. HotPDF verrouille les bitmaps compressés en Flate sur DeviceRGB, tandis qu'un JPEG embarqué avec icJpeg garde son propre nombre de composantes, donc un JPEG CMYK à quatre composantes ou un JPEG en niveaux de gris passe et un JPEG RGB ordinaire non. Convertissez les visuels vers le profil presse dans votre pipeline d'imagerie avant qu'ils n'atteignent le PDF
Pourquoi /DefaultRGB ne sauve-t-il pas un fichier PDF/X-1a ?
/DefaultRGB n'aide pas le X-1a parce que la règle porte sur ce que la presse reçoit, pas sur si le RGB est caractérisé. Pour le PDF/A, HotPDF laisse RegisterDefaultColorSpace('DefaultRGB', ...) absorber l'usage DeviceRGB : dès qu'un espace couleur Default mappe DeviceRGB vers un profil ICC, le contenu est indépendant du périphérique et le contrôle de cohérence PDF/A l'accepte. Les développeurs passés par ce workflow ont tendance à tenter la même réparation ici
EnsurePDFX1aContentColorSpaces ignore délibérément ce mappage. Une valeur RGB caractérisée reste du RGB, et l'OutputIntent X-1a est une condition d'impression CMYK, donc quelqu'un devrait quand même la convertir. Si vous devez retenir une différence entre les deux profils, archivage et impression, retenez celle-ci : le PDF/A demande si une couleur est non ambiguë, le PDF/X-1a demande si elle est déjà de l'encre
Ordre de dessin, et le setup de page qui ne compte pas
Comme le contrôle tourne à EndDoc sur du contenu déjà écrit, l'ordre dans lequel vous posez les choses ne compte pas. Du RGB dessiné avant que PDFXCompliance soit attribué, ou avant que l'OutputIntent soit enregistré, est quand même attrapé. Cela compte pour du code qui construit des pages dans des routines partagées et décide du profil de sortie tard, parfois depuis un réglage utilisateur choisi après que la moitié du document existe
Pdf.BeginDoc;
// ... OutputIntent et TrimBox comme avant ...
Pdf.CurrentPage.SetRGBFillColor(clRed); // helper historique, émet du DeviceRGB
Pdf.CurrentPage.Rectangle(72, 72, 200, 100);
Pdf.CurrentPage.Fill;
Pdf.PDFXCompliance := 'X-1a'; // décidé après le dessin
Pdf.EndDoc; // lève quand même : DeviceRGB enregistré
Un drapeau au moment du dessin a un piège à connaître si vous construisez un contrôle similaire vous-même. Chaque nouvelle page est initialisée avec un état graphique noir via SetRGBColor(0), qui émet une paire 0 0 0 rg et 0 0 0 RG, et si ce boilerplate de setup de page avait le droit de poser le drapeau DeviceRGB, chaque document paraîtrait souillé de RGB, tant pour ce contrôle que pour le contrôle de cohérence couleur PDF/A. HotPDF sauvegarde et restaure le drapeau autour de cette initialisation, donc seule la couleur que vous dessinez réellement compte
Comment trouver le contenu RGB quand EndDoc lève ?
Lisez la localisation au début du message d'exception, car elle vous dit lequel des deux chemins a trouvé le problème. Le message a la forme PDFXCompliance 'X-1a': <where> uses <what>, suivie de la référence ISO 15930-1 et du conseil de convertir en CMYK ou Gray ou de passer en X-3 ou X-4. Le validateur lève une Exception simple à la première violation, donc filtrez sur le texte plutôt que sur une classe d'exception
document content uses DeviceRGB (rg/RG operators, RGB images or annotation colours recorded during drawing)signifie que le drapeau au moment du dessin s'est déclenché. Pas de numéro de page, car le drapeau est à l'échelle du document et est contrôlé avant le parcours. Fouillez votre code de dessin pour des appelsSetRGB*, des bitmaps compressés en Flate, des JPEG RGB et des couleurs d'annotationTColorpage 3 image XObject /Im2 uses DeviceRGB contentoupage 1 shading Pattern /P1 uses DeviceRGB contentvient du parcours de ressources et pointe une clé de ressource exacteuses an ICCBased RGB colour space (N=3)après une localisationColorSpace /...est le résultat typique de l'enregistrement d'un profil sRGB avecRegisterICCProfileet de sa sélection viaSetFillColorSpace, un chemin que le drapeau au moment du dessin ne voit pas- Les localisations imbriquées se chaînent, par exemple
page 2 Form XObject /Fm1 ColorSpace /CS1, pour que vous puissiez suivre le chemin de la page jusqu'à la ressource qui porte l'espace RGB
try
Pdf.EndDoc;
except
on E: Exception do
begin
if Pos('X-1a', E.Message) > 0 then
LogPrepressFailure(Pdf.FileName, E.Message); // votre propre logger
raise;
end;
end;
Comme seule la première violation est rapportée, réparer un travail avec plusieurs sources RGB est itératif : réparer, recompiler, lire le message suivant. Pour des travaux en lot, ça paie de logger le message complet par fichier et de garder une courte liste de contrevenants connus, comme un bitmap de logo ou un helper de graphique qui prend encore du TColor
Où la barrière RGB se situe dans votre preflight
EnsurePDFX1aContentColorSpaces est une barrière RGB ciblée qui tourne dans votre build, et elle se couple avec un preflight PDF/X-1a complet plutôt que d'en remplacer un. Elle couvre les familles RGB, via le parcours de ressources depuis les /Resources de chaque page et via le drapeau au moment du dessin que les setters de couleur de HotPDF maintiennent pour les opérateurs rg et RG inline ; les espaces couleur imbriqués sont suivis jusqu'à la profondeur 8 en garde contre les cycles malformés, et la première violation est rapportée par EndDoc. Les autres familles de couleur comme Lab ou CalGray relèvent du preflight complet, donc passez le fichier fini dans un validateur externe comme partie de votre build pour obtenir le verdict de conformité complet. La vue d'ensemble de la sortie de conformité est dans le guide de sortie PDF/A, PDF/X et PDF/UA avec HotPDF, et le branchement d'un validateur dans un pipeline sans surveillance est couvert dans l'automatisation des contrôles preflight PDF en Delphi
HotPDF est un composant PDF VCL natif pour Delphi et C++Builder avec sortie PDF/X, PDF/A et PDF/UA, API CMYK et tons directs, et support d'OutputIntent ICC. Détails, licences et téléchargement d'essai sont sur la page produit du composant PDF HotPDF pour Delphi