Copy link to clipboard
Copied
I have a photoshop file with dozens of folders each containing dozens of layers. Many of those layers are toggled as invisible.
Throughout all of those layers I need to change the color #eb2121 to the color #87ea76.
Currently I am doing this manually:
1. Opening each folder,
2. Toggling the visibility of each layer,
3. Clicking on each layer one by one and using the paint bucket tool to change the incorrect color to the correct color whenever I see it.
4. Re-toggling the visibility of the layers
5. closing the folder
I believe I need a script that will be able to cycle through all layers, locate instannces of the relevant colors and change the color to the new color. Preferably, the script would leave the layers' visibility status and folder open status unchanged.
Is anyone aware of such a script?
Thank you for your assistance.
Well, check out this script.
After calling the script, two ColoPickers will be called. The first sets the starting color, the second sets the ending color.
Feature: the pixel at the coordinate (0,0) must be empty on all layers, otherwise it will be corrupted (deleted).
The script does not work very fast, but faster than you can do it by hand. At the end, all folders will be collapsed, there is no other option, at least in PS2020.
try {
var tolerance = 32; // for magicwand/bucket
...
Copy link to clipboard
Copied
del
...
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Hi r-bin,
Sorry for the delayed response.
This is a cartoon character that i'm using for Adobe Character Animator, so the layout, formating and visibility toggling is done to comply with those guidelines. For the character to work in Character Animator, it needs to have the Front body toggled visible, with the Right Profile and Left Profile versions of the boddy toggled invisible.
For the attached cartoon character's body, I have multiple layers within folders. I would love to change the character's shirt color, pants color, skin color and hair color, which all appear in multiple layers.
Currently, if I wanted to change the character's shirt, I would need to open each layer that contains a sleeve or his torso and manually change the color from say a #666666 grey to a #e84521 orange, which is very long and tedious. Likewise, to change the skin color of the character would take dozens of layers.
Ideally, there would be a script that would go through each layer, identify all the pixels that are colored #666666 and change them to color #e84521, while leaving the visibility status unchanged. That would effectively change all the layers containing the character's grey shirt color into an orange shirt. I believe the accuracy of the color change is important.
Do you think that is possible?
Thank you
Copy link to clipboard
Copied
Well, check out this script.
After calling the script, two ColoPickers will be called. The first sets the starting color, the second sets the ending color.
Feature: the pixel at the coordinate (0,0) must be empty on all layers, otherwise it will be corrupted (deleted).
The script does not work very fast, but faster than you can do it by hand. At the end, all folders will be collapsed, there is no other option, at least in PS2020.
try {
var tolerance = 32; // for magicwand/bucket
if (app.showColorPicker(true))
{
var c1 = app.foregroundColor;
if (app.showColorPicker(false))
{
var c2 = app.backgroundColor;
var old_units = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
var total;
app.displayDialogs = DialogModes.NO;
set_performance("accelerated");
app.refresh();
app.activeDocument.suspendHistory("Replace Color", 'app.doForcedProgress("Replace Color", "total=f()")');
app.preferences.rulerUnits = old_units;
alert(total + " layers have been changed");
}
}
}
catch (e) { alert(e); }
function f()
{
try {
var total = 0;
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID("document"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
var d = executeActionGet(r)
var n = d.getInteger(stringIDToTypeID("numberOfLayers"));
var i0 = d.getBoolean(stringIDToTypeID("hasBackgroundLayer"))?0:1;
for (var i = i0; i <= n; i++)
{
if (!app.updateProgress(i, n)) return;
app.changeProgressText("Processed: " + i + " of " + n + ", replaced: " + total);
var r = new ActionReference();
r.putIndex(stringIDToTypeID("layer"), i);
var d = executeActionGet(r);
if (d.getInteger(stringIDToTypeID("layerKind")) != 1) continue;
var viz = d.getBoolean(stringIDToTypeID("visible"));
var r = new ActionReference();
r.putIndex(stringIDToTypeID("layer"), i);
var d = new ActionDescriptor();
d.putBoolean(stringIDToTypeID("makeVisible"), true);
d.putReference(stringIDToTypeID("null"), r);
executeAction(stringIDToTypeID("select"), d, DialogModes.NO);
if (replace_color(c1, c2, tolerance)) ++total;
if (!viz)
{
var r = new ActionReference();
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
var d = new ActionDescriptor();
d.putReference(stringIDToTypeID("null"), r);
executeAction(stringIDToTypeID("hide"), d, DialogModes.NO);
}
}
executeAction(stringIDToTypeID("collapseAllGroupsEvent"), undefined, DialogModes.NO);
return total;
}
catch (e) { throw(e); }
}
function replace_color(c1, c2, t)
{
try {
if (t == undefined) t = 32;
var ret = false;
var doc = app.activeDocument;
doc.selection.select([[0,0],[0,1],[1,1],[1,0]]);
fill(c1);
var d = new ActionDescriptor();
var r = new ActionReference();
r.putProperty(stringIDToTypeID("channel"), stringIDToTypeID("selection"));
d.putReference(stringIDToTypeID("null"), r);
var d1 = new ActionDescriptor();
d1.putUnitDouble(stringIDToTypeID("horizontal"), stringIDToTypeID("pixelsUnit"), 0);
d1.putUnitDouble(stringIDToTypeID("vertical"), stringIDToTypeID("pixelsUnit"), 0);
d.putObject(stringIDToTypeID("to"), stringIDToTypeID("point"), d1);
d.putInteger(stringIDToTypeID("tolerance"), t);
d.putBoolean(stringIDToTypeID("antiAlias"), true);
d.putBoolean(stringIDToTypeID("merged"), false);
d.putBoolean(stringIDToTypeID("contiguous"), false);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
if (doc.selection.bounds[2].value != 1 || doc.selection.bounds[3].value != 1)
{
fill(c2);
var doc = app.activeDocument;
doc.selection.select([[0,0],[0,1],[1,1],[1,0]]);
ret = true;
}
executeAction(stringIDToTypeID("delete"), undefined, DialogModes.NO);
doc.selection.deselect();
return ret;
}
catch (e) { throw(e); }
}
function fill(c)
{
try {
var red = c.rgb.red - 0.001;
if (red < 0) red = 0;
var green = c.rgb.green - 0.001;
if (green < 0) green = 0;
var blue = c.rgb.blue - 0.001;
if (blue < 0) blue = 0;
var d = new ActionDescriptor();
d.putEnumerated(stringIDToTypeID("using"), stringIDToTypeID("fillContents"), stringIDToTypeID("color"));
var d1 = new ActionDescriptor();
d1.putDouble(stringIDToTypeID("red"), red);
d1.putDouble(stringIDToTypeID("green"), green);
d1.putDouble(stringIDToTypeID("blue"), blue);
d.putObject(stringIDToTypeID("color"), stringIDToTypeID("RGBColor"), d1);
d.putUnitDouble(stringIDToTypeID("opacity"), stringIDToTypeID("percentUnit"), 100);
d.putEnumerated(stringIDToTypeID("mode"), stringIDToTypeID("blendMode"), stringIDToTypeID("normal"));
executeAction(stringIDToTypeID("fill"), d, DialogModes.NO);
}
catch (e) { throw(e); }
}
function set_performance(mode)
{
try {
var d = new ActionDescriptor();
var r = new ActionReference();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("playbackOptions"));
r.putEnumerated(stringIDToTypeID("application"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
d.putReference(stringIDToTypeID("null"), r);
var d1 = new ActionDescriptor();
d1.putEnumerated(stringIDToTypeID("performance"), stringIDToTypeID("performance"), stringIDToTypeID(mode));
d.putObject(stringIDToTypeID("to"), stringIDToTypeID("playbackOptions"), d1);
executeAction(stringIDToTypeID("set"), d, DialogModes.NO);
}
catch (e) { throw(e); }
}
Copy link to clipboard
Copied
Wow!
Thank you so much, that definitely improves my process. It took about 2 minutes to go through all my layers, which would normally take me 30 minutes of mindless clicking.
Thank you again!