Skip to main content
Known Participant
May 1, 2020
Question

Target action in javascript to specific layer instead of current layer

  • May 1, 2020
  • 4 replies
  • 4653 views

I am trying to set the tag color of a lyer in Photoshop. For this I used the action script listener and got the result below which is for the current selected layer. From an example I found on internet but for getting the current tag color I modified:

 

    ref10.putEnumerated( idLyr, idOrdn, idTrgt );

 

to

 

      ref10.putIdentifier(idLyr , layer.id );
 

 

But this still targets the currently selected layer, not the LayerSet one I passed via layer

 

Any hints would be welcome. Unfortunately I found no information about modifying logged actions for current layer for addressing a specific layer via its id.

 

// =======================================================
var idsetd = charIDToTypeID( "setd" );
var desc33 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref10 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref10.putEnumerated( idLyr, idOrdn, idTrgt );
desc33.putReference( idnull, ref10 );
var idT = charIDToTypeID( "T " );
var desc34 = new ActionDescriptor();
var idClr = charIDToTypeID( "Clr " );
var idClr = charIDToTypeID( "Clr " );
var idVlt = charIDToTypeID( "Vlt " );
desc34.putEnumerated( idClr, idClr, idVlt );
var idLyr = charIDToTypeID( "Lyr " );
desc33.putObject( idT, idLyr, desc34 );
executeAction( idsetd, desc33, DialogModes.NO );

This topic has been closed for replies.

4 replies

Brainiac
May 2, 2020

Some properties can only be set for the active layer. These include, for example, the name and color of the layer.
In the DOM model fiction occurs, because the target layer temporarily becomes active, and this is done incorrectly. The layer visibility may will turn on and the current selections of layers will be removed.

 

UPD.

It is better to set such properties immediately when creating a layer (with the "make" command).
 
Known Participant
May 3, 2020

Ok, thanks to all the posters! Very much appreciated.

 

I see I need to give some more details. At first I was writing code to export icons automatically by showing and hiding layers. This code was building the entire layer tree using javascript classes for later processing and generating of the icons.  This code may actually benefit from AM code, but... (see below).

 

The current project (linked to the first one) uses the same code to build the  javascript via DOM but then needs to generate and modify a lot of layers. As this code requires quite a lot of information provided by th eDOM, generating the tree with the DOM may be not so bad (i.e. AM not winning that much time).

 

But my base question remains, is there any reliable documentation of AM ? Just using the listener is not a good approach.

 

For instance do I understand you correctly that it would be possible to set layer name, placement and color in one single MAKE action ? Or do you refer "only" that it woul dbe better to do this all while it is selected from the MAKE anyway?

Brainiac
May 2, 2020

In most cases, DOM and AM have the same interaction features with objects that are accessible to the user through the Photoshop interface. In other words, if you cannot change the color of the layer label in the Photoshop interface without selecting it, then with a high probability it will not be possible to do this using a script.

 

If you have a pre-compiled array with laуerIDs, then the fastest way is not to select each layer separately, but to select all the necessary layers at once:

 

    function selectLayerByIDList (IDList) {
        var ref = new ActionReference()

        for (var i = 0; i < IDList.length; i++) {
            ref.putIdentifier(s2t("layer"), IDList[i])
        }

        var desc = new ActionDescriptor()
        desc.putReference(s2t("null"), ref)
       // desc.putEnumerated(s2t("selectionModifier"), s2t("addToSelectionContinuous"), s2t("addToSelection"))

        executeAction(s2t("select"), desc, DialogModes.NO)
    }

    function s2t(s) { return stringIDToTypeID(s) }

 

 

after that, apply the function with the assignment of a color label - it will be assigned to all layers in the current selection.

 

$.hiresTimer;
s2t = stringIDToTypeID;

(ref = new ActionReference()).putProperty(s2t('property'), p = s2t('numberOfLayers'));
ref.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
var len = executeActionGet(ref).getInteger(p)

var ids = []
for (var i = 1; i <= len; i++) {
    (ref = new ActionReference()).putProperty(s2t('property'), p = s2t('layerID'));
    ref.putIndex(s2t('layer'), i);
    ids.push(executeActionGet(ref).getInteger(p))
}

selectLayerByIDList(ids)
setLayerLabelCol('violet') 

alert ($.hiresTimer);

function selectLayerByIDList(IDList) {
    var ref = new ActionReference()
    for (var i = 0; i < IDList.length; i++) { ref.putIdentifier(s2t('layer'), IDList[i]) }
    (desc = new ActionDescriptor()).putReference(s2t('null'), ref)
   // desc.putEnumerated(s2t('selectionModifier'), s2t('addToSelectionContinuous'), s2t('addToSelection'))
    executeAction(s2t('select'), desc, DialogModes.NO)
}

function setLayerLabelCol(labelCol) {
    /*
        No Color = "none"
        Red = "red"
        Orange = "orange"
        Yellow = "yellowColor"
        Green = "green"
        Blue = "blue"
        Violet = "violet"
        Gray = "gray"
    */
    (ref = new ActionReference).putEnumerated(s2t('layer'), s2t('ordinal'), s2t('targetEnum'));
    (desc = new ActionDescriptor()).putReference(s2t('null'), ref);
    (desc1 = new ActionDescriptor()).putEnumerated(s2t('color'), s2t('color'), s2t(labelCol));
    desc.putObject(s2t('to'), s2t('layer'), desc1);
    executeAction(s2t('set'), desc, DialogModes.NO);
}

 

Kukurykus
Brainiac
May 2, 2020

desc.putEnumerated(s2t("selectionModifier"), s2t("addToSelectionContinuous"), s2t("addToSelection"))

Brainiac
May 2, 2020

Well, yes, there isn’t much sense in this line.

c.pfaffenbichler
Adobe Expert
May 2, 2020

I don’t seem to understand your approach fully. 

Which Layer do you want to adress and how do you know its identifier? 

What is the whole Script supposed to achieve? (Screenshots please.)  

 

In any case I see no way to change the Layer Color other than selecting it, but selecting it via Action Manager-code should at least be faster than selecting it via DOM-code. 

Known Participant
May 2, 2020

Actually it does not really matter what the entire script is to achieve, I hope there is a way to address any action directly to a given layer without requiring to select it previously. This part of the script will have to tag a lot of layers with specific tag/label colors. But other operations will follow. The document has about 700 layers.

 

Once you have a ArtLayer or LayerSet object you get its ID via the id property. It's advantage is that it is global and independent of its location in the layer tree.

 

On the internet I found the action below which uses the layer ID  to retrieve the layer color which is unfortunately  not directly exposed in the layer classes. I hope there is similar possibility with execution actions not requiring me an additional "select" (ID="slct") action.

 

Since there are som many layers and every action slows down the script noticably, I want to prevent any unecessary action. In addition from a technical point of view I always try to avoid  a combination of "select" /"do something with selection" because it is error prone.

 

I had a look at the select actioon and saw it was passing the ID via list not as single identifier. I will check if this work swith setd directly as well.

 

Selection via list could be an option of course by collection all IDs of one color and color all in ounr action, if whis works. While looking interesting from performance point of view I wtill want to avoid this approach for th ereasoin meantioned above as well as I guess it will result in the expansion of all layer sets.

 

 

//==============================================================================================
function getLayerColor(layer
    var ref = new ActionReference(); 
    
    ref.putPropertycharIDToTypeID("Prpr") ,stringIDToTypeID('color'));     
    ref.putIdentifier(charIDToTypeID"Lyr " ), layer.id );
    
    return PS2Colors[typeIDToStringID(executeActionGet(ref).getEnumerationValue(stringIDToTypeID('color')))];
};

 

c.pfaffenbichler
Adobe Expert
May 2, 2020

»Actually it does not really matter what the entire script is to achieve, I hope there is a way to address any action directly to a given layer without requiring to select it previously.«

There isn’t (at least so far).

So it does matter what the Script is intended to achieve because maybe one can streamline the process. 

 

»Once you have a ArtLayer or LayerSet object you get its ID via the id property.«

Do you collect the identifiers via DOM-code or AM-code? 

 

// 2020, use it at your own risk;
colorLayerByIndex ([1,6], "violet");
////// based on code by by mike hale, via paul riggott //////
function colorLayerByIndex(index, theColor){ 
try {
for (var m = 0; m < index.length; m++) {
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), index[m]);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
desc.putEnumerated(stringIDToTypeID( "selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection")); 
desc.putBoolean(charIDToTypeID("MkVs"), false ); 
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
};
// change color;
var desc33 = new ActionDescriptor();
var ref10 = new ActionReference();
var idLyr = charIDToTypeID("Lyr ");
ref10.putEnumerated(idLyr, charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
desc33.putReference(charIDToTypeID("null"), ref10 );
var desc34 = new ActionDescriptor();
var idClr = charIDToTypeID("Clr ");
desc34.putEnumerated(idClr, idClr, stringIDToTypeID(theColor));
desc33.putObject(charIDToTypeID("T   "), idLyr, desc34);
executeAction(charIDToTypeID("setd"), desc33, DialogModes.NO);
}catch(e){
alert(e.message); 
}
};

 

Stephen Marsh
Adobe Expert
May 2, 2020

I am not sure if I'm following 100%...

 

If there were 6 layer groups:

 

Group 6 (the last group added, index 0, highest in the stack)

Group 5

Group 4

Group 3

Group 2

Group 1 (the first group added, index 5, lowest in the stack)

 

If you wanted to label say "Group 5" as red, then it would have the index of [1]:

 

 

// color label layerset by index number.jsx

// layer set index number, starts at 0 (zero)
// last set added has the highest number (highest in the layer set stack)

var doc = app.activeDocument;
doc.activeLayer = doc.layerSets[1]; // layer set index number
setLayerLabelCol();

function setLayerLabelCol() {

    /*
    No Color = "none"
    Red = "red"
    Orange = "orange"
    Yellow = "yellowColor"
    Green = "green"
    Blue = "blue"
    Violet = "violet"
    Gray = "gray"
    */

    var labelCol = "red" // Change to a value listed above
    var c2t = function (s) {
        return app.charIDToTypeID(s);
    };
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var descriptor2 = new ActionDescriptor();
    var reference = new ActionReference();
    reference.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
    descriptor.putReference(c2t("null"), reference);
    descriptor2.putEnumerated(s2t("color"), s2t("color"), s2t(labelCol)); // variable labelCol
    descriptor.putObject(s2t("to"), s2t("layer"), descriptor2);
    executeAction(s2t("set"), descriptor, DialogModes.NO);
}

 

 

Known Participant
May 2, 2020

Thank you for your suggestion, but unfortunately this is not the solution because doc.activeLayer implicitely expands the layer group and even more important change its visibility to true if it was hidden before. Rewinding all these actions is possible of course but not the solution for several reasons including performance as I will have to process several 100's of layers.

 

Another solution I want to avoid is to select the layer via an action again due to performance. Getting the color of several 100 layers via actrion takes already a lot of time.

 

I hope there is a way to pass the layer identifier via putIdentifier as it ius for retrieving the color.

Stephen Marsh
Adobe Expert
May 2, 2020

This is above my current skill set and knowledge. Hope the following link helps!

 

https://community.adobe.com/t5/photoshop/modify-adjustment-layer-without-selecting-it-scripting/td-p/11096397?page=1