Skip to main content
April 26, 2020
Answered

How do I export the color table (.act file) using a script?

  • April 26, 2020
  • 3 replies
  • 9072 views

Hi!

I'm trying to automate some of the work I am doing by scripting in Photoshop. I have a bunch of PNG files, where I need to find out which colors each and every image consists of (RBG values). I thought I could do something like this (for each and every one):

1) Open the file

2) Convert the file to Indexed color

3) Save the Color Table (as an .act file)

4) Have a Python script post-process the .act files and printout the RGB values into another file, one for each picture.

I have steps 1, 2 and 4 under control and tested. But step #3 I cannot for my life understand how to do, or even if it is possible. I've looked at the JavaScript reference guide provided by Adobe, but I cannot find any suitable method, constant, object or anything that would help me here.

 

So, my quesiton is... Is there a way for me to extract the Color Table by using a script?

(If you have any other ideas on how one could achieve this in a better way that would be awesome. The end goal is, as stated, to get the RGB colors from (many) PNG files (separated per file)).

This topic has been closed for replies.
Correct answer r-bin
Adobe often has glitches or unfinished features.

The code to load from the act file is like this and it works.
var d = new ActionDescriptor();
var r = new ActionReference();
r.putProperty(stringIDToTypeID("color"), stringIDToTypeID("colorTable"));
d.putReference(stringIDToTypeID("null"), r);
d.putPath(stringIDToTypeID("to"), new File("C:/1/aaa.act"));
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);

The code for exporting to the act file should be like this, but it does not work.
var d = new ActionDescriptor();
d.putPath(stringIDToTypeID("null"), new File("C:/1/aaa.act"));
var r = new ActionReference();
r.putProperty(stringIDToTypeID("color"), stringIDToTypeID("colorTable"));
d.putReference(stringIDToTypeID("to"), r);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
 

To solve your problem, you can use simplified parsing of the psd file to extract data directly.
try {
var act_file = new File("C:/1/aaa.act"); // your act-file here

var tmp_file = new File(Folder.temp.fsName + "/" + "~tmp.psd");

var d = new ActionDescriptor();
var d1 = new ActionDescriptor();
d1.putBoolean(stringIDToTypeID("maximizeCompatibility"), false);
d.putObject(stringIDToTypeID("as"), stringIDToTypeID("photoshop35Format"), d1);
d.putPath(stringIDToTypeID("in"), tmp_file);
d.putBoolean(stringIDToTypeID("copy"), true);
d.putBoolean(stringIDToTypeID("spot"), false);
d.putBoolean(stringIDToTypeID("alphaChannels"), false);
d.putBoolean(stringIDToTypeID("layers"), false);
d.putBoolean(stringIDToTypeID("embedProfiles"), false);
d.putBoolean(stringIDToTypeID("annotType"), false);
executeAction(stringIDToTypeID("save"), d, DialogModes.NO);

var s = "";

if (!tmp_file.open("r")) { throw("tmp file open error"); }
tmp_file.encoding = "BINARY";

tmp_file.seek(25, 0);

s = tmp_file.read(1);

if (s.charCodeAt(0) != 2) { throw("wrong color mode"); }

s = tmp_file.read(4);

var len = s.charCodeAt(0)<<24 | s.charCodeAt(1)<<16 | s.charCodeAt(2)<<8 | s.charCodeAt(3);

if (len != 0x300) { throw("wrong color len"); }

var table = tmp_file.read(len);

s = tmp_file.read(4);

var len = s.charCodeAt(0)<<24 | s.charCodeAt(1)<<16 | s.charCodeAt(2)<<8 | s.charCodeAt(3);

var data = tmp_file.read(len);

tmp_file.close();
tmp_file.remove();

var color_cnt = 256;
var transp_idx = 0xFFFF;

var n = data.indexOf("8BIM"+ String.fromCharCode(0x04,0x16,0,0,0,0,0,2));

if (n >= 0)
    {
    color_cnt = data.charCodeAt(n+12)<<8 | data.charCodeAt(n+13);
    //alert(color_cnt)
    }

var n = data.indexOf("8BIM"+ String.fromCharCode(0x04,0x17,0,0,0,0,0,2));

if (n >= 0)
    {
    transp_idx = data.charCodeAt(n+12)<<8 | data.charCodeAt(n+13);
    //alert(transp_idx)
    }

if (!act_file.open("w")) { throw("open error"); }
act_file.encoding = "BINARY";

for (var i = 0; i < 256; i++) 
    act_file.write(String.fromCharCode(table.charCodeAt(i), table.charCodeAt(256+i), table.charCodeAt(512+i)));

if (color_cnt != 256 || transp_idx != 0xFFFF) 
    act_file.write(String.fromCharCode(color_cnt>>8, color_cnt&0xFF, transp_idx>>8, transp_idx&0xFF));


if (act_file.error) { throw(act_file.error); }
    
act_file.close();

alert("done");
} 
catch(e) { alert(e); }
 
Check it out. It works.

3 replies

Participant
July 27, 2021

Hi there,

I'm using a script to add colour chips to an image –credit to Wolff (Script to Create Colour Chip Layers in Photoshop)– but it's only working on my one machine. As seen in the screenshots, all other machines end up with a grey layer in place of the colour chips layer.

I've tried on a range of machines –between Mac and PC, Photoshop 2020 and 2021– and I cannot work out why it wouldn't work on other machines.

The script (saved as a txt for attaching) and screenshots are attached for reference.

Any one have any ideas?

Thanks,

Ben

Legend
July 29, 2021

Comment out the line

tempFile.remove ();

 

and provide here the file "~ tmp.psd" from the temporary folder on the problem machine, which (file) is formed after the script is run.

 

Participant
July 29, 2021

Thanks for looking into this, r-bin. The "~ tmp.psd" file is attached. 

r-binCorrect answer
Legend
April 27, 2020
Adobe often has glitches or unfinished features.

The code to load from the act file is like this and it works.
var d = new ActionDescriptor();
var r = new ActionReference();
r.putProperty(stringIDToTypeID("color"), stringIDToTypeID("colorTable"));
d.putReference(stringIDToTypeID("null"), r);
d.putPath(stringIDToTypeID("to"), new File("C:/1/aaa.act"));
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);

The code for exporting to the act file should be like this, but it does not work.
var d = new ActionDescriptor();
d.putPath(stringIDToTypeID("null"), new File("C:/1/aaa.act"));
var r = new ActionReference();
r.putProperty(stringIDToTypeID("color"), stringIDToTypeID("colorTable"));
d.putReference(stringIDToTypeID("to"), r);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
 

To solve your problem, you can use simplified parsing of the psd file to extract data directly.
try {
var act_file = new File("C:/1/aaa.act"); // your act-file here

var tmp_file = new File(Folder.temp.fsName + "/" + "~tmp.psd");

var d = new ActionDescriptor();
var d1 = new ActionDescriptor();
d1.putBoolean(stringIDToTypeID("maximizeCompatibility"), false);
d.putObject(stringIDToTypeID("as"), stringIDToTypeID("photoshop35Format"), d1);
d.putPath(stringIDToTypeID("in"), tmp_file);
d.putBoolean(stringIDToTypeID("copy"), true);
d.putBoolean(stringIDToTypeID("spot"), false);
d.putBoolean(stringIDToTypeID("alphaChannels"), false);
d.putBoolean(stringIDToTypeID("layers"), false);
d.putBoolean(stringIDToTypeID("embedProfiles"), false);
d.putBoolean(stringIDToTypeID("annotType"), false);
executeAction(stringIDToTypeID("save"), d, DialogModes.NO);

var s = "";

if (!tmp_file.open("r")) { throw("tmp file open error"); }
tmp_file.encoding = "BINARY";

tmp_file.seek(25, 0);

s = tmp_file.read(1);

if (s.charCodeAt(0) != 2) { throw("wrong color mode"); }

s = tmp_file.read(4);

var len = s.charCodeAt(0)<<24 | s.charCodeAt(1)<<16 | s.charCodeAt(2)<<8 | s.charCodeAt(3);

if (len != 0x300) { throw("wrong color len"); }

var table = tmp_file.read(len);

s = tmp_file.read(4);

var len = s.charCodeAt(0)<<24 | s.charCodeAt(1)<<16 | s.charCodeAt(2)<<8 | s.charCodeAt(3);

var data = tmp_file.read(len);

tmp_file.close();
tmp_file.remove();

var color_cnt = 256;
var transp_idx = 0xFFFF;

var n = data.indexOf("8BIM"+ String.fromCharCode(0x04,0x16,0,0,0,0,0,2));

if (n >= 0)
    {
    color_cnt = data.charCodeAt(n+12)<<8 | data.charCodeAt(n+13);
    //alert(color_cnt)
    }

var n = data.indexOf("8BIM"+ String.fromCharCode(0x04,0x17,0,0,0,0,0,2));

if (n >= 0)
    {
    transp_idx = data.charCodeAt(n+12)<<8 | data.charCodeAt(n+13);
    //alert(transp_idx)
    }

if (!act_file.open("w")) { throw("open error"); }
act_file.encoding = "BINARY";

for (var i = 0; i < 256; i++) 
    act_file.write(String.fromCharCode(table.charCodeAt(i), table.charCodeAt(256+i), table.charCodeAt(512+i)));

if (color_cnt != 256 || transp_idx != 0xFFFF) 
    act_file.write(String.fromCharCode(color_cnt>>8, color_cnt&0xFF, transp_idx>>8, transp_idx&0xFF));


if (act_file.error) { throw(act_file.error); }
    
act_file.close();

alert("done");
} 
catch(e) { alert(e); }
 
Check it out. It works.
April 27, 2020

Wow, that's awesome. It really does work. The only part left now is to make that snippet of code work on all open documents (there will be a bunch of PNGs I want to iretate over and do the same for each and every one of them).

Thank you, I would never have solved this myself. I was about to resort to manually saving the .act files myself by going through the dialogue boxes...

Kukurykus
Legend
April 26, 2020