I am using a script (by Sergey Kritskiy from this question) so to select all shapes with specific color and replace this color with another one. I made some changes, I have also add a confirm window (at step 5) which gives a kind of "report" message before start doing it's stuff. Into the message of confirm window, I have also this layers.length so to inform me how many layers will be change. But every time gives me the same number!!! For example, if I have 300 layers, 150 blue and 150 red, even if I choose to change only blue ones, the layers.length still says 300!!! Here is the script as it looks now...

I remind you that I am new to photoshop scripting and I am not any ace of Java...

function main(){

    var hexToRGB = function(hex) { var r = hex >> 16; var g = hex >> 8 & 0xFF; var b = hex & 0xFF; return [r, g, b]; };

    function SetLayerType() {
        var layerType='';
        while(layerType == null || layerType == ''){
            layerType = prompt('Enter layers type...', '', 'Step 1');
        return layerType;
    layerType = SetLayerType();

    function SetLayerName() {
        var layerName = prompt('Enter layers name...', '', 'Step 2');
    layerName = SetLayerName();

    if (confirm('Click "Yes" and choose the color you want to replace...', false, 'Step 3')) {
        if (app.showColorPicker()){
            var color1_decimal = app.foregroundColor.rgb.hexValue;
            var color1_hexadecimal = color1_decimal.toString(16);
            var color1_rgb = hexToRGB(parseInt(color1_hexadecimal, 16));
    else {

    if (confirm('Click "Yes" and choose the new color...', false, 'Step 4')) {
        if (app.showColorPicker()){
            var color2_decimal = app.foregroundColor.rgb.hexValue;
            var color2_hexadecimal = color2_decimal.toString(16);
            var color2_rgb = hexToRGB(parseInt(color2_hexadecimal, 16));
    else {

    var layers = getLayersData(),
        sourceColor = [color1_rgb[0], color1_rgb[1], color1_rgb[2]], 
        targetColor = [color2_rgb[0], color2_rgb[1], color2_rgb[2]];
    if (confirm ('You are about to replace color for [' + layers.length + '] shapes in\n[' + activeDocument.name + '] document.\n\nOld color: (' + sourceColor + ')\nNew Color: (' + targetColor + ')\n\nDo you want to continue?',  false, 'Step 5')) {
        var colorToChange = new SolidColor();
        colorToChange.rgb.red = sourceColor[0];
        colorToChange.rgb.green = sourceColor[1];
        colorToChange.rgb.blue = sourceColor[2];
        for (var i = 0; i < layers.length; i++) {
            if (layers[i].color.rgb.hexValue == colorToChange.rgb.hexValue) {
    else {

    function getLayersData() {
        var lyrs = [];
        try {
            var layers = 0
        catch (e) {
            var layers = 1;
        while (true) {
            ref = new ActionReference();
            ref.putIndex(charIDToTypeID('Lyr '), layers);
            try {
                var desc = executeActionGet(ref);
            catch (err) {
            var lyr = {};
            lyr.type = desc.getInteger(stringIDToTypeID("layerKind"));
            lyr.name = desc.getString(charIDToTypeID("Nm  "));
            lyr.id = desc.getInteger(stringIDToTypeID("layerID"));
            if (lyr.type == layerType && lyr.name.match(layerName)) {
                var adj = desc.getList(stringIDToTypeID("adjustment")).getObjectValue(0);
                if (adj.hasKey(stringIDToTypeID("color"))) {
                    var curColor = new SolidColor();
                    curColor.rgb.red = adj.getObjectValue(stringIDToTypeID("color")).getUnitDoubleValue(stringIDToTypeID("red"));
                    curColor.rgb.green = adj.getObjectValue(stringIDToTypeID("color")).getUnitDoubleValue(stringIDToTypeID("grain"));
                    curColor.rgb.blue = adj.getObjectValue(stringIDToTypeID("color")).getUnitDoubleValue(stringIDToTypeID("blue"));
                    lyr.color = curColor;
        return lyrs

    function changeShapeColor(color) {
        var desc8 = new ActionDescriptor();
        var ref1 = new ActionReference();
        ref1.putEnumerated(stringIDToTypeID('contentLayer'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
        desc8.putReference(charIDToTypeID('null'), ref1);
        var desc9 = new ActionDescriptor();
        var desc10 = new ActionDescriptor();
        desc10.putDouble(charIDToTypeID('Rd  '), color[0]);
        desc10.putDouble(charIDToTypeID('Grn '), color[1]);
        desc10.putDouble(charIDToTypeID('Bl  '), color[2]);
        desc9.putObject(charIDToTypeID('Clr '), charIDToTypeID('RGBC'), desc10);
        desc8.putObject(charIDToTypeID('T   '), stringIDToTypeID('solidColorLayer'), desc9);
        executeAction(charIDToTypeID('setd'), desc8, DialogModes.NO);

    function selectById(id) {
        var desc1 = new ActionDescriptor();
        var ref1 = new ActionReference();
        ref1.putIdentifier(charIDToTypeID('Lyr '), id);
        desc1.putReference(charIDToTypeID('null'), ref1);
        executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);


EDIT: If you try the script, at the second step, where asks for layer name, just leave it empty!!!

1 Answer 1


First of all, your SetLayerName() doesn't return anything and your layerName is undefined. It should be like this:

function SetLayerName() {
    return prompt('Enter layers name...', '', 'Step 2');
var layerName = SetLayerName();

Then getLayersData() returns layers that are match for a specific type and name, NOT a specific color. If you want to show how many layers will be changed you should also add this condition before pushing a layer to lyrs: if (curColor.rgb.hexValue == colorToChange.rgb.hexValue) lyrs.push(lyr);

It'd be much easier for you if you'd spend an hour on any JavaScript course on any code teaching platform.


On line 42 and 43 you're defining sourceColor and targetColor from exiting arrays (color1_rgb and color2_rgb) and then on line 54 you're defining colorToChange from sourceColor. Basically you're doing

var color1_rgb = app.foregroundColor.rgb.values; // stripping down the SolidColor object
var layers = getLayersData(); //colorToChange is needed here
var sourceColor = color1_rgb;
var colorToChange = new SolidColor() // uses values of sourceColor;

Both your sourceColor and colorToChange can be defined before getLayersData() because they use values of color1_rgb, that's defined in the beginning. Even more, you're using 3 different variables to define the same thing. You don't need both color1_rgb and sourceColor, you only need to get the color once and then use it for everything.

    var colorToChange = app.foregroundColor;
    var layers = getLayersData();
  • Where exactly should I place this If condition? I put it right before lyrs.push(lyr); and I get undefined is not an object!!! I think I should follow your advice with this JavaScript course for sure!!! :( Jun 27, 2019 at 18:34
  • 1
    That's because you're creating colorToChange after you call getLayersData(), so colorToChange doesn't exist when the condition is checking. Put your whole var colorToChange = new SolidColor(); and setting its values before calling the getLayersData() Jun 27, 2019 at 19:15
  • I can't create colorToChange before getLayersData() because colorToChange "gets" from getLayersData() so it has to be first!!! Jun 28, 2019 at 15:40
  • 1
    No, your colorToChange doesn't get anything from getLayersData() Jun 28, 2019 at 19:02
  • I can't find the way to "fit" this if (curColor.rgb.hexValue == colorToChange.rgb.hexValue)!!! :( I have already start a javascript course us you said, so to understand some things better, but for now, can you please give a working example for this? Jun 29, 2019 at 7:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.