Copy link to clipboard
Copied
I work with Photoshop for a team that creates animated desktop pets. In a summary, when we work with asymmetrical characters, there are a lot of layers and groups that need to be turned on or off when we need to export the frames of the character looking to the other side. So there are layers that are called "Eye Asym", "Left Arm Asym", "Right Ear Asym", etc., and those can be inside of multiple groups that are inside of other groups.
I'm trying to set a script that can toggle on/off all groups or layers that contain " Asym" on the name, all at once.
After a lot of research, and multiple failed attempts, the only one I have found that is close to work is this one: https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-request-for-toggling-visibilit... (General expression changed for my case)
#target photoshop
var re = /.* Asym/; // a reg exp
var matches = collectNamesAM(re); // get array of matching layer indexes
for( var l = 0; l < matches.length; l++ ){
makeActiveByIndex( matches, false );
// do something with layer
var docLayer = app.activeDocument.activeLayer;
docLayer.visible=docLayer.visible==false;
// test matches with alert
//alert(app.activeDocument.activeLayer.name);
} // next match if any
function collectNamesAM(re){
var allLayers = new Array();
var startLoop = Number( !hasBackground() );
var endLoop = getNumberOfLayer();
for( var l = startLoop;l < endLoop; l++){
while( !isValidActiveLayer( l ) ) {
l++;
}
if( getLayerNameByIndex( l ).match(re) != null){
allLayers.push( l );
}
}
return allLayers;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: getActiveLayerIndex
// Description: Gets gets the Action Manager API index
// of activeLayer corrected for Background Layer
// Usage: var idx = getActiveLayerIndex();
// Input: None
// Return: Number - correct AM itemIndex
// Dependices: hasBackground
//////////////////////////////////////////////////////////////////////////////*/
function getActiveLayerIndex() {
var ref = new ActionReference();
ref.putProperty( 1349677170 , 1232366921 );
ref.putEnumerated( 1283027488, 1332896878, 1416783732 );
var res = executeActionGet(ref).getInteger( 1232366921 )
- Number( hasBackground() );
res == 4 ? res++:res // why the skip in this doc?
return res;
}
/*//////////////////////////////////////////////////////////////////////////////
// Function: isValidActiveLayer( )
// Description: Checks LayerSection for 'real' layers
// Usage: if( isValidActiveLayer() )
// Input: None
// Return: Boolean - True if not the end of a Set
// Notes: Needed only if the layer was made active
// using Action Manager API
//////////////////////////////////////////////////////////////////////////////*/
function isValidActiveLayer( idx ) {
var propName = stringIDToTypeID( 'layerSection' ); // can't replace
var ref = new ActionReference();
ref.putProperty( 1349677170 , propName); // TypeID for "Prpr"
// 'Lyr ", idx
ref.putIndex( 1283027488, idx );
var desc = executeActionGet( ref );
var type = desc.getEnumerationValue( propName );
var res = typeIDToStringID( type );
return res == 'layerSectionEnd' ? false:true;
};
/*//////////////////////////////////////////////////////////////////////////////
// Function: hasBackground
// Description: Test for background layer using AM API
// Usage: if( hasBackground() );
// Input: None
// Return: Boolean - true if doc has background layer
// Notes: Requires the document to be active
// DOM: App.Document.backgroundLayer
//////////////////////////////////////////////////////////////////////////////*/
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;
};
function makeActiveByIndex( idx, forceVisible ){
try{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putIndex(charIDToTypeID( "Lyr " ), idx)
desc.putReference( charIDToTypeID( "null" ), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), forceVisible );
executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO );
}catch(e){ return -1;}
};
function getNumberOfLayer(){
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
var numberOfLayer = desc.getInteger(charIDToTypeID("NmbL"));
return numberOfLayer;
};
function getLayerNameByIndex( idx ) {
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "Nm " ));
ref.putIndex( charIDToTypeID( "Lyr " ), idx );
return executeActionGet(ref).getString(charIDToTypeID( "Nm " ));;
};
But it doesn't work properly, because it toggles multiple times in a row the top group of layers that contains a layer with the word " Asym" inside, instead of toggling those layers once.
I appreciate any help you can provide.
That Script referred to a specific name, so here is one with a few changes:
// hide or show layers with a certain name-part;
// 2022, use it at your own risk;
if (app.documents.length > 0) {
var thisName = "Asym";
var theLayers = collectLayersByName(thisName);
for (var x = 0; x < theLayers.length; x++) {
if (theLayers[x][3] == true) {var idhide = stringIDToTypeID( "hide" )}
else {var idhide = stringIDToTypeID( "show" )};
var desc22 = new ActionDescriptor();
...
Copy link to clipboard
Copied
Copy link to clipboard
Copied
OMG yes! why didn't I find this one during all the research I made!?
It works with predefined names. Is there a way to make it works with Reg Ex? or at least to work with names that contain a specific word within?
Because all the names of the layers I need to toggle are different, but they all share the same word "Asym"
Ie. "Left Ear Asym", "Right Arm Asym", "Left Eye Asym", etc.
Copy link to clipboard
Copied
I posted an edited version after the initial post, did you check that out?
Copy link to clipboard
Copied
That Script referred to a specific name, so here is one with a few changes:
// hide or show layers with a certain name-part;
// 2022, use it at your own risk;
if (app.documents.length > 0) {
var thisName = "Asym";
var theLayers = collectLayersByName(thisName);
for (var x = 0; x < theLayers.length; x++) {
if (theLayers[x][3] == true) {var idhide = stringIDToTypeID( "hide" )}
else {var idhide = stringIDToTypeID( "show" )};
var desc22 = new ActionDescriptor();
var list2 = new ActionList();
var ref8 = new ActionReference();
ref8.putIdentifier( stringIDToTypeID( "layer" ), theLayers[x][2] );
list2.putReference( ref8 );
desc22.putList( stringIDToTypeID( "null" ), list2 );
executeAction( idhide, desc22, DialogModes.NO );
}
};
////// collect layers with certain name //////
function collectLayersByName (aName) {
// get number of layers;
var ref = new ActionReference();
ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
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 theVisibility = layerDesc.getBoolean(stringIDToTypeID('visible'));
if (theName.match(aName) != null) {theLayers.push([theName, theIndex, theID, theVisibility])}
};
}
catch (e) {};
};
return theLayers
};
Copy link to clipboard
Copied
It works perfectly!
Thank you very much for your time!!