PS script for toggling visibility of layers based on their names
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-visibility-of-multiple-layers-using-regex/m-p/7355269 (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.
