Skip to main content
Inspiring
June 9, 2021
Answered

Get infos about all selected layers?

  • June 9, 2021
  • 6 replies
  • 6926 views

Hello,

Based on the following script found on the net (don't remember where exactly because I made lots of searches), is there a way to add more infos to the selected layers? I would like to know if a layer is a LayerSet or not, and also if it is "movable" (not locked and not background layer).

 

Please look at the "???" at the end of the script

 

function getSelectedLayersInfo() {
	var lyrs = [];
	var lyr;
	var ref = new ActionReference();
	var desc;
	var tempIndex = 0;
	var ref2;
	ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("targetLayers"));
	ref.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
	
	var targetLayers = executeActionGet(ref).getList(stringIDToTypeID("targetLayers"));
	for (var i = 0; i < targetLayers.count; i++) {
		ref2 = new ActionReference();
		// if there's a background layer in the document, AM indices start with 1, without it from 0
		try {
			activeDocument.backgroundLayer;
			ref2.putIndex(charIDToTypeID('Lyr '), targetLayers.getReference(i).getIndex());
			desc = executeActionGet(ref2);
			tempIndex = desc.getInteger(stringIDToTypeID("itemIndex")) - 1;
		} catch (o) {
			ref2.putIndex(charIDToTypeID('Lyr '), targetLayers.getReference(i).getIndex() + 1);
			desc = executeActionGet(ref2);
			tempIndex = desc.getInteger(stringIDToTypeID("itemIndex"));
		}
	
		lyr = {};
		lyr.index = tempIndex;
		lyr.id = desc.getInteger(stringIDToTypeID("layerID"));
		lyr.name = desc.getString(charIDToTypeID("Nm  "));
		///// lyr.isLayerSet = ???????
		///// lyr.isLocked = ???????
		///// lyr.isBackground = ???????
		lyrs.push(lyr);
	}
	
	return lyrs;
}

 

This script works fine on Photoshop CS6, but doesn't return enough informations about selected layers for my use.

 

Thank you.

This topic has been closed for replies.
Correct answer Kukurykus

 

lyr.isBackgrounLayer = desc.getBoolean(stringIDToTypeID('background'))
lyr.positionLocked = desc.getObjectValue(stringIDToTypeID('layerLocking')).getBoolean(stringIDToTypeID('protectPosition'))
lyr.typename = ({'true': 'LayerSet', 'false': 'ArtLayer'})[!(typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection'))).split('Content').length-1)]

 

6 replies

frmorelAuthor
Inspiring
June 13, 2021

With your help, and some script found on the net, I wrote two functions to "save" the actual state of selected layer(s), and restore the saved state. As I am very far to be a JSX or AM expert, these scripts could certainly be optimized. At least, they work with Photoshop CS6.

 

Usage sample:

var arrSavedLayersIDs = saveSelectedLayersIds();
//... perform your actions
restoreSelectedLayersIds(arrSavedLayersIDs);

 

function saveSelectedLayersIds() {
	var cTID = charIDToTypeID; // shortcut
	var sTID = stringIDToTypeID; // shortcut
	
	var arrSavedLayersIDs = [];
	var thisLayerDesc;
	
	var ref = new ActionReference();
	ref.putProperty(sTID("property"), sTID("targetLayers"));
	ref.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Trgt'));
	
	if (executeActionGet(ref).count > 0) {
		// ---------------------------------------------- several active layers
		var layersDesc = executeActionGet(ref).getList(sTID("targetLayers"));
		// -------------------------- selected layers loop
		var ref2;
		for (var i = 0; i < layersDesc.count; i++) {
			ref2 = new ActionReference();
			// if there's a background layer in the document, AM indices start with 1, without it from 0
			try {
				activeDocument.backgroundLayer;
				ref2.putIndex(cTID('Lyr '), layersDesc.getReference(i).getIndex());
			} catch (e) {
				ref2.putIndex(cTID('Lyr '), layersDesc.getReference(i).getIndex() + 1);
			}
			thisLayerDesc = executeActionGet(ref2);

			arrSavedLayersIDs.push(thisLayerDesc.getInteger(sTID("layerID")));
		}
	
	}else{
		// ---------------------------------------------- only one layer active
		ref = new ActionReference();
		ref.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt')); // reference is active layer
		thisLayerDesc = executeActionGet(ref);
		
		arrSavedLayersIDs.push(thisLayerDesc.getInteger(sTID("layerID")));
	}
	
	return arrSavedLayersIDs;
}

 

function restoreSelectedLayersIds(arrSavedLayersIDs) {
	if (Object.prototype.toString.call(arrSavedLayersIDs) === '[object Array]') {
		selectLayerByID(arrSavedLayersIDs[0], false);
		for (i = 1; i < arrSavedLayersIDs.length; i++) {
			selectLayerByID(arrSavedLayersIDs[i], true);
		}
		return '';
	}else{
		return "ERROR: arrSavedLayersIDs is not an array.";
	}
}

function selectLayerByID(idLayer, addToSelection) {
    var addToSelection = addToSelection || false;
    
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putIdentifier(charIDToTypeID('Lyr '), idLayer);
    desc1.putReference(charIDToTypeID('null'), ref1);
    if (addToSelection) desc1.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
    
    try {
    	executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
    	return true;
	} catch (e) {
		return false;
	}
}
frmorelAuthor
Inspiring
June 9, 2021

Guys, you need to be very patient with me, because if I'm quite familiar with "pure" Javascript, I don't understand at all code like Kukurykus'one:

sTT = stringIDToTypeID;
(dsc = executeActionGet(ref)).getBoolean(sTT('background'))
dsc.getObjectValue(sTT('layerLocking')).getBoolean(sTT('protectPosition'))
!(typeIDToStringID(dsc.getEnumerationValue(sTT('layerSection'))).split('Content').length-1)

 

I mean, how can I include this code to my original script? How can I set the lyr object at the end of my script with this code? It's certainly a newbie question.

		lyr = {};
		lyr.index = tempIndex;
		lyr.id = desc.getInteger(stringIDToTypeID("layerID"));
		lyr.name = desc.getString(charIDToTypeID("Nm  "));
		///// lyr.isLayerSet = ???????
		///// lyr.isLocked = ???????
		///// lyr.isBackground = ???????
		lyrs.push(lyr);

 

Concerning the other posted scripts, they all seem to work with a passed layer reference... And I still don't know how to have a reference to a layer with my bloody original script 😞

Kukurykus
Legend
June 9, 2021

Probably the page did not refresh for you. Check my code again and you'll see it ideally fit to your script. I mean simply copy content of my post and replace with:

///// lyr.isLayerSet = ???????
///// lyr.isLocked = ???????
///// lyr.isBackground = ???????

 

frmorelAuthor
Inspiring
June 9, 2021

Thnk you Kukurykus! 🙂

I didn't see you update, sorry.

 

On strange thing: it tells me the layer "lockedLayer" is unlock (see screen capture):

Stephen Marsh
Community Expert
Community Expert
June 9, 2021

I created the following script to help find layer based information when creating scripts that deal with layers:

 

/* https://community.adobe.com/t5/photoshop/could-you-select-all-layers-sequentially/m-p/11741392 */

#target photoshop

/////////// ACTIVE LAYER INSPECTOR v1.4 ///////////
/// Displays some info about the current layer ///

/* Name = Not unique */
/* itemIndex = Changes with layer addition/removal, Offset by -1 */
/* layer.id = Unique, Static */

try {
    var savedRuler = app.preferences.rulerUnits;
    app.preferences.rulerUnits = Units.PIXELS;

    var doc = app.activeDocument;
    var docLayer = doc.activeLayer;
    var layerName = docLayer.name;
    var itemIndex = docLayer.itemIndex - 1;
    var layerID = docLayer.id;
    var typeName = docLayer.typename;
    var Kind = docLayer.kind;
    var bgLayer = docLayer.isBackgroundLayer;
    var Parent = docLayer.parent;

    /* https://community.adobe.com/t5/photoshop/find-out-the-size-and-position-of-an-object-in-a-layer/td-p/12057799 */
    var bounds = activeDocument.activeLayer.bounds;

    alert('ACTIVE LAYER INSPECTOR - v1.4' + '\r' + 'Layer Name: ' + layerName + '\r' + 'Layer Item Index #: ' + itemIndex + '\r' + 'Layer ID #: ' + layerID + '\r' + 'Layer Type: ' + typeName + '\r' + 'Layer Kind: ' + Kind + '\r' + 'Parent: ' + Parent + '\r' + 'isBackgroundLayer: ' + bgLayer + '\n' + 'Layer Bounds -' + '\r' + 'X: ' + bounds[0] + ', Y: ' + bounds[1] + '\n' + 'Width: ' + (bounds[2] - bounds[0]) + ', Height: ' + (bounds[3] - bounds[1]));
    app.preferences.rulerUnits = savedRuler;
}
catch (e) {
}

 

I didn't know about the other scripts posted above, so I'm keen to give them a look and perhaps borrow interesting bits!

frmorelAuthor
Inspiring
June 9, 2021

Thank you for your quick answers 🙂

 

@Kukurykus: maybe I didn't understand how to use your code in my script but Photoshop 6 tells me that sTT is not a function.

 

@c.pfaffenbichler: interesting but:

- Key 13 is "layerLocking: DescValueType.OBJECTTYPE
[ActionDescriptor]_layerLocking", even the layer is locked or not

- can't figure how to know if the layer is a LayerSet, or if its parent is a LayerSet.

 

As I really don't understand these deep codes, maybe another solution would be to have a reference to the current layer (at the end of the loop), so I could use:

lyr.isLayerSet = (layerRef.typename == 'LayerSet');
lyr.isLocked = layerRef.allLocked;

So, how could I have a layer reference from the initial code?

Kukurykus
Legend
June 9, 2021

Oh, I'm sorry, copy - paste failed. The mistake is corrected in my edited code 😉

c.pfaffenbichler
Community Expert
Community Expert
June 9, 2021

You can use this code to get more information about a selected Layer and use that to amend your Script. 

// based on code by michael l hale;
// 2012, use it at your own risk;
if (app.documents.length > 0) {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var layerDesc = executeActionGet(ref);
checkDesc2 (layerDesc);
};
////// based on code by michael l hale //////
function checkDesc2 (theDesc) {
var c = theDesc.count;
var str = '';
for(var i=0;i<c;i++){ //enumerate descriptor's keys
	str = str + 'Key '+i+' = '+typeIDToStringID(theDesc.getKey(i))+': '+theDesc.getType(theDesc.getKey(i))+'\n'+getValues (theDesc, i)+'\n';
	};
alert("desc\n\n"+str);
};
////// check //////
function getValues (theDesc, theNumber) {
switch (theDesc.getType(theDesc.getKey(theNumber))) {
case DescValueType.ALIASTYPE:
return theDesc.getPath(theDesc.getKey(theNumber));
break;
case DescValueType.BOOLEANTYPE:
return theDesc.getBoolean(theDesc.getKey(theNumber));
break;
case DescValueType.CLASSTYPE:
return theDesc.getClass(theDesc.getKey(theNumber));
break;
case DescValueType.DOUBLETYPE:
return theDesc.getDouble(theDesc.getKey(theNumber));
break;
case DescValueType.ENUMERATEDTYPE:
return (typeIDToStringID(theDesc.getEnumerationValue(theDesc.getKey(theNumber)))+"_"+typeIDToStringID(theDesc.getEnumerationType(theDesc.getKey(theNumber))));
break;
case DescValueType.INTEGERTYPE:
return theDesc.getInteger(theDesc.getKey(theNumber));
break;
case DescValueType.LISTTYPE:
return theDesc.getList(theDesc.getKey(theNumber));
break;
case DescValueType.OBJECTTYPE:
return (theDesc.getObjectValue(theDesc.getKey(theNumber))+"_"+typeIDToStringID(theDesc.getObjectType(theDesc.getKey(theNumber))));
break;
case DescValueType.RAWTYPE:
return theDesc.getReference(theDesc.getData(theNumber));
break;
case DescValueType.REFERENCETYPE:
return theDesc.getReference(theDesc.getKey(theNumber));
break;
case DescValueType.STRINGTYPE:
return theDesc.getString(theDesc.getKey(theNumber));
break;
case DescValueType.UNITDOUBLE:
return (theDesc.getUnitDoubleValue(theDesc.getKey(theNumber))+"_"+typeIDToStringID(theDesc.getUnitDoubleType(theDesc.getKey(theNumber))));
break;
default: 
break;
};
};

 

Kukurykus
KukurykusCorrect answer
Legend
June 9, 2021

 

lyr.isBackgrounLayer = desc.getBoolean(stringIDToTypeID('background'))
lyr.positionLocked = desc.getObjectValue(stringIDToTypeID('layerLocking')).getBoolean(stringIDToTypeID('protectPosition'))
lyr.typename = ({'true': 'LayerSet', 'false': 'ArtLayer'})[!(typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection'))).split('Content').length-1)]