Split into Layers by Index Colors, Read Index Colors
Hello,
I would like to split an image into a layer by its colors. I've searched the forum and found one, but it crashes, unfortunately. The other one seems to be working which I've found on StackExchange. But it's also extremely slow. So I thought maybe if it would be more practical to convert image into index color space. And let the user define 16,32,64...256 colors. Till this step, I think it can be done via script listener. (By the way, I guess it's only possible with Local Adaptive, Perceptual, and Selective options to define the custom color amount. So, for example first temporary convert colors into index colors in another temporary document. Create channels, copy and paste channels into previous RGB image as channels and then split into layers from channel selections.
But I couldn't be sure how to read each color in an index color table and their overall values.
I need this script mostly for separating vector-based or simple illustrations which include for example 16 colors only.
I wanted to ask before working on a script because maybe you can enlighten me with some other or easier method to do that.
Thank you.
Examples I've found;
1st one: This one separates only RGB channels as far as I understood.(from sizeoverload.com site)
#target photoshop
var doc = app.activeDocument;
var fuzz = 200;
var shadeNumber = 3;
var shadeValue = 110;
var colorRange = new Array();
colorRange[0] = {
red: 255,
green: 0,
blue: 0
};
colorRange[1] = {
red: 0,
green: 255,
blue: 0
};
colorRange[2] = {
red: 0,
green: 0,
blue: 255
};
function convertToDuotone() {
// write options for indexed color mode here
myObject = new IndexedConversionOptions();
myObject.palette = Palette.LOCALADAPTIVE;
// how many colors to split/filter the image into
myObject.colors = shadeNumber;
doc.changeMode(ChangeMode.INDEXEDCOLOR, myObject);
};
function convertToRGB() {
doc.changeMode(ChangeMode.RGB);
}
function setColorTable() {
var idsetd = charIDToTypeID("setd");
var desc20 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
var ref6 = new ActionReference();
var idClr = charIDToTypeID("Clr ");
var idClrT = charIDToTypeID("ClrT");
ref6.putProperty(idClr, idClrT);
desc20.putReference(idnull, ref6);
var idT = charIDToTypeID("T ");
var list1 = new ActionList();
for (var i = 0; i < shadeNumber; i++) {
var tableColor = new ActionDescriptor();
var idRd = charIDToTypeID("Rd ");
tableColor.putDouble(idRd, colorRange[i]['red']);
var idGrn = charIDToTypeID("Grn ");
tableColor.putDouble(idGrn, colorRange[i]['green']);
var idBl = charIDToTypeID("Bl ");
tableColor.putDouble(idBl, colorRange[i]['blue']);
var idRGBC = charIDToTypeID("RGBC");
list1.putObject(idRGBC, tableColor);
}
desc20.putList(idT, list1);
var idTrnI = charIDToTypeID("TrnI");
desc20.putInteger(idTrnI, shadeNumber);
executeAction(idsetd, desc20, DialogModes.NO);
}
convertToDuotone();
setColorTable();
convertToRGB();
doc.selection.deselect();
for (var i = 0; i < 3; i++) {
var selectColour = new SolidColor();
selectColour.rgb.red = colorRange[i]['red'];
selectColour.rgb.green = colorRange[i]['green'];
selectColour.rgb.blue = colorRange[i]['blue'];
var scaleA = (selectColour.lab.a + 128.5) / 256;
var desc11 = new ActionDescriptor();
desc11.putInteger(charIDToTypeID("Fzns"), fuzz);
var desc12 = new ActionDescriptor();
desc12.putDouble(charIDToTypeID("Lmnc"), selectColour.lab.l);
desc12.putDouble(charIDToTypeID("A "), selectColour.lab.a + scaleA);
desc12.putDouble(charIDToTypeID("B "), selectColour.lab.b + scaleA);
desc11.putObject(charIDToTypeID("Mnm "), charIDToTypeID("LbCl"), desc12);
desc11.putObject(charIDToTypeID("Mxm "), charIDToTypeID("LbCl"), desc12);
executeAction(charIDToTypeID("ClrR"), desc11, DialogModes.NO);
if (hasSelection() == true) {
var layerRef = doc.artLayers.add();
var desc140 = new ActionDescriptor();
desc140.putClass(charIDToTypeID('Nw '), charIDToTypeID('Chnl'));
var ref51 = new ActionReference();
ref51.putEnumerated(charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Msk '));
desc140.putReference(charIDToTypeID('At '), ref51);
desc140.putEnumerated(charIDToTypeID('Usng'), charIDToTypeID('UsrM'), charIDToTypeID('RvlS'));
executeAction(charIDToTypeID('Mk '), desc140, DialogModes.NO);
doc.activeChannels = [doc.channels[0], doc.channels[1], doc.channels[2]]
var myColor = new SolidColor();
myColor.rgb.red = myColor.rgb.green = myColor.rgb.blue = shadeValue;
app.activeDocument.selection.selectAll();
app.activeDocument.selection.fill(myColor, undefined, undefined, true);
app.activeDocument.selection.fill(myColor);
if ((shadeValue+36) > 255)
{
shadeValue = 255;
} else {
shadeValue += 36;
};
};
};
function hasSelection() {
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var docDesc = executeActionGet(ref);
var hasSelection = docDesc.hasKey(stringIDToTypeID("selection"));
return hasSelection;
};
doc.selection.deselect();
And the other one from stackexchange.com;
#target photoshop
var ChannelIDs = {
RED: "Rd ",
GREEN: "Grn ",
BLUE: "Bl ",
RGB: "RGB "
};
function isSelectionEmpty(doc) {
try {
return (doc.selection.bounds) ? false : true;
} catch (err) {
return true;
}
}
function createChannelFromSelection(doc, channelName) {
var chan = doc.channels.add();
chan.name = channelName;
chan.kind = ChannelType.SELECTEDAREA;
doc.selection.store(chan, SelectionType.REPLACE);
}
function cutToLayer() { // "Layer via cut"
executeAction(charIDToTypeID("CtTL"), undefined, DialogModes.NO);
}
function createSnapshot(snapshotName) {
var makDescriptor = new ActionDescriptor(),
snapshotAction = new ActionReference(),
fromRef = new ActionReference();
snapshotAction.putClass(charIDToTypeID("SnpS"));
makDescriptor.putReference(charIDToTypeID("null"), snapshotAction);
fromRef.putProperty(charIDToTypeID("HstS"), charIDToTypeID("CrnH"));
makDescriptor.putReference(charIDToTypeID("From"), fromRef);
if (snapshotName) { // Assign snapshot name
makDescriptor.putString(charIDToTypeID("Nm "), snapshotName );
makDescriptor.putEnumerated(charIDToTypeID("Usng"), charIDToTypeID("HstS"), charIDToTypeID("FllD") );
}
executeAction(charIDToTypeID("Mk "), makDescriptor, DialogModes.NO);
}
function restoreSnapshot(snapshotName) {
if (!snapshotName) { throw new Error("Expected snapshot name"); }
var selectDescriptor = new ActionDescriptor(),
snapshotRef = new ActionReference();
snapshotRef.putName(charIDToTypeID("SnpS"), snapshotName);
selectDescriptor.putReference(charIDToTypeID("null"), snapshotRef);
executeAction(charIDToTypeID("slct"), selectDescriptor, DialogModes.NO);
}
function selectChannel(channelId) {
if (!channelId) { throw new Error("Expected channel ID"); }
var setDescriptor = new ActionDescriptor(),
selectRef = new ActionReference(),
channelRef = new ActionReference(),
idChnl = charIDToTypeID("Chnl");
selectRef.putProperty(idChnl, charIDToTypeID("fsel"));
setDescriptor.putReference(charIDToTypeID("null"), selectRef);
channelRef.putEnumerated(idChnl, idChnl, charIDToTypeID(channelId));
setDescriptor.putReference(charIDToTypeID("T "), channelRef);
executeAction(charIDToTypeID("setd"), setDescriptor, DialogModes.NO);
};
function loadSelection(docName, channelName) {
var setDescriptor = new ActionDescriptor(),
selectRef = new ActionReference(),
docRef = new ActionReference(),
idChnl = charIDToTypeID("Chnl");
selectRef.putProperty(idChnl, charIDToTypeID("fsel"));
setDescriptor.putReference(charIDToTypeID("null"), selectRef);
docRef.putName(idChnl, channelName);
docRef.putName(charIDToTypeID("Dcmn"), docName);
setDescriptor.putReference(charIDToTypeID("T "), docRef);
executeAction(charIDToTypeID("setd"), setDescriptor, DialogModes.NO);
}
function convertToIndexedColour(doc) {
var opts = new IndexedConversionOptions();
opts.dither = Dither.NONE;
opts.forced = ForcedColors.NONE;
opts.matte = MatteType.NONE;
opts.palette = Palette.EXACT;
opts.transparency = false;
doc.changeMode(ChangeMode.INDEXEDCOLOR, opts);
}
function selectColourTableEntry(i) {
var actionSet = charIDToTypeID("setd");
var setDescriptor = new ActionDescriptor();
var ref = new ActionReference();
ref.putProperty(charIDToTypeID("Clr "), charIDToTypeID("ClrT"));
setDescriptor.putReference(charIDToTypeID("null"), ref);
var colourTable = new ActionList();
if (i > 0) { // Fill low part of colour table
for (var n = 0; n < i; ++n) {
addColourTableEntry(colourTable, 0, 0, 0);
}
}
// Select single entry
addColourTableEntry(colourTable, 255, 255, 255);
if (i < 255) { // Fill high part of colour table
for (var n = i + 1; n < 256; ++n) {
addColourTableEntry(colourTable, 0, 0, 0);
}
}
setDescriptor.putList(charIDToTypeID("T "), colourTable);
executeAction(actionSet, setDescriptor, DialogModes.NO);
}
function addColourTableEntry(colourTable, r, g, b) {
var entry = new ActionDescriptor();
entry.putDouble(charIDToTypeID(ChannelIDs.RED), r);
entry.putDouble(charIDToTypeID(ChannelIDs.GREEN), g);
entry.putDouble(charIDToTypeID(ChannelIDs.BLUE), b);
colourTable.putObject(charIDToTypeID("RGBC"), entry);
}
function main() {
var doc = activeDocument;
var lyr = doc.activeLayer;
// Create indexed duplicate
var dupDoc = doc.duplicate();
activeDocument = dupDoc;
convertToIndexedColour(dupDoc);
var snapshotName = "indexed";
var channelName = "matte";
var i;
// Snapshot the current history state
createSnapshot(snapshotName);
for (i = 0; i < 256; ++i) {
selectColourTableEntry(i);
// For some reason selecting channels doesn't work in indexed mode?
dupDoc.changeMode(ChangeMode.RGB);
// Create new matte from red channel
selectChannel(ChannelIDs.RED);
// If there is no selection then we're done
if (isSelectionEmpty(dupDoc)) { break; }
createChannelFromSelection(dupDoc, channelName);
// Use matte to cut new layer in original document
activeDocument = doc;
loadSelection(dupDoc.name, channelName);
cutToLayer();
doc.activeLayer.name = "Region " + (i + 1);
// Reset ready for next layer
doc.activeLayer = lyr;
activeDocument = dupDoc;
restoreSnapshot(snapshotName);
}
// Clean up
activeDocument = dupDoc;
dupDoc.close(SaveOptions.DONOTSAVECHANGES);
activeDocument = doc;
doc.activeLayer.remove();
alert("Found " + i + " region" + (i === 1 ? "" : "s"));
}
main();
