Copy link to clipboard
Copied
I'm still trying to get the hang of Action Manager code, but I keep hitting a wall. I'm trying to figure out how I can get all of the children of the selected group, but I can't find a way to do this.
- How can I retrieve all elements below a group (LayerSet) through AM code?
- Is it possible to retrieve the parent of a specific layer?
- Is it possible to collapse/expand groups with AM code?
How do you guys attack these kinds of challenges? I have googled and searched github for these questions, but I haven't found anything of help. I feel like there's just a few of you that knows AM code, how did you plow your way into learning AM coding? I mean, the basic operations that can be recorded by the listener is doable even for me, but approaching challenges like the one's I have now, I don't even know where to start?
Hey simene49649793, these 2 functions should get you half way there.
getDocumentInfo() - Retrieves the document information. Super cool function that I found in one of these forums. This is similar to Generator's getDocumentInfo. It has some optional params to retrieve more specific data.
This AM function will return the document object as a string, because ExtendScript is very limited unfortunately. You will have to parse it using a JSON polyfill. I use this one: https://github.com/JavierAroche/descriptor-info/blob/master/example/helpers/JSON.jsx
...Copy link to clipboard
Copied
Hi simene49649793,
there is a script study years ago written by Michael L. Hale (RIP)
This should help you out:
// written by Michael L.Hale
// selektiert alle Ebenen in der aktiven Gruppe
// assumes the group you want to select the layer in is the activeLayer
var groupStartIdx = getActiveLayerIndex();
app.activeDocument.activeLayer = app.activeDocument.activeLayer.layers[app.activeDocument.activeLayer.layers.length-1];
var groupEndIdx = getActiveLayerIndex();
for(l=groupEndIdx;l<groupStartIdx;l++){
addToLayerSelectionByIndex( l );
}
function addToLayerSelectionByIndex( idx ) {
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex( charIDToTypeID('Lyr '), idx );
desc.putReference( charIDToTypeID('null'), ref );
desc.putEnumerated( stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection') );
desc.putBoolean( charIDToTypeID('MkVs'), false );
executeAction( charIDToTypeID('slct'), desc, DialogModes.NO );
};
function getActiveLayerIndex() {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" ));
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var res = executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" )) - Number( hasBackground() );
return res;
};
function hasBackground(){
var res = undefined;
try{
var ref = new ActionReference();
ref.putProperty( 1349677170 , 1315774496);
ref.putIndex( 1283027488, 0 );
executeActionGet(ref).getString(1315774496 );;
res = true;
}catch(e){ res = false}
return res;
};
Have fun
Copy link to clipboard
Copied
Hey simene49649793, these 2 functions should get you half way there.
getDocumentInfo() - Retrieves the document information. Super cool function that I found in one of these forums. This is similar to Generator's getDocumentInfo. It has some optional params to retrieve more specific data.
This AM function will return the document object as a string, because ExtendScript is very limited unfortunately. You will have to parse it using a JSON polyfill. I use this one: https://github.com/JavierAroche/descriptor-info/blob/master/example/helpers/JSON.jsx
You can then grab the document.layers key which includes all the layers in the document.
function getDocumentInfo() {
// Build Action Descriptor
var ref = new ActionReference();
var desc = new ActionDescriptor();
var psJSON = stringIDToTypeID("json");
ref.putProperty(charIDToTypeID('Prpr'), psJSON);
ref.putEnumerated(stringIDToTypeID("document"), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc.putReference(charIDToTypeID('null'), ref);
// desc.putBoolean(stringIDToTypeID("expandSmartObjects"), true);
// desc.putBoolean(stringIDToTypeID("selectedLayers"), true);
// desc.putBoolean(stringIDToTypeID("getTextStyles"), true);
// desc.putBoolean(stringIDToTypeID("getFullTextStyles"), true);
// desc.putBoolean(stringIDToTypeID("getDefaultLayerFX"), true);
// desc.putBoolean(stringIDToTypeID("getPathData"), true);
return executeAction(charIDToTypeID( "getd" ), desc, DialogModes.NO).getString(psJSON);
}
getSelectedLayerIDs() - Retrieves the selected layer IDs as an array.
function getSelectedLayerIDs() {
var selectedLayerIDs = [];
// Filter selected layers
var docRef = new ActionReference();
docRef.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var docDesc = executeActionGet(docRef);
// Get target layer ids
if( docDesc.hasKey(stringIDToTypeID('targetLayersIDs'))) {
targetLayersIDsDesc = docDesc.getList( stringIDToTypeID('targetLayersIDs'));
for(var ii = 0; ii < targetLayersIDsDesc.count; ii++) {
selectedLayerIDs.push(Number(targetLayersIDsDesc.getReference( ii ).getIdentifier()));
}
}
return selectedLayerIDs;
}
Once you have the document layers as an object and the selected layer IDs, you can simply iterate through all the layers (recursive function) until you find the one you're looking for. If you're only targeting one group layer, it will be a lot easier.
- Is it possible to retrieve the parent of a specific layer?
This one is tricky, but if you're comfortable with recursive functions, you should be able to get the parent layer of the any layer in a document.
collapseAllGroups() - Collapses all document groups.
function collapseAllGroups() {
try {
var idcollapseAllGroupsEvent = stringIDToTypeID( "collapseAllGroupsEvent" );
var desc13 = new ActionDescriptor();
return executeAction( idcollapseAllGroupsEvent, desc13, DialogModes.NO );
} catch(err) {}
}
How do you guys attack these kinds of challenges? I have googled and searched github for these questions, but I haven't found anything of help. I feel like there's just a few of you that knows AM code, how did you plow your way into learning AM coding? I mean, the basic operations that can be recorded by the listener is doable even for me, but approaching challenges like the one's I have now, I don't even know where to start?
It takes a lot of practice, patience, googling and spending lots of hours in forums
DBarranca is authoring a Photoshop Scripting book. That will be great for people trying to learn all of this.
http://www.davidebarranca.com/2016/10/new-course-photoshop-scripting/
Some resources that have helped me a lot:
I made this little module to better understand Action Descriptors.
https://github.com/JavierAroche/descriptor-info
Hope it helps!
Copy link to clipboard
Copied
The code is here to get layerset layers...
Copy link to clipboard
Copied
If want select all nested layers in one selected group then you can simply
1) create group - Ctrl + G
2) remove group - Ctrl + Shift + G
3) now you have all nested layers selected (recursively)
4) get selected layers indexes/ids
This should have good performance for complex nested layers.
Parent of specific layer
1) select your layer by index/id
2) app.activeDocument.activeLayer.parent.id
Copy link to clipboard
Copied
Hi Jarda Bereza,
did you try the performance of the code in the last three posts? Do you have problems with the performance of it?
Perhaps you can show a working code snippet for making a time comparison? I like to learn.
Copy link to clipboard
Copied
pixxxel schubser napsal(a):
Perhaps you can show a working code snippet for making a time comparison? I like to learn.
I did some time measurement.
Document has 1634 layers, 287 groups and 11136px × 6740px
1) 64 layers selected in 5 groups - 1402ms
2) 141 layers selected in 32 groups - 291ms
(ExtendScript Toolkit his buil-in time measurement features.)
Limitations:
- you can't group artboards
- you can create only 10 nested groups
If you select one layer by ID/index it should be +- 20ms per layer
DOM recursion is slow. With ActionManager you can read layers, they don't have tree structure but it is linear structure. So it is very fast, but you probably need select layers one by one. You can select layers range, but I am not sure how much reliably it is.
Code here: http://pastebin.com/dgUqSb1n
Copy link to clipboard
Copied
I've aproach these problems into my toggle open close groups script, there is also a function that can get the children and one that can get the parent with AM. You will find them in this collection:
just go to the BCM_ToolsUi/ extras/scripts and here the file with all the necessay functions is mb_utils.jsxinc
Copy link to clipboard
Copied
Great.
The TO simene49649793 ask: "It is possible? How can I do this?"
And we start a very usefully discussion about: What is the first class way to do this?
I will also take a look next year on the several links. Thx for this.
I wish you all the best and a Happy New Year 2017
Copy link to clipboard
Copied
pixxxel schubser: That was a clever way to do it! I've been able to retrieve all children of selected groups using this method, works great I would wish it was possible to retrieve them without making selections, but if I can figure out how to collapse groups afterwards it won't matter Also, using this method I think it should be easy to find the parent layer also by just decreasing the layer index until a hit a LayerSet, I'll try that later. Thank you
JavierAroche: That getDocumentInfo was awesome I couldn't get collapseAllGroups to work though, it doesn't seem to do anything Thank you for all of the resources
Thank you everyone, this is extremely interesting and helpful! I'm still looking for a way to collapse/expand LayerSets, so if anyone have any ideas on how to do this I'd be really interested to hear how it can be done Happy new year guys, and thanks again
Copy link to clipboard
Copied
You can actually use AM to get the childrens of a layerset, without selecting each layer, that's the beauty of AM. I'm using it to get the chlid layers like this: I'm starting on the parent layerset and set a variable x to 1, then with a loop I go backwards by using the putIndex method for the layer class, with index set to i--, and everytime I get an LayerSectionStart, I'm incrementing the x var, and if I get an LayerSectionEnd I'm decrementing x, when I get x to be equal to 0, I stop the loop, and this way I know that all the layers gathered in an array while the loop run, are the child layers. I usually gather the id's of the layers, the idx and the names...this way I can use another function to select all the layers by Id.
As for the closing of a layer group I've solved it by selecting all the child layers, unparent them and group them into another set. And set the properties of the second set similar to the first group...Expanding the layer set it's easy you just have to select one child of that layer set. please take a look of the script I've mention to see how I've done it.
Thank you. And Happy New Year to you all.
Copy link to clipboard
Copied
I couldn't get collapseAllGroups to work though, it doesn't seem to do anything
simene49649793 - That's weird, maybe the "collapseAllGroupsEvent" isn't available in your version of Photoshop? I just tested that same function and it seems to be working on Photoshop CC 2014.2.2 and CC 2015.0.0.