Copy link to clipboard
Copied
Hello,
I have the following problem in InDesign 2025.
I am trying to transform the CMYK color [41,46,56,36] to RGB color using the colorTransform method and the return value is [0,0,0] RGB color. Why? What am I not setting or doing wrong?
If I look at this color with the eyedropper in InDesign, it shows values of R: 117 G:103 B:88
The value does not improve even if I try to convert it to Lab or HSB first
Regards: Árpad
By one of those obscure whims that belong only to the Adobe dev team, the method app.colorTransform(…) expects and returns numbers in 0…1 — except for the LAB color space which still uses the original colorValue ranges (L: 0…100, a: -100..100, b: -100..100). So you need to properly downscale (then upscale) the values found in your Swatch/Color objects, as dictated by the specific color spaces under consideration.
Best is to have in your toolbox an adapter routine, like this:
...
Copy link to clipboard
Copied
Can you share the script?
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
But for example cyan color is work fine:
Copy link to clipboard
Copied
My original color was PANTONE 7531 C. The result of the pantone color to rgb color transformation was also [0,0,0].
Then I tried the pantone color to cmyk color transformation which gave the correct value, then the cmyk color to rgb color transformation again only gave [0,0,0]
Copy link to clipboard
Copied
But for example cyan color is work fine:
var cmykValues=[100,0,0,0], rgbValues=[]
rgbValues=app.colorTransform(cmykValues,ColorSpace.CMYK,ColorSpace.RGB);
alert(rgbValues)
By @árpádp3188668
That's strange - could be buggy I can't find much in the documentation about this.
Copy link to clipboard
Copied
I am dabbling in scripting so here's my attempt at what is going on
InDesign handles colour conversions through its internal colour management system, but it does not expose these conversion routines to scripting (unless I'm mistaken). In other words, your code isn’t wrong it is trying to call functions that InDesign does not provide. The eyedropper and other internal tools benefit from the full colour management engine, but ExtendScript only gives you access to basic colour properties.
This can give the alert but it's quite basic as I don't see a way for colortransform to work.
function cmykToRgb(cmyk) {
var C = cmyk[0] / 100;
var M = cmyk[1] / 100;
var Y = cmyk[2] / 100;
var K = cmyk[3] / 100;
var R = Math.round(255 * (1 - C) * (1 - K));
var G = Math.round(255 * (1 - M) * (1 - K));
var B = Math.round(255 * (1 - Y) * (1 - K));
return [R, G, B];
}
var cmykValues = [41, 46, 56, 36]; // Example CMYK values
var rgbValues = cmykToRgb(cmykValues);
alert("RGB: " + rgbValues.join(", "));
this makes the RGB swatch but I had to add a slight boost to get the values you wanted
function cmykToRgbApprox(cmyk) {
var C = cmyk[0] / 100;
var M = cmyk[1] / 100;
var Y = cmyk[2] / 100;
var K = cmyk[3] / 100;
// Adjusted formula to better approximate InDesign values
var R = Math.round(255 * (1 - C) * (1 - K) * 1.2); // Slight boost
var G = Math.round(255 * (1 - M) * (1 - K) * 1.1);
var B = Math.round(255 * (1 - Y) * (1 - K) * 1.05);
return [
Math.min(255, Math.max(0, R)),
Math.min(255, Math.max(0, G)),
Math.min(255, Math.max(0, B))
];
}
var doc = app.activeDocument;
var cmykValues = [41, 46, 56, 36]; // Your CMYK values
var rgbValues = cmykToRgbApprox(cmykValues);
var rgbSwatch = doc.colors.add();
rgbSwatch.model = ColorModel.PROCESS;
rgbSwatch.space = ColorSpace.RGB;
rgbSwatch.colorValue = rgbValues;
rgbSwatch.name = "Converted RGB (" + rgbValues.join(", ") + ")";
alert("RGB Values: " + rgbValues.join(", "));
You might need to adjust the boost for your own needs - but it was fun trying this.
Would love to know more or if there's a better way.
Copy link to clipboard
Copied
can you give this one a try?
var doc = app.activeDocument;
var selectedColor;
if (app.selection.length > 0 && app.selection[0].fillColor) {
selectedColor = app.selection[0].fillColor;
} else {
var swatchName = prompt("Enter the name of a swatch to convert:", "");
if (!swatchName) {
alert("No swatch selected.");
exit();
}
try {
selectedColor = doc.colors.itemByName(swatchName);
if (!selectedColor.isValid) throw new Error();
} catch (e) {
alert("Swatch not found.");
exit();
}
}
var originalModel = selectedColor.model; // Store original model (Process or Spot)
var originalSpace = selectedColor.space; // Store original color space
var cmykValues, rgbValues;
if (originalModel === ColorModel.SPOT) {
// Convert Spot (Pantone) to Process CMYK
selectedColor.model = ColorModel.PROCESS;
selectedColor.space = ColorSpace.CMYK;
cmykValues = selectedColor.colorValue;
} else if (originalSpace === ColorSpace.CMYK) {
cmykValues = selectedColor.colorValue;
} else {
alert("Selected color is neither CMYK nor Spot (Pantone).");
exit();
}
// Convert CMYK to RGB
selectedColor.space = ColorSpace.RGB;
rgbValues = selectedColor.colorValue;
// Restore original colour settings
selectedColor.model = originalModel;
selectedColor.space = originalSpace;
alert(
"CMYK: " + cmykValues.join(", ") +
"\nConverted RGB: " + rgbValues.join(", ")
);
Copy link to clipboard
Copied
Thank you very much!
I see your color space changing technique works great!
Copy link to clipboard
Copied
Unfortunately I was in a hurry.
It only works if I select an object and query its color, but if I select a base color swatch or a PANTONE color swatch by name I get the following error message:
"This color is not editable"
or for PANTONE:
"This color property is not editable"
in this line: selectedColor.space = ColorSpace.RGB;
Copy link to clipboard
Copied
For now, your own conversion function is the only solution that works well.
Copy link to clipboard
Copied
Swatch might be 'locked' so I'd try duplicate the swatch temp
Haven't tested
var doc = app.activeDocument;
var selectedColor;
var tempColor;
// Check if an object is selected and has a fill color
if (app.selection.length > 0 && app.selection[0].fillColor) {
selectedColor = app.selection[0].fillColor;
} else {
// Ask user to enter a swatch name
var swatchName = prompt("Enter the name of a swatch to convert:", "");
if (!swatchName) {
alert("No swatch selected.");
exit();
}
try {
selectedColor = doc.colors.itemByName(swatchName);
if (!selectedColor.isValid) throw new Error();
} catch (e) {
alert("Swatch not found.");
exit();
}
}
// Duplicating color to make it editable
try {
tempColor = selectedColor.duplicate();
} catch (e) {
alert("Cannot duplicate this color.");
exit();
}
var cmykValues, rgbValues;
// Function to round values
function roundArray(arr) {
return arr.map(function (num) {
return Math.round(num);
});
}
// Get CMYK values
if (tempColor.space === ColorSpace.CMYK) {
cmykValues = roundArray(tempColor.colorValue);
} else {
// Convert to CMYK first
tempColor.space = ColorSpace.CMYK;
cmykValues = roundArray(tempColor.colorValue);
}
// Convert to RGB
tempColor.space = ColorSpace.RGB;
rgbValues = roundArray(tempColor.colorValue);
// Remove temporary color
tempColor.remove();
alert(
"CMYK: " + cmykValues.join(", ") +
"\nConverted RGB: " + rgbValues.join(", ")
);
Copy link to clipboard
Copied
The conversion already works on the copy, but when creating a copy, it always asks if it can create a copy of the swatch.
Copy link to clipboard
Copied
Maybe disable alerts:
app.scriptPreferences.userInteractionLevel = UserInteractionLevel.NEVER_INTERACT;
Copy link to clipboard
Copied
Edit: I posted a script here originally, but I realised that it gives a bad result when there is text selected. I won't bother fixing it, I'll just delete it, because @Marc Autret's has found a much better way to do it, that doesn't have that problem. Please see Marc's post.
- Mark
Copy link to clipboard
Copied
By one of those obscure whims that belong only to the Adobe dev team, the method app.colorTransform(…) expects and returns numbers in 0…1 — except for the LAB color space which still uses the original colorValue ranges (L: 0…100, a: -100..100, b: -100..100). So you need to properly downscale (then upscale) the values found in your Swatch/Color objects, as dictated by the specific color spaces under consideration.
Best is to have in your toolbox an adapter routine, like this:
function colorTransform(/*num[]*/vals,/*str|ColorSpace*/from,/*str|ColorSpace*/to,/*int=0*/dec, a,k,i)
//----------------------------------
// vals :: array of numbers *as processed by Color.colorValue*, that is
// - [0..255, 0..255, 0..255] in RGB space
// - [0..100, 0..100, 0..100, 0..100] in CMYK space
// - [0..100, -128..127, -128..127] in LAB space
// - [0..360, 0..100, 0..100] in HSB space
// (Rem: MixedInk is not supported by app.colorTransform.)
// from :: source ColorSpace or key string ('RGB'|'CMYK'|'HSB'|'LAB')
// to :: dest. ColorSpace or key string ('RGB'|'CMYK'|'HSB'|'LAB')
// dec :: rounding decimal digits (use -1 to bypass rounding);
// default is 0, i.e. rounding to the nearest integer.
// Returns the converted values as a new array of 3 or 4 numbers in
// the expected ranges (i.e. as processed by Color.colorValue).
// => num[]
{
from = from.toString().toUpperCase();
to = to.toString().toUpperCase();
if( from==to ) return vals.slice();
switch( from )
{
case 'RGB':
// app.colorTransform() expects r,g,b values in 0..1 (!)
// -> divide by 255
a = [ vals[0]/255, vals[1]/255, vals[2]/255 ];
break;
case 'CMYK':
// app.colorTransform() expects c,m,y,k values in 0..1 (!)
// -> divide by 100
a = [ .01*vals[0], .01*vals[1], .01*vals[2], .01*vals[3] ];
break;
case 'HSB':
// app.colorTransform() expects h,s,b values in 0..1 (!)
// -> divide h by 360 and s,b by 100
a = [ vals[0]/360, .01*vals[1], .01*vals[2] ];
break;
case 'LAB':
// app.colorTransform() expects L,a,b values as given in original range,
// that is, L:0..100, a:-100..100, b:-100..100
a = vals.slice();
break;
default:
throw "Unsupported color space " + from;
}
try
{
a = app.colorTransform(a, ColorSpace[from], ColorSpace[to]);
}
catch(e)
{
throw "Unable to convert " + a + " from " + from + " to " + to + " [" + e + "]";
}
switch( to )
{
case 'RGB':
// app.colorTransform() returns r,g,b values in 0..1 (!)
// -> multiply by 255
a[0]*=255; a[1]*=255; a[2]*=255;
break;
case 'CMYK':
// app.colorTransform() returns c,m,y,k values in 0..1 (!)
// -> multiply by 100
a[0]*=100; a[1]*=100; a[2]*=100; a[3]*=100;
break;
case 'HSB':
// app.colorTransform() returns h,s,b values in 0..1 (!)
// -> multiply h by 360 and s,b by 100
a[0]*=360; a[1]*=100; a[2]*=100;
break;
case 'LAB':
// app.colorTransform() returns L,a,b values in original range,
// that is, L:0..100, a:-100..100, b:-100..100
default:;
}
if( 0 <= (dec|=0) )
{
k = Math.pow(10,dec);
for(i=a.length ; i-- ; a[i]=Math.round(k*a[i])/k );
}
return a;
}
// TEST: Transform the CMYK color [41,46,56,36] to RGB
// ---
var res = colorTransform( [41,46,56,36], 'CMYK', 'RGB' );
alert( res ); // => 113,97,82
Best,
Marc
Copy link to clipboard
Copied
Thanks @Marc Autret, in my quick test I did notice that app.colorTransform was returning 0..1 numbers, but I was too silly to realise that it would also require 0..1 numbers, too! Haha.
- Mark
Copy link to clipboard
Copied
in my quick test I did notice that app.colorTransform was returning 0..1 numbers
Hi Mark, just keep in mind that the LAB color space is an exception to the rule, since it takes and returns
L:0..100, a:-100..100, b:-100..100
Copy link to clipboard
Copied
Thanks, had a lot of fun with this one. Knew there was something up with that. Very strange stuff.
Copy link to clipboard
Copied
Hey @Eugene Tyson things don't always work out in the end, but that was great problem solving on your part. 🙂