Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Target action in javascript to specific layer instead of current layer

New Here ,
May 01, 2020 May 01, 2020

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

TOPICS
Actions and scripting
4.9K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe
Community Expert ,
May 01, 2020 May 01, 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);
}

 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 02, 2020 May 02, 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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 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...

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 02, 2020 May 02, 2020

Nevbertheless very interesting post you reference here. The starnge thing is that it mentions exately what I tried to do without success, as being the solution. So I should investigate a bit more down this way.

 

Thanks!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 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. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 02, 2020 May 02, 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')))];
};

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 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); 
}
};

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 02, 2020 May 02, 2020

The approach of directly addressing the layer is meant for streamlining as well as securing the code. The reason I did say that it does not matter to know what the script is doing is that often this results in getting answers with specific "optimizations" (often tricks)  for that single use case, which I am not seeking. I want to get a general solution I can reuse in any plugin. The streamlining is a second process where I analyze if the function could have options to streamline the use-case (if interessting for othe cases as well), or should be externally streamlined.

 

Thanks fo rth eposted code which is similar to my fallback solution if I cannot dirrectly do it in one action, which would be a shame. Another post in this thread mentions a solution exactely like the one I tried before opening this post and for them it looks like it works fine. So I need to investigate this a bit more.

 

As an example of streamlining the code you posted, I would for example (later) try to use a list of layer ids (which the script listener log suggests being possible) instead of a single layer id..

 

But as said according to another post my putIdentifier instead of th eputEnumerated should work.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 02, 2020 May 02, 2020

Sory forgot to add to my previous post that I retrieve the layers using the DOM

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 2020

»Sory forgot to add to my previous post that I retrieve the layers using the DOM«

Do you iterate through all Layers and Groups via DOM?

That would almost certainly be a huge waste of time. 

 

»Thanks fo rth eposted code which is similar to my fallback solution if I cannot dirrectly do it in one action«

Selecting all the Layers that need to have a color applied in one go would not seem like a terrible performance-bump – after all there are only 8 options for Layer Colors. 

 

»But as said according to another post my putIdentifier instead of th eputEnumerated should work.«

But it doesn’t as of hotoshop 2020 so you should draw the corresponding conclusions. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 02, 2020 May 02, 2020

> Do you iterate through all Layers and Groups via DOM

> That would almost certainly be a huge waste of time. 

 

Yes, that is what I am doing. Why would this be a waste of time? I need to access most of these layers multiple times during th eprocessing. I actually first collect all layers in may own object structure with main information like name and and color so that I later only come back to this structore not the DOM.

 

> Selecting all the Layers that need to have a color applied in one go would not seem like a terrible performance-bump – after all there are only 8 options for Layer Colors. 

 

I don't understand what this has to do with the number of colors available. I speak of colorring (let's say) 100 layers with one sigle color in one run, passing a list to the action contain ing all IDs of all layers that should get that color.

 

»But as said according to another post my putIdentifier instead of th eputEnumerated should work.«

>But it doesn’t as of hotoshop 2020 so you should draw the corresponding conclusions. 

 

Ah? Where do you see that information that it does not work as of PS2020? The refered post is a recent one and I could not see such limitation mentioned.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 2020

»Why would this be a waste of time?«

Because iterating through Layers with DOM-code takes a lot longer than doing it with AM-code. 

Compare the time yourself. 

Edit: At least for a file with hundreds of Layers … 

 

»I speak of colorring (let's say) 100 layers with one sigle color in one run, passing a list to the action contain ing all IDs of all layers that should get that color.«

As there are only 8 color options the application can only need 8 runs of the corresponing function, even if it selects the Layers.

Whether one adresses the Layers via identifier or index seems pretty much irrelevant and the code can be adapted to either case. 

 

»Where do you see that information that it does not work as of PS2020?«

I did the test. (And I am not very surprised because I have observed similar with at least one other operation.) 

You did, too, if I understand you correctly, but you seem unwilling to »believe your own eyes«. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
May 02, 2020 May 02, 2020

Because iterating through Layers with DOM-code takes a lot longer than doing it with AM-code. 
Compare the time yourself. 


Sorry, my bad, I understood the emphasis to be on "iterating through all layers", not on "DOM". Yes I could agree with this as DOM is based on AM, and the layer class may retriewve all data via AM even if not used.

On the other side, as far as I know there is no proper documentation of AM. Or am I wrong here?. For simple actions there is the script listener creating some more or less opaque code, and I was not able to locate any coherent documentation of the AM getter. This is th ereason I never investigate that path excepüt where absolutely required.

 

> As there are only 8 color options the application can only need 8 runs of the corresponing function, even if it selects the Layers.

 

Sorry, looks like my english is very bad, as I still don't get the point. I am speking of one single color  here to start with (so I don't see the differenc about having 8 or 1 million "colors"). And for my understanding there is absolutely a huge difference if setting 100 layers to "red" I need to call 100 times "select" and then "setd" for the color, or one single time "select" with a list of 100 layers and then also one single time "setd" to set the color to all selected layers.

 

> Whether one adresses the Layers via identifier or index seems pretty much irrelevant and the code can be adapted to either case. 

 

Indexes are changing over time, which makes them a bad and error prone choice in this context.


> Where do you see that information that it does not work as of PS2020?«
>> I did the test. (And I am not very surprised because I have observed similar with at least one other operation.) 

 

>> You did, too, if I understand you correctly, but you seem unwilling to »believe your own eyes«. 

 

Sorry again, but for me this is not a question of believing, it is about knowing and analyzing. Of course if some of my code fails to do what I expect, I do not immediatally assume Photoshop 2020 is "wrong". And anyway it would just confiorm me in not using AM if it is expected to behavave differently tomorrow than it is today.

 

Yes, I did one single test with one other action than the one in the referenced post. And until now my conclusion from this is not tghat this does not wiork in PS2020, but that either it does not work with all action, or I may not have provbided the parameter the way the AM expects it.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 03, 2020 May 03, 2020

»And for my understanding there is absolutely a huge difference if setting 100 layers to "red" I need to call 100 times "select" and then "setd" for the color, or one single time "select" with a list of 100 layers and then also one single time "setd" to set the color to all selected layers.«

I am afraid we may not be communicating successfully – it was my point exactly that one can set all the Layers one wants to the intended color in one go. 

The code I posted a while back with the function »colorLayerByIndex« allows to do that (it takes an Array of indices as the first argument) and it can easily be amended to work with identifiers instead of the indices. 

 

»Of course if some of my code fails to do what I expect, I do not immediatally assume Photoshop 2020 is "wrong".«

That is a good attitude. 

But there comes a point, when one has whittled a test down to the very basics and ruled out mistakes on one own’s part, that it does not seem unfair to draw the conlusion: Photoshop Scripting has limitations and/or shortcomings. (And I am not saying »bugs« here.)

And then one should probably just go on and think about how to circumvent the limitations and maybe (if it seems important enough) post a Feature Request over on feedback.photoshop.com 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 03, 2020 May 03, 2020

As for formal documentation I don’t know if Adobe provides more apart from the sections in the Scripting Reference files. 

https://www.adobe.com/devnet/photoshop/scripting.html

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 2020

The following code provides a comparison for the time it takes to get an array of all the layers’ names and ids via AM-code and via DOM-code. (The AM-code actually also collects other properties into the array.) 

With a small number of Layers the DOM-code was actually faster in my test, but with a file with 60 layers/groups the DOM-code took roughly 5 times longer than the AM-code. 

So my statement 

»Because iterating through Layers with DOM-code takes a lot longer than doing it with AM-code. «

was actually incorrect for some cases and I apologize for my sloppiness; but if your files contain about 700 Layers the benefits of AM-code should be in effect. 

// 2020, use it at your own risk;
var time3 = Number(timeString());
var bbb = collectLayersViaDOM(app.activeDocument, []);
var time4 = Number(timeString());
var time1 = Number(timeString());
var aaa = collectLayersBounds ();
var time2 = Number(timeString());
alert ("\nAM_"+((time2-time1)/1000)+"\nDOM_"+((time4-time3)/1000)+"\n"+aaa.join("\n")+"\n"+bbb.join("\n"));
////// collect layers //////
function collectLayersBounds () {
// the file;
var myDocument = app.activeDocument;
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if group collect values;
if (layerSet != "layerSectionEnd" /*&& layerSet != "layerSectionStart" && isBackground != true*/) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
var theColor = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("color")));
var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theseBounds = [theBounds.getUnitDoubleValue(stringIDToTypeID("left")), theBounds.getUnitDoubleValue(stringIDToTypeID("top")), theBounds.getUnitDoubleValue(stringIDToTypeID("right")), theBounds.getUnitDoubleValue(stringIDToTypeID("bottom"))];
theLayers.push([theName, theIndex, theID, theColor, theseBounds])
};
}
catch (e) {};
};
return theLayers
};
////// function collect all layers //////
function collectLayersViaDOM (theParent, allLayers) {
	if (!allLayers) {var allLayers = new Array} 
	else {};
	for (var m = theParent.layers.length - 1; m >= 0;m--) {
		var theLayer = theParent.layers[m];
// apply the function to layersets;
		if (theLayer.typename == "ArtLayer") {
			allLayers.push([theLayer.name, theLayer.id])
			}
		else {
			allLayers = (collectLayersViaDOM(theLayer, allLayers))
// this line includes the layer groups;
			allLayers.push([theLayer.name, theLayer.id]);
			}
		};
	return allLayers
    };
////// function to get the date //////
function timeString () {
var now = new Date();
return now.getTime()
};

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 02, 2020 May 02, 2020

If you use AM correctly it never can be slower than DOM. Few weeks ago I pointed it to you in one post, but for some reason you ignored it, so I bring something that makes AM faster again:

 

ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'))

 

Put it after 14th line of your code, and compare results (also for small number of layers) 😉 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 2020

Yeah, it shaves about a hundreth of a second off (which is something when the time is about 0.02). 

 

I can’t remember in which thread you pointed it out to me, I might have »zoned out« of the conversation. 

Also I am in general not much of a »speed-hound« but in this case »putProperty« is apparently the thing that makes the difference even for the files with few Layers. 

The only case I could think of in which this DOM-code is faster than this AM-code is: a one-layer image. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 02, 2020 May 02, 2020

With one layer, DOM still can't be faster as it's based on AM, so in worst case they are equal then.

 

The post you ask for is HERE, where you changed my code removing the property that was used.

 

Personally I never used it as I wanted minimum code in code, until Jarda Bereza​ said it's faster 🙂

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 2020

»With one layer, DOM still can't be faster as it's based on AM«

Then it may be a rounding issue. 

 

I think the only code I posted in that other thread was DOM anyway but I didn’t remove code of yours; I think I was a little exasperated by the original poster’s posts and didn’t pay much attention to the other discussions in the thread. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 02, 2020 May 02, 2020

Look at 2 posts higher, over linked post, where the link to other discussion maybe soon will work.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 2020

Are you confusing me with pixxxel_schubser? 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
May 02, 2020 May 02, 2020

YES 😛

 

I don't know why, I always had problems to remember you both separately. So this is an example it happens again, but now not only in my head, but in writing as well 😄

 

For example one guy I know constantly confuse Sweden with Switzerland. I'm not, but at leasat I can understand him when I do the same thikning of you and pixxxel_schubser

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 02, 2020 May 02, 2020

I guess it might be that both names sound german-ish? 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines