Aller au contenu
getnextpdf.com

Produire des couleurs prêtes pour l'impression en CMJN et tons directs

La couleur à l’écran est en RVB. La couleur d’impression ne l’est pas. Quand une presse ou un RIP d’épreuvage consomme ton PDF, il veut des encres process (CMJN), l’occasionnelle encre nommée (un ton direct ou une couleur Separation), et une déclaration de la condition de production qu’il doit présumer. Cette recette montre les trois chemins d’émission de couleur que NextPDF te donne pour ce public :

  • Remplissages et tracés en CMJN devicesetFillColorCmyk() / setDrawColorCmyk().
  • Encres ton direct / Separation à une teinte — registerSpotColor() puis setSpotFillColor() / setSpotDrawColor().
  • Un output intent ICC qui déclare une condition de travail/sortie RVB pour tout le document — Config::withOutputColorProfile(). Les profils fournis sont des espaces de travail RVB ; cela ne déclare pas une vraie condition d’impression presse CMJN / PDF/X.

Précision de portée d’emblée : il s’agit d’émission de couleur. NextPDF écrit les nombres CMJN, l’espace Separation et la déclaration d’output intent que tu demandes. Il n’exécute pas de transformation de gestion des couleurs — il ne va pas recalculer ton illustration RVB dans un gamut CMJN de destination, l’épreuver à l’écran, ni garantir une correspondance visuelle. Fournis des couleurs déjà spécifiées pour ta condition.

Fenêtre de terminal
composer require nextpdf/core:^3

Aucune extension optionnelle n’est requise. L’API de couleur est stable depuis 1.2.0 et tourne sur la matrice de backport 8.1–8.4.

Le CMJN est le défaut pour l’impression process offset et numérique : quatre canaux, cyan / magenta / jaune / noir (la « clé »). Définis la couleur de remplissage ou de tracé, puis dessine comme d’habitude.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
// Components are percentages, 0–100 (cyan, magenta, yellow, key).
$doc->setFillColorCmyk(0, 95, 100, 0); // a process "red"
$doc->rect(20, 30, 60, 40, 'F');
$doc->setDrawColorCmyk(100, 0, 0, 0); // pure cyan rule
$doc->setLineWidth(1.0);
$doc->rect(20, 30, 60, 40, 'S');
$doc->setTextColorCmyk(0, 0, 0, 100); // rich-free 100% K text
$doc->setFont('helvetica', '', 12);
$doc->text(20, 85, 'Process CMYK');
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/cmyk.pdf');

Chaque appel émet un opérateur de couleur DeviceCMYK dans le content stream : k pour la couleur de non-tracé (remplissage/texte) et K pour la couleur de tracé, avec les quatre composantes mises à l’échelle dans la plage 0.0–1.0 que le PDF utilise en interne. ISO 32000-2 §8.6.8 (Colour Operators, Table 73) définit k et K comme les opérateurs de réglage de couleur DeviceCMYK ; §8.6.4.4 définit l’espace de couleur DeviceCMYK lui-même.

L’objet valeur sous-jacent est NextPDF\Graphics\Color. Si tu construis les couleurs directement, Color::cmyk($c, $m, $y, $k) prend les mêmes pourcentages 0–100 et est ce qu’appelle chaque méthode de document …Cmyk.

Un ton direct est une encre unique nommée — un Pantone, un HKS, un vernis, une plaque de « découpe » die-cut — que la presse charge comme sa propre plaque plutôt que de la construire à partir d’encres process. En PDF, c’est un espace de couleur Separation : un nom de colorant plus un espace alternatif (ici DeviceCMYK) et une transformation de teinte qui mappe une valeur de teinte dans [0, 1] vers l’alternatif, de sorte que les rendus non-ton-direct affichent encore une approximation.

Enregistre l’encre une fois avec son repli CMJN, puis définis-la comme couleur de remplissage ou de tracé à un pourcentage de teinte :

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
// Register the ink and its CMYK fallback (percentages, 0–100).
$doc->registerSpotColor('PANTONE 485 C', 0, 95, 100, 0);
// Full-strength fill.
$doc->setSpotFillColor('PANTONE 485 C'); // tint defaults to 100
$doc->rect(20, 30, 50, 30, 'F');
// 40% tint of the same ink.
$doc->setSpotFillColor('PANTONE 485 C', 40);
$doc->rect(80, 30, 50, 30, 'F');
// Same ink as a stroke at 75%.
$doc->setSpotDrawColor('PANTONE 485 C', 75);
$doc->setLineWidth(1.5);
$doc->line(20, 75, 130, 75);
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/spot.pdf');

Tu dois appeler registerSpotColor() avant de la sélectionner ; un nom non enregistré lève une PageLayoutException. L’enregistrement écrit la ressource Separation et la transformation de teinte ; setSpotFillColor() / setSpotDrawColor() émettent alors /CS_<token> cs <tint> scn pour un remplissage (ou la forme de tracé en majuscules /CS_<token> CS <tint> SCN) contre cette ressource Separation enregistrée. Deux noms distincts sont en jeu ici, et le moteur les gère séparément :

  • La CLÉ de ressource — le jeton /CS_… que l’opérateur du content stream référence et sous lequel est indexé le dictionnaire /Resources /ColorSpace de la page — est dérivée du nom d’encre en remplaçant chaque caractère non-mot par _, si bien que 'PANTONE 485 C' sélectionne la ressource /CS_PANTONE_485_C. (Pour les noms d’encre contenant un _ littéral, un trait d’union ou une autre ponctuation, un court suffixe déterministe est ajouté pour garder la clé sans collision, de sorte que deux noms quasi identiques ne partagent jamais un même espace de couleur.)
  • Le nom de colorant Separation lui-même — le nom porté à l’intérieur du tableau d’espace de couleur [/Separation /<name> …] — est conservé tel quel et encodé par l’écriveur comme un objet name PDF, en échappant en hexadécimal (#XX) tout délimiteur ou octet non imprimable. Il n’est pas aplati en jeton CS_… ; la clé de ressource et le nom de colorant sont calculés indépendamment.

L’argument de teinte que tu passes est un pourcentage, 0 (papier) à 100 (encre pleine), mais l’opérande écrit dans le content stream est la valeur normalisée 0.0–1.0, donc une teinte 40 émet /CS_PANTONE_485_C cs 0.400000 scn. ISO 32000-2 §8.6.6.4 couvre les espaces de couleur Separation et leur transformation de teinte.

La transformation de teinte par défaut est une interpolation linéaire de [0 0 0 0] (papier à la teinte 0) jusqu’au repli CMJN enregistré (encre pleine à la teinte 1). C’est correct pour des tons directs ordinaires ; une encre non linéaire ou un profil mesuré exige une transformation personnalisée, ce qui dépasse le cadre de cette recette.

Un PDF peut porter une déclaration au niveau du document de la condition de couleur pour laquelle ses couleurs ont été préparées — un output intent : un dictionnaire nommant la condition de production, avec le profil ICC de destination embarqué sous forme de flux ICCBased. Dans un vrai workflow d’impression/PDF-X, c’est une condition de presse CMJN (un profil FOGRA ou GRACoL couché, par exemple). Les profils que NextPDF fournit, cependant, sont des espaces de travail RVB — donc ce que Config::withOutputColorProfile() déclare est une condition de sortie de visualisation / d’espace de travail RVB, pas une destination CMJN. Lis la note sous l’exemple avant de t’y fier pour une sortie presse.

NextPDF expose cela via le Config du document. Choisis l’un des profils d’espace de travail fournis, construis le config, et crée le document à partir de lui :

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;
use NextPDF\Core\Document;
use NextPDF\Core\OutputColorProfile;
// Declare an explicit, embedded output intent for the document.
$config = (new Config())
->withOutputColorProfile(OutputColorProfile::Srgb);
$doc = Document::createStandalone($config);
$doc->addPage();
$doc->setFillColorCmyk(0, 95, 100, 0);
$doc->rect(20, 30, 60, 40, 'F');
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/with-intent.pdf');

OutputColorProfile est une énumération d’espaces de travail pour lesquels le moteur fournit un profil. Tous les cas adossés à un profil sont des espaces de travail RVB à trois composantes ; DeviceRGB est la sentinelle par défaut et n’émet aucun output intent. Il n’y a pas de profil de destination CMJN fourni :

  • DeviceRGB — le défaut. Aucun output intent n’est émis : aucune condition de sortie au niveau PDF n’est déclarée, et le pipeline PDF/A (s’il est actif) garde le contrôle exclusif du tableau /OutputIntents. Utilise-le quand tu ne veux pas en déclarer un. (Le contenu PDF DeviceRGB sans output intent est dépendant du périphérique — ce n’est pas un sRGB déclaré.)
  • Srgb — émet un dictionnaire d’output intent embarquant le sRGB.icc fourni, avec l’identifiant de condition standard sRGB IEC61966-2.1.
  • DisplayP3, Rec2020, A98RGB, ProphotoRGB — espaces de travail RVB à large gamut, chacun embarquant son profil ICC fourni sous un identifiant de condition personnalisé (NextPDF wide-gamut …).

Tout cas autre que DeviceRGB fait émettre à l’écriveur un dictionnaire d’output intent référençant le flux ICCBased embarqué (avec son décompte de composantes /N 3). ISO 32000-2 §14.11.5 définit le dictionnaire d’output intent ; §8.6.5.5 définit l’espace de couleur ICCBased qui porte le profil embarqué. Dans le moteur actuel, ce dictionnaire est écrit avec le sous-type d’output intent PDF/X /GTS_PDFX quel que soit le profil fourni que tu choisis (le chemin d’archivage PDF/A utilise son propre sous-type /GTS_PDFA1 et est émis séparément).

La mise en garde importante : parce que tous les profils fournis sont en RVB, cela déclare l’espace de travail RVB et l’intention de visualisation du document — ce n’est pas un profil de destination CMJN, et cela ne transforme rien en CMJN. Le moteur ne te laisse pas fournir un profil ICC de destination CMJN personnalisé via withOutputColorProfile(). Un vrai output intent CMJN d’impression/PDF-X exige un workflow qui embarque ton propre profil ICC CMJN comme destination ; pour un output intent d’archivage câblé dans le même tableau /OutputIntents, voir Sortie PDF/A-4.

  • CMJN device — le défaut pour toute illustration destinée à une presse process. Spécifie tes couleurs en CMJN dès le départ pour qu’aucune supposition RVB→CMJN n’ait lieu en aval.
  • Ton direct / Separation — les couleurs de marque qui doivent atteindre une encre exacte, plus les plaques non-process (vernis, blanc, métallique, die-cut, dorure). Enregistre une fois, peins à n’importe quelle teinte.
  • Output intent — définis-le quand tu veux que le fichier soit auto-descriptif sur sa condition de travail/sortie RVB, ou quand un consommateur (un lecteur, un RIP à gestion des couleurs, un validateur) attend une condition de sortie déclarée. Les profils fournis ne déclarent qu’une condition de travail/sortie RVB ; ils ne déclarent pas une vraie condition d’impression presse CMJN / PDF/X.
  • Les composantes CMJN sont des pourcentages (0–100), pas 0–1. Les méthodes de document …Cmyk et Color::cmyk() prennent chaque canal comme un pourcentage 0–100 et le divisent par 100 à l’écriture de l’opérateur ; l’opérande du content stream est la valeur normalisée 0.0–1.0. Passe 100 pour de l’encre pleine, pas 1.0 (que le moteur traiterait comme 1 % d’encre).
  • Enregistre avant de sélectionner un ton direct. setSpotFillColor() / setSpotDrawColor() lèvent une exception si le nom n’a jamais été enregistré. Les noms sont mis en correspondance exactement, casse et espaces compris.
  • L’état de couleur persiste. Une couleur CMJN ou ton direct reste en vigueur jusqu’à ce que tu la changes. Réinitialise avant un bloc sans rapport.
  • Le repli CMJN est une approximation. La transformation de teinte Separation existe pour que les rendus non-ton-direct puissent montrer quelque chose ; ce n’est pas la sortie presse. La vraie encre est ce que produit la plaque nommée.
  • Un output intent est une déclaration, pas une conversion. Déclarer OutputColorProfile::Srgb ne transforme pas tes couleurs en sRGB ; cela énonce la condition visée. La justesse des couleurs relève de ta responsabilité en amont.

Chaque sélection de couleur est un seul opérateur de content stream ; un ton direct écrit en plus une ressource Separation par encre enregistrée. Un profil d’output intent embarqué est écrit une fois par document. Tous les chemins restent largement dans le budget de 2000 ms / 64 Mo.

Cette recette émet uniquement les couleurs et le profil que ton code spécifie. Elle n’analyse aucune entrée non fiable et ne fait aucun accès réseau. Si les noms de colorant ou les composantes CMJN viennent de données externes, valide-les : écrête les composantes à 0–100 et rejette les caractères de contrôle dans les noms de ton direct (un octet NUL dans un nom Separation est rejeté par le moteur).

ÉnoncéSpecClause
k et K sont les opérateurs de couleur qui définissent la couleur DeviceCMYK de non-tracé / de tracé.ISO 32000-2§8.6.8
DeviceCMYK est l’espace de couleur process soustractif à quatre composantes.ISO 32000-2§8.6.4.4
Un espace de couleur Separation nomme un colorant dont la teinte se mappe vers un espace alternatif via une transformation de teinte.ISO 32000-2§8.6.6.4
Un espace de couleur ICCBased embarque un flux de profil ICC avec un décompte de composantes /N.ISO 32000-2§8.6.5.5
Un output intent déclare la condition de production cible ; GTS_PDFX nomme le sous-type d’impression.ISO 32000-2§14.11.5

Profil de reproductibilité — structural. L’émission de couleur n’a pas d’entropie propre, mais chaque document enregistré porte un /ID de queue et des atomes de date, et un flux ICC embarqué n’est stable au niveau des octets que pour un profil fourni fixe. La revendication soutenue est l’égalité structurelle après normalisation qpdf. Cette recette décrit comment NextPDF produit la structure ; elle n’affirme pas une conformité ISO 32000-2 générale.

Sans objet. Le CMJN device, la couleur ton direct/Separation et la déclaration d’output intent sont des capacités du Core sans barrière Premium. Le Core prend en charge la déclaration d’output intent RVB fournie montrée ici ; les workflows ICC de condition d’impression CMJN personnalisée ne sont pas revendiqués par cette recette.