Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
There were some bugs in the version I posted from my first attempt at removing stdlib and Stream dependencies.
This version works, at least for the testing I've done.
-X
//
// ColorTable
// This class reads and writes color table files from disk.
// This assumes that the index color table is (at most) 256 colors long.
// If the file contains less, toString will pad with 0,0,0 entries.
//
// $Id: ColorTable.jsx,v 1.5 2009/08/02 17:10:48 anonymous Exp $
// Copyright: (c)2007, xbytor
// License: http://creativecommons.org/licenses/LGPL/2.1
// Contact: xbytor@gmail.com
//
////============================= ColorTable ====================================
ColorTable = function() {
var self = this;self.file = null;
self.colors = [];
};
ColorTable.RcsId = "$Id: ColorTable.jsx,v 1.5 2009/08/02 17:10:48 anonymous Exp $";ColorTable.prototype.typename = "ColorTable";
//
// toString always returns 256 colors
//
ColorTable.prototype.toString = function() {
var self = this;
var str = '';if (!self.colors || self.colors.length == 0) {
return undefined;
}for (var i = 0; i < 256; i++) {
if (i >= self.colors.length) {
str += "0,0,0\n";
} else {
var sc = self.colors;
var rgb = sc.rgb;
str += rgb.red + ',' + rgb.green + ',' + rgb.blue + '\n';
}
};return str;
};ColorTable.prototype.read = function(str) {
var self = this;$.level = 1; debugger;
self.colors = [];for (var i = 0; i < 256; i++) {
var sc = new SolidColor();
var rgb = sc.rgb;rgb.red = str.readByte();
rgb.green = str.readByte();
rgb.blue = str.readByte();
self.colors.push(sc);if (str.eof()) {
break;
}
}
};ColorTable.prototype.readFromFile = function(fptr) {
var self = this;if (fptr.constructor == String) {
fptr = File(fptr);
}var file = self.file = fptr;
file.open("r");
file.encoding = 'BINARY';
var s = file.read();
file.close();var str = {
str: s,
ptr: 0
};str.readByte = function() {
var self = this;
if (self.ptr >= self.str.length) {
return -1;
}
return self.str.charCodeAt(self.ptr++);
};str.eof = function() {
return this.ptr >= this.str.length;
};self.read(str);
};ColorTable.prototype.apply = function(fptr) {
var self = this;cTID = function(s) { return cTID
|| cTID= app.charIDToTypeID(s); };
sTID = function(s) { return sTID|| sTID= app.stringIDToTypeID(s); };self.readFromFile(fptr);
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty(cTID('Clr '), cTID('ClrT'));
desc.putReference(cTID('null'), ref);var list = new ActionList();
var colors = self.colors;
for (var i = 0; i < colors.length; i++) {
var color = colors;
var cdesc = new ActionDescriptor();
cdesc.putDouble(cTID('Rd '), color.rgb.red);
cdesc.putDouble(cTID('Grn '), color.rgb.green);
cdesc.putDouble(cTID('Bl '), color.rgb.blue);
list.putObject(cTID('RGBC'), cdesc);
}desc.putList(cTID('T '), list);
return executeAction(cTID('setd'), desc, DialogModes.NO);
};
/*
Sample Usagevar clrTbl = new ColorTable();
clrTbl.apply("~/Desktop/temp/bianca.act");var clrTbl = new ColorTable();
clrTbl.readFromFile("~/someTable.act");
var str = clrTbl.toString();
alert(str);
*/// for testing
ColorTable.main = function() {
var clrTbl = new ColorTable();
clrTbl.apply("~/Desktop/temp/bianca.act");
};
//ColorTable.main();"ColorTable.jsx";
// EOF
Copy link to clipboard
Copied
Cool, thanks xBytor!
i just got everything working as intended as well without any external dependeencies. 😃
Much appreciated!
Copy link to clipboard
Copied
Xbytor, great code. Thanks!
I have a question:
How should we do to invert the process? I mean, read the color table from the active document and put it into an array or maybe save to an .act file.
thanks again...
Copy link to clipboard
Copied
Hi Peter,
The active document contains a colour palette as soon as you convert it to an indexed colour format (change mode). Saving that out shouldn't be hard by literally reverting the process to write out the colour bytes of the document into a filestream.
Cheers,
Gunnar
Copy link to clipboard
Copied
I've forgotten how to read the color palette from a document. But once you have the SolidColor objects and load them into a ColorTable object,
this code will save them out to a file.
//
// ColorTable.writeToFile usage:
// var tbl = new ColorTable();
// // load tbl.colors with SolidColor objects
// tbl.writeToFIle("~/Desktop/my-table.act");
//
ColorTable.prototype.writeToFile = function(file) {
var self = this;if (file.constructor == String) {
file = File(file);
}file.open("w") || Error.runtimeError(9002, "Unable to open output file \"" +
file + "\".\r" + file.error);
file.encoding = 'BINARY';var str = {
str: [],
ptr: 0
};str.writeByte = function(b) {
var self = this;
self.str[self.ptr++] = String.fromCharCode(b);
return self;
};var len = Math.min(colors.length, 256);
for (var i = 0; i < len; i++) {
var color = colors;
str.writeByte(color.rgb.red);
str.writeByte(color.rgb.green);
str.writeByte(color.rgb.blue);
}var len = str.str.length;
for (var i = 0; i < len; i++) {
file.write(str.str);
}
file.close();
};
Copy link to clipboard
Copied
Thanks guys.
Xbytor, if you remember how to read the table from the active document, could you please post it?
I have been looking a way to do it, but I can't find it anywhere...
Copy link to clipboard
Copied
As I recall, there is not a way to read the table. If there where you would not need the code above, you could deal with the table without reading and writing table files.
You might be able to come up with a script that saves the doc to a temp file, extracts the lookup table using a command line app like ImageMagic, then convert that data into something that works with Xbytor's code if you need to get the table on the fly.
If not save the table in the GUI and use it with X's code.
Copy link to clipboard
Copied
Ok, thank you very much guys for the "enlightenment".
I used the suggestion for saving a temp GIF file and extracting the table using the Xbytor's Stream Class (Thanks again X).
I adapted a function from original "Stream.binToHex" to get individual hex color values based on the location of the table inside the GIF file.
Here is the code:
// Get individual colors by decimal order number,
// in Hex format from a GIF image read from file
#include "xtools/xlib/stream.js"
Stream.getTbColor = function(s, ColorNumber) {
function hexDigit(d) {
if (d < 10) return d.toString();
d -= 10;
return String.fromCharCode('A'.charCodeAt(0) + d);
}
var GifTbStart = 0xD;
var GifTbEnd = 0x6f; // 32 Colors
var colorString = 3; // Constant -> RGB
var str = '';
s = s.toString();
if (GifTbStart+(colorString*ColorNumber)+colorString < GifTbEnd){ // Color table limit
for (var i = GifTbStart+(colorString*ColorNumber); i < GifTbStart+(colorString*ColorNumber)+colorString; i++) {
var ch = s.charCodeAt(i);
str += hexDigit(ch >> 4) + hexDigit(ch & 0xF);
}
}
else {
str = 'Out of range'
}
return str;
}
//
// Test loading individual colors into an array
//
var indexTable = [];
var img = Stream.readFromFile("~/file.gif");
importColors = function (){
for (i=0; i< 32; i++){ // 32 Colors
indexTable[i+1] = Stream.getTbColor(img, i); // shifted from color #0 to #1
}
}
importColors();
alert(indexTable[15]+'\n'+indexTable[18]);
//
// Test calling one color
//
tellColor = function(indexNumber) {
var test = Stream.getTbColor(img, indexNumber);
alert(test);
}
tellColor(25);
Thanks again,
PeterGun
Copy link to clipboard
Copied
Why the '32 colors' stuff? Is this just the size of the color tables in your gifs or is it some other restriction?
Copy link to clipboard
Copied
32 is the size of the color table from the gifs on this specific project I'm working on. ; )
I think the correct (general) approach, if someone needs to work with images of various tables sizes, would be identifying the number of colors from the image file and then read the color triplets based on this info. I think that may be possible by reading the info for Color Resolution on the Logical Screen Descriptor of the file.
As I was working on a fixed size table, I did't need to go that far.
Copy link to clipboard
Copied
continuing...
I wrote a script to read a color table from a GIF file and save to an ACT color table file. I think it might be useful for someone.
It goes a little more deeper than the code I posted before, as it now identifies the table size. It is important because it tells how much data to read.
Some gif files, even if they are saved with a reduced palette (less than 256), they have all the bytes for the full color palette filled inside the file (sometimes with 0x000000). But, some gif files exported in PS via "save for web" for example, have the color table reduced to optimize file size.
The script store all colors into an array, allowing some kind of sorting, or processing at will.
It uses the xlib/Stream.js in xtools from Xbytor
Here is the code:
// reads the color table from a GIF image
// saves to an ACT color table file format
#include "xtools/xlib/Stream.js"
// read the 0xA byte in hex format from the gif file
// this byte has the color table size info at it's 3 last bits
Stream.readByteHex = function(s) {
function hexDigit(d) {
if (d < 10) return d.toString();
d -= 10;
return String.fromCharCode('A'.charCodeAt(0) + d);
}
var str = '';
s = s.toString();
var ch = s.charCodeAt(0xA);
str += hexDigit(ch >> 4) + hexDigit(ch & 0xF);
return str;
};
// hex to bin conversion
Math.base = function(n, to, from) {
return parseInt(n, from || 10).toString(to);
}
//load test image
var img = Stream.readFromFile("~/file.gif");
hex = Stream.readByteHex(img); // hex string of the 0xA byte
bin = Math.base(hex,2,16); // binary string of the 0xA byte
tableSize = bin.slice(5,8) // Get the 3 bit info that defines size of the ct
switch(tableSize)
{
case '000': // 6 bytes table
tablSize = 2
break;
case '001': // 12 bytes table
tablSize = 4
break;
case '010': // 24 bytes table
tablSize = 8
break;
case '011': // 48 bytes table
tablSize = 16
break;
case '100': // 96 bytes table
tablSize = 32
break;
case '101': // 192 bytes table
tablSize = 64
break;
case '110': // 384 bytes table
tablSize = 128
break;
case '111': // 768 bytes table
tablSize = 256
break;
}
//========================================================
// read a color (triplet) from the color lookup table
// of a GIF image file | return 3 Bytes Hex String
Stream.getTbColor = function(s, color) {
function hexDigit(d) {
if (d < 10) return d.toString();
d -= 10;
return String.fromCharCode('A'.charCodeAt(0) + d);
}
var tbStart = 0xD; // Start of the color table byte location
var colStrSz = 3; // Constant -> RGB
var str = '';
s = s.toString();
for (var i = tbStart+(colStrSz*color); i < tbStart+(colStrSz*color)+colStrSz; i++) {
var ch = s.charCodeAt(i);
str += hexDigit(ch >> 4) + hexDigit(ch & 0xF);
}
return str;
}
var colorHex = [];
importColors = function (){
for (i=0; i< tablSize; i++){ // number of colors
colorHex = Stream.getTbColor(img, i);
}
}
importColors();
// remove redundant colors
// important to determine exact color number
function unique(arrayName){
var newArray=new Array();
label:for(var i=0; i<arrayName.length;i++ ){
for(var j=0; j<newArray.length;j++ ){
if(newArray==arrayName)
continue label;
}
newArray[newArray.length] = arrayName;
}
return newArray;
}
colorHex = unique(colorHex);
// we have now an array with all colors from the table in hex format
// it can be sorted if you want to have some ordering to the exported file
// in case, add code here.
var colorStr = colorHex.join('');
//=================================================================
// Output to ACT => color triplets in hex format until 256 (Adr. dec 767)
// if palette has less than 256 colors, is necessary to add the
// number of colors info in decimal format to the the byte 768.
ColorNum = colorStr.length/6;
lstclr = colorStr.slice(-6); // get last color
if (ColorNum < 10){
ColorNum = '0'+ ColorNum;
}
cConv = function (s){
var opt = '';
var str = '';
for (i=0; i < s.length ; i++){
for (j=0; j<2 ; j++){
var ch = s.charAt(i+j);
str += ch;
}
i ++;
opt += String.fromCharCode(parseInt(str,16));
str = '';
}
return opt
}
output = cConv(colorStr);
// add ending file info for tables with less than 256 colors
if (ColorNum < 256){
emptyColors = ((768-(colorStr.length/2))/3);
lstclr = cConv(lstclr);
for (i=0; i < emptyColors ; i++){
output += lstclr; // fill 256 colors
}
output += String.fromCharCode(ColorNum) +'\xFF\xFF'; // add ending bytes
}
Stream.writeToFile("~/file.act", output);
PeterGun
Copy link to clipboard
Copied
Cool, this thread turns out as one of the most useful ones I've ever seen! Good work Peter, thanks a bunch.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Thanks for the post of the script in advance.
There were a few things not directly working like the function charIDToTypeID() had to be properly used. The file mamber had to be prefixed by a "self.", too, to be correctly referenced for some reason.
It's utterly annoying that the photoshop API doesn't support palettes itself. We have to use palettes a lot in our company and this is a major drawback of Photoshop.
Again, thanks for the post.
Regards
Copy link to clipboard
Copied
Find more inspiration, events, and resources on the new Adobe Community
Explore Now