Les fonctions PDF sont l'un des aspects les plus discrets de la spécification. La plupart des développeurs les rencontrent une seule fois, en tant qu'élément dont un ombrage axial de type 2 a besoin afin de créer un fondu entre deux couleurs, puis n'y reviennent plus. C'est dommage, car le mécanisme de fonction est un petit évaluateur polyvalent que le format réutilise pour les ombrages, les fonctions de transfert, les fonctions de points de demi-teinte, les teintes de séparation et les courbes de transfert de masque progressif. Parmi les quatre types de fonctions, le type 0 est le plus puissant et le moins compris. Il s'agit d'une fonction échantillonnée : une grille multidimensionnelle de valeurs de sortie entre lesquelles le lecteur effectue une interpolation. Comme la grille peut contenir n'importe quels nombres que vous y insérez, une fonction de type 0 peut exprimer une correspondance non linéaire arbitraire, ce qui correspond exactement à la forme d'une table de correspondance (LUT) de couleurs
Cet article parcourt le dictionnaire de type 0 tel que défini par l'ISO 32000-1 au §7.10.2, puis illustre les deux cas qui comptent le plus dans un pipeline de documents : une LUT de correction colorimétrique RVB vers RVB à trois entrées, et une transformation de teinte de couleur d'accompagnement à une entrée. Le même constructeur de fonctions échantillonnées sert aux deux, et la différence entre eux réside entièrement dans le nombre d'entrées dont dispose la grille
Une fonction échantillonnée est une grille que le lecteur interpole
Une fonction de type 0 mappe un vecteur de m entrées sur un vecteur de n sorties en stockant des échantillons sur une grille régulière et en interpolant entre eux. L'ISO 32000-1 §7.10.2 liste les clés qui décrivent cette grille. /Domain contient deux nombres par entrée, les limites inférieure et supérieure de chaque axe d'entrée. /Range contient deux nombres par composant de sortie. /Size est un tableau de m entiers donnant le nombre d'échantillons le long de chaque axe d'entrée ; ainsi, une grille de douze échantillons de côté en trois dimensions a pour /Size [12 12 12] et stocke 1 728 points de grille. /BitsPerSample définit la précision de chaque valeur stockée ; HotPDF accepte 1, 2, 4, 8, 12, 16, 24 et 32 bits, ce qui correspond aux valeurs autorisées par le Tableau 38
Le flux d'échantillons est lu dans un ordre fixe. La première dimension d'entrée varie le plus rapidement, puis la deuxième, et ainsi de suite, et à chaque point de la grille, les n composants de sortie sont stockés dans l'ordre. Pour une table RVB vers RVB de trois octets par point de grille sur huit bits, la disposition est sortie rouge, sortie verte, sortie bleue, balayée d'abord sur l'entrée rouge. Deux autres clés mappent le monde continu sur la grille de nombres entiers. /Encode mappe chaque entrée de son intervalle /Domain vers la plage d'indices d'échantillons de 0 à Size[i] - 1, et /Decode remappe les entiers bruts stockés sur les intervalles de /Range. Lorsque vous les laissez à leurs valeurs par défaut, une entrée couvrant [0 1] atterrit proprement sur la grille complète et un octet stocké de 255 se décode au sommet de sa plage de sortie, ce qui est exactement ce qu'attend une LUT de couleurs normalisée [0,1]
Ordre 1 contre Ordre 3
Entre les points de la grille, le lecteur doit interpoler, et /Order choisit de quelle manière. /Order 1 correspond à une interpolation multilinéaire : linéaire le long d'un axe, bilinéaire sur deux, trilinéaire sur trois. Elle est rapide, c'est exactement ce que fait le matériel de la plupart des visionneuses, et pour une transformation de couleur fluide, elle est généralement indiscernable de toute méthode plus complexe. /Order 3 demande une interpolation par spline cubique, qui ajuste une courbe plus lisse à travers les échantillons au prix d'un travail plus important et d'une région de support plus large autour de chaque point évalué
Le compromis réside entre la densité de la grille et la fluidité de la courbe. L'ordre cubique justifie son utilisation lorsque la grille est grossière et que la transformation présente une courbure visible, car une ligne droite entre deux échantillons éloignés peut aplatir une courbe de tons d'une manière que l'œil perçoit sur les dégradés. Une fois que la grille est dense, les segments sont suffisamment courts pour que l'interpolation linéaire suive la courbe de près et l'ordre cubique n'apporte pas grand-chose. Une règle pratique consiste à ne recourir à /Order 3 qu'avec de petites grilles ou des transformations abruptes, et sinon à s'en tenir à la valeur par défaut linéaire. Notez que /Order s'applique uniquement aux fonctions de type 0, et HotPDF rejette toute valeur autre que 1 ou 3
La LUT 3D : trois entrées, trois sorties
Une correction colorimétrique RVB vers RVB est le cas d'école d'une grille à trois entrées, la LUT 3D classique utilisée dans l'étalonnage des couleurs et la mise en correspondance des appareils. Chaque axe du cube correspond à un canal d'entrée, chaque point de la grille stocke le triplet RVB corrigé pour cette coordonnée d'entrée, et le lecteur interpole trilinéairement les échantillons des coins autour de toute couleur entrante. Trois entrées sont inévitables ici car le rouge corrigé peut dépendre du vert et du bleu d'entrée, et non pas seulement du rouge d'entrée ; une courbe par canal ne peut pas exprimer la diaphonie entre les canaux, contrairement à un cube
HotPDF construit le flux de type 0 via RegisterSampledFunction, qui prend directement /Domain, /Range, /Size, /BitsPerSample et les octets d'échantillons, et renvoie l'objet fonction. Pour un cube normalisé standard, vous passez les limites [0,1] sur les trois axes d'entrée et les trois sorties, une taille N x N x N, et la table d'échantillons aplatie. Le constructeur vérifie que le nombre d'octets correspond à la grille : pour une profondeur alignée sur des octets, il s'attend à ce que le nombre d'octets soit égal à OutputCount x (BitsPerSample div 8) x le produit des tailles, et lève une exception si la longueur du tableau est incorrecte, de sorte qu'une foulée (stride) mal calculée échoue bruyamment à l'enregistrement plutôt que de s'afficher comme des données corrompues plus tard
const
N = 17; // Cube 17 x 17 x 17, la résolution de LUT ICC courante
var
LutFn: THPDFStreamObject;
Samples: TBytes;
begin
// Remplit Samples avec N*N*N points de grille, 3 octets chacun (sortie R,V,B),
// l'entrée rouge variant le plus rapidement. Construisez le triplet corrigé pour chaque
// coordonnée de grille avec votre conversion gérée par ICC, puis stockez-le.
SetLength(Samples, N * N * N * 3);
BuildCorrectedCube(Samples, N); // votre remplissage géré par la couleur
LutFn := Pdf.RegisterSampledFunction(
[0,1, 0,1, 0,1], // /Domain : trois axes d'entrée sur [0,1]
[0,1, 0,1, 0,1], // /Range : trois canaux de sortie sur [0,1]
[N, N, N], // /Size : la résolution du cube par axe
8, // /BitsPerSample
Samples,
1); // /Order 1 = trilinéaire
end;
La justesse colorimétrique du cube réside dans la façon dont vous le remplissez, et non dans la fonction PDF. La voie honnête consiste à calculer chaque point de la grille via une conversion gérée par ICC, le même moteur qui pilote un épreuvage à l'écran, afin que les nombres dans la grille aient une signification par rapport à un profil source et de destination défini. Enregistrez les profils qui délimitent la conversion avec RegisterICCProfile, qui enregistre un espace colorimétrique ICCBased (1, 3 ou 4 composants) et renvoie un nom de ressource que vous pouvez attacher au contenu alimenté par la LUT. La fonction de type 0 porte la table d'interpolation ; le profil ICC porte la signification des extrémités
Le cas 1D : une transformation de teinte de couleur d'accompagnement
Les espaces colorimétriques de séparation s'appuient sur les mêmes mécanismes pour une tâche totalement différente. Un espace de séparation, défini dans l'ISO 32000-1 §8.6.6.4, représente un colorant unique, une encre d'accompagnement telle qu'un Pantone ou un vernis, en associant un nom à une transformation de teinte : une fonction qui mappe la valeur de teinte unidimensionnelle, de 0 pour l'absence d'encre à 1 pour une pleine charge d'encre, sur un espace colorimétrique alternatif que l'appareil peut réellement rendre, généralement du CMJN. Cette transformation de teinte est fréquemment une fonction de type 0, et désormais la grille n'a plus qu'un seul axe d'entrée
C'est le contraste net avec la LUT 3D. Une encre d'accompagnement représente un degré de liberté, donc sa transformation de teinte a besoin d'une entrée et la grille est une ligne d'échantillons, chacun contenant la valeur CMJN (ou autre) à ce niveau de teinte. Le cube RVB a besoin de trois entrées car son domaine est tridimensionnel et les canaux interagissent. Même type de fonction, mêmes règles d'interpolation, dimensionnalité différente ; la spécification réutilise un évaluateur et laisse /Size décider si vous parcourez une ligne, un plan ou un cube. HotPDF encapsule toute la séparation dans RegisterSeparationLUT, qui construit en interne la transformation de teinte de type 0 à une entrée à partir d'un tableau d'octets plat et renvoie le nom de ressource de l'espace colorimétrique
var
SpotCS: AnsiString;
begin
// Quatre octets de sortie CMJN par point de grille de teinte, domaine de teinte [0..1].
// Ici 0 % d'encre -> tout à zéro, 100 % d'encre -> une composition riche,
// avec deux étapes intermédiaires ; la transformation de teinte interpole entre les deux.
SpotCS := Pdf.RegisterSeparationLUT(
'PANTONE 286 C', // nom du colorant
'DeviceCMYK', // espace colorimétrique alternatif
[ 0, 0, 0, 0, // teinte 0.00 -> 0,0,0,0
90, 60, 0, 0, // teinte 0.33
100, 80, 0, 10, // teinte 0.66
100, 72, 0, 18]); // teinte 1.00 -> pleine charge d'encre
// Utilisez SpotCS avec SetFillColorSpace / SetFillColor sur une page.
end;
Le nombre d'échantillons doit être un nombre entier de points de grille : un multiple positif du nombre de composants de l'espace alternatif, et au moins deux points afin qu'il y ait un segment à interpoler. Si vous transmettez trois octets par point contre un substitut CMJN, l'appel le rejette. Il s'agit de la même validation défensive appliquée par le constructeur 3D, ce que l'on attend d'une fonction qui, sinon, échouerait silencieusement au moment de l'impression
Où la même machinerie refait surface
Une fois que vous percevez le Type 0 comme une table d'interpolation générique, deux autres fonctionnalités de contrôle de périphérique cessent de ressembler à des cas particuliers. Une fonction de transfert ajuste les valeurs des composants lors de leur envoi vers le périphérique de sortie, et il s'agit simplement d'une fonction par canal ; HotPDF l'enregistre en tant qu'ExtGState via RegisterTransferFunctionState, qui accepte soit une fonction combinée, soit un tableau de fonctions par canal. Puisque ces fonctions sont des objets fonctionnels ordinaires, vous pouvez lui passer exactement le même THPDFStreamObject que RegisterSampledFunction renvoie et piloter une courbe de transfert à partir d'une table échantillonnée plutôt qu'à partir d'une formule
var
ToneFn: THPDFStreamObject;
GsName: AnsiString;
begin
// Une courbe de tons échantillonnée à une seule entrée et une seule sortie sur [0,1].
ToneFn := Pdf.RegisterSampledFunction(
[0,1], [0,1], [256], 8, ToneCurveBytes, 1);
// Appliquez-la à tous les canaux en tant que fonction de transfert /TR2 combinée.
GsName := Pdf.RegisterTransferFunctionState(ToneFn, []);
// Sélectionnez GsName sur la page avant de dessiner le contenu concerné.
end;
La génération du noir et le retrait de sous-couleur (UCR) appartiennent à la même famille. Lorsqu'un appareil convertit du RVB en CMJN, il décide quelle proportion du composant gris doit être imprimée à l'encre noire, et la spécification exprime cette décision sous la forme d'une fonction, les entrées /BG2 et /UCR2 d'un dictionnaire d'état graphique, chacune étant une courbe à une seule entrée allant du gris calculé à une quantité de noir. Ce sont également des fonctions de Type 0 lorsque vous souhaitez une courbe mesurée plutôt qu'analytique, construites de la même manière via RegisterSampledFunction et placées dans l'état graphique. La leçon à retenir est que la fonction PDF n'est jamais l'endroit où s'opère la gestion des couleurs ; c'est la table de correspondance qui porte une décision que vous avez prise avec un véritable moteur de couleurs, et le Type 0 est le seul type de fonction suffisamment flexible pour porter n'importe quelle décision
Pour une vue d'ensemble de la façon dont les polices, les images et les ressources de couleurs sont émises dans un document final, consultez notre présentation détaillée de la sortie de rapports avec des polices et des images. Lorsque la sortie doit survivre à un archivage ou à un contrôle en amont pour l'impression, les règles relatives à l'espace colorimétrique et à l'intention de sortie abordées dans le guide de validation PDF/A, PDF/X et PDF/UA déterminent quelles fonctions sont autorisées et comment la couleur de l'appareil doit être balisée. Tout cela est inclus dans le Composant HotPDF pour Delphi et C++Builder, aux côtés des API d'ombrage, ICC et de séparation qui s'appuient sur le même cœur de Type 0