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); }
}