Copy link to clipboard
Copied
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.
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)]
Copy link to clipboard
Copied
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)]
Copy link to clipboard
Copied
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;
};
};
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
Oh, I'm sorry, copy - paste failed. The mistake is corrected in my edited code 😉
Copy link to clipboard
Copied
See if you can see what you need from this script
layerInfo(activeDocument.activeLayer);
function layerInfo(layer) {
try {
if (layer.kind==LayerKind.TEXT) {
// Display some TextItem data
var txtInfo = "";
txtInfo = txtInfo + "\nLayerTextItemContents='" + layer.textItem.contents + "'";
txtInfo = txtInfo + "\nLayerTextItemFont='" + layer.textItem.font + "'";
txtInfo = txtInfo + "\nLayerTextItemSize='" + layer.textItem.size + "'";
txtInfo = txtInfo + "\nLayerTextItemColor'" + layer.textItem.color.rgb.red + "," + layer.textItem.color.rgb.green + "," + layer.textItem.color.rgb.blue + "'";
txtInfo = txtInfo + "\nLayerTextItemDirection='" + layer.textItem.direction + "'";
txtInfo = txtInfo + "\nLayerTextItemAntiAliasMethod='" + layer.textItem.antiAliasMethod + "'";
txtInfo = txtInfo + "\nLayerTextItemPosition='" +layer.textItem.position + "'";
txtInfo = txtInfo + "\nLayerTextItemKind='" + layer.textItem.kind + "'";
if (layer.textItem.kind==TextType.PARAGRAPHTEXT) {
txtInfo = txtInfo + "\nLayerTextItemWidth='" + layer.textItem.width + "'";
txtInfo = txtInfo + "\nLayerTextItemHeight='" + layer.textItem.height + "'";
txtInfo = txtInfo + "\nLayerTextItemTextComposer ='" + layer.textItem.textComposer + "'";
}
}
else {txtInfo="";}
}
catch(e) {
txtInfo= txtInfo + "\ntextItem " + e + ': on line ' + e.line
layer.textItem.contents = layer.textItem.contents;
layerInfo(layer);
}
// alert(txtInfo);
alert("typename='" + layer.typename + "'"
+ "\nvisible='" + layer.visible + "'"
+ "\nlayerName='" + layer.name + "'"
+ "\nisBackgroundLayer = " + layer.isBackgroundLayer
+ "\nlayerID='" + layer.id + "'"
+ "\nitemIndex='" + layer.itemIndex + "'"
+ "\nlayerKind='" + layer.kind + "'"
+ "\nallLocked='" + layer.allLocked + "'"
+ "\npixelsLocked = " + layer.pixelsLocked
+ "\npositionLocked = " + layer.positionLocked
+ "\ntransparentPixelsLocked = " + layer.transparentPixelsLocked
+ "\nblendMode='" + layer.blendMode + "'"
+ "\nopacity='" + layer.opacity + "'"
+ "\nfillOpacity = " + layer.fillOpacity
+ "\nbounds='" + layer.bounds + "'"
+ "\nboundsNoEffects='" + layer.boundsNoEffects + "'"
+ "\nlinkedLayers='" + layer.linkedLayers + "'"
+ "\nparent='" + layer.parent + "'"
+ "\ngrouped = " + layer.grouped
+ "\nlayerMaskDensity = " + layer.layerMaskDensity
+ "\nlayerMaskFeather = " + layer.layerMaskFeather
+ "\nvectorMaskDensity = " + layer.vectorMaskDensity
+ "\nvectorMaskFeather = " + layer.vectorMaskFeather
+ "\nxmpMetadata='" + obj_to_str(layer.xmpMetadata) + "'"
+ txtInfo
);
}
//Thanks to r-bin
function obj_to_str(obj){var str = ""; for (var p in obj) if(obj.hasOwnProperty(p))try{str+=p+"::"+obj[p]+"\n";}catch(e){};return str;}
/*
TextItem Properties * indicates in the Alert
//txtInfo = txtInfo + "\nLayerTextItemLanguage='" + layer.textItem.language + "'"
//txtInfo = txtInfo + "\nLayerTextItemFauxBold='" + layer.textItem.fauxBold + "'"
//txtInfo = txtInfo + "\nLayerTextItemFauxItalic='" + layer.textItem.fauxItalic + "'"
//txtInfo = txtInfo + "\nLayerTextItemUnderline='" + layer.textItem.underline + "'"
//txtInfo = txtInfo + "\nLayerTextItemCapitalization='" + layer.textItem.capitalization + "'"
*antiAliasMethod
autoKerning
autoLeadingAmount
baselineShift
capitalization
*color
*contents
desiredGlyphScaling
desiredLetterScaling
desiredWordScaling
*direction
fauxBold
fauxItalic
firstLineIndent
*font
hangingPunctuation
*height
hyphenateAfterFirst
hyphenateBeforeLast
hyphenateCapitalWords
hyphenateWordsLongerThan
hyphenation
hyphenationZone
hyphenLimit
justification
*kind
language
leading
leftIndent
ligatures
maximumGlyphScaling
maximumLetterScaling
maximumWordScaling
minimumGlyphScaling
minimumLetterScaling
minimumWordScaling
noBreak
oldStyle
*parent
*position
rightIndent
*size
spaceAfter
spaceBefore
strikeThru
*textComposer
tracking
typename
underline
useAutoLeading
verticalScale
warpBend
warpDirection
warpHorizontalDistortion
warpStyle
warpVerticalDistortion
*width
*/
m
Copy link to clipboard
Copied
»- Key 13 is "layerLocking: DescValueType.OBJECTTYPE
[ActionDescriptor]_layerLocking", even the layer is locked or not«
Yeah, one needs to »go deeper« when one wants to get the values from inside ObjectType – which @Kukurykus ’ line of code
dsc.getObjectValue(sTT('layerLocking')).getBoolean(sTT('protectPosition'))
illustrates.
Copy link to clipboard
Copied
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!
Copy link to clipboard
Copied
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 😞
Copy link to clipboard
Copied
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 = ???????
Copy link to clipboard
Copied
Thnk you Kukurykus! 🙂
I didn't see you update, sorry.
On strange thing: it tells me the layer "lockedLayer" is unlock (see screen capture):
Copy link to clipboard
Copied
You used 'movable' word that is not the same as locking everything. Change your line to:
lyr.allLocked = desc.getObjectValue(stringIDToTypeID('layerLocking')).getBoolean(stringIDToTypeID('protectAll'))
Copy link to clipboard
Copied
Great!
Sorry to confuse you with "movable" (didn't know there was a difference).
Thanks all for your time and efforts 🙂
Copy link to clipboard
Copied
@Kukurykus In order to know if a layer is inside a group or not, I tried to get the parent's name from the desc, using "PrNm" without success (I checked keyParentName exists in Photoshop CS6 from CS6 SDK). Any idea of how to retrieve this information?
I guess I should look "deeper" in one of the desc item, as c.pfaffenbichler said, but I don't know how.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Getting layer's parent using ActionManager
By @Kukurykus
function layer_parent_id(id)
{
try {
var ret = get_prop_value("layer", id, "parentLayerID");
if (ret != undefined) return ret;
var r = new ActionReference();
r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("count"));
r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
var count = executeActionGet(r).getInteger(stringIDToTypeID("count"))+1;
var idx = get_prop_value("layer", id, "itemIndex")+1;
var has_bg = get_prop_value("document", null, "hasBackgroundLayer");
if (has_bg == undefined) try { activeDocument.backgroundLayer; has_bg = true; } catch (e) { has_bg = false; }
if (has_bg) { --idx; --count; }
var sect_cnt = 0;
while (idx < count)
{
var r = new ActionReference();
r.putIndex(stringIDToTypeID("layer"), idx);
var d = executeActionGet(r);
var sect = d.getEnumerationValue(stringIDToTypeID("layerSection"));
switch (sect)
{
case stringIDToTypeID("layerSectionStart"):
--sect_cnt;
if (sect_cnt == -1) return d.getInteger(stringIDToTypeID("layerID"));
break;
case stringIDToTypeID("layerSectionEnd"):
++sect_cnt;
break;
}
if (sect_cnt <= -1) return -1;
++idx;
}
return -1;
}
catch (e) { throw(e); }
}
/////////////////////////////////////////////////////////////////////////////////
function get_prop_value(class_key, id, prop_key)
{
try
{
if (typeof(class_key) == "string") class_key = stringIDToTypeID(class_key);
if (typeof(prop_key) == "string") prop_key = stringIDToTypeID(prop_key);
var r = new ActionReference();
if (prop_key != undefined) r.putProperty(stringIDToTypeID("property"), prop_key);
if (id == undefined || id == null) r.putEnumerated(class_key, stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
else if (typeof(id) == "string") r.putName(class_key, id);
else r.putIdentifier(class_key, id);
var desc;
if (prop_key == undefined)
{
try { return executeActionGet(r); } catch (e) { return undefined; }
}
try { desc = executeActionGet(r); } catch (e) { return undefined; }
if (!desc.hasKey(prop_key)) return undefined;
var ret = get_value(desc, prop_key);
for (var i = 3; i < arguments.length; i++)
if (arguments[i] != undefined) ret = get_value(ret, arguments[i]);
return ret;
function get_type(obj, key)
{
try
{
if (obj == undefined) return undefined;
if (typeof(key) == "string") key = stringIDToTypeID(key);
switch (obj.typename)
{
case "ActionDescriptor":
case "ActionList" : return obj.getType(key);
case "ActionReference" : return obj.getForm();
}
}
catch (e) { throw(e); }
}
function get_value(obj, key)
{
try
{
if (obj == undefined) return undefined;
if (typeof(key) == "string") key = stringIDToTypeID(key);
switch (obj.typename)
{
case "ActionDescriptor":
case "ActionList" : return get_desc_value(obj, key);
case "ActionReference" : return get_ref_value(obj);
}
}
catch (e) { throw(e); }
}
function get_desc_value(d, key)
{
try
{
if (d == undefined) return undefined;
if (typeof(key) == "string") key = stringIDToTypeID(key);
var val;
if (d instanceof ActionDescriptor && !d.hasKey(key)) return undefined;
else if (d instanceof ActionList && key >= d.count) return undefined;
var type = d.getType(key);
switch (type)
{
case DescValueType.ALIASTYPE: val = d.getPath(key); break;
case DescValueType.BOOLEANTYPE: val = d.getBoolean(key); break;
case DescValueType.CLASSTYPE: val = d.getClass(key); break;
case DescValueType.DOUBLETYPE: val = d.getDouble(key); break;
case DescValueType.INTEGERTYPE: val = d.getInteger(key); break;
case DescValueType.LISTTYPE: val = d.getList(key); break;
case DescValueType.RAWTYPE: val = d.getData(key); break;
case DescValueType.STRINGTYPE: val = d.getString(key); break;
case DescValueType.LARGEINTEGERTYPE: val = d.getLargeInteger(key); break;
case DescValueType.REFERENCETYPE: val = d.getReference(key); break;
case DescValueType.OBJECTTYPE: val = d.getObjectValue(key); break;
case DescValueType.UNITDOUBLE: val = d.getUnitDoubleValue(key); break;
case DescValueType.ENUMERATEDTYPE: val = d.getEnumerationValue(key); break;
}
return val;
}
catch (e) { throw(e); }
}
function get_ref_value(r)
{
try
{
var val;
switch (r.getForm())
{
case ReferenceFormType.CLASSTYPE: val = r.getDesiredClass(); break;
case ReferenceFormType.IDENTIFIER: val = r.getIdentifier(); break;
case ReferenceFormType.INDEX: val = r.getIndex(); break;
case ReferenceFormType.NAME: val = r.getName(); break;
case ReferenceFormType.OFFSET: val = r.getOffset(); break;
case ReferenceFormType.ENUMERATED: val = r.getEnumeratedValue(); break;
case ReferenceFormType.PROPERTY: val = r.getProperty(); break;
}
return val;
}
catch (e) { throw(e); }
}
}
catch(e) { throw(e); }
}
Copy link to clipboard
Copied
That's right, I noticed it too. But both of them wanted to know if a layer is inside of group 🙂
Copy link to clipboard
Copied
REM:
"parentName" and "parentIndex" refer to Actions.
The "parentName" for an Action is the name of its ActionSet.
This has nothing to do with layers.
Copy link to clipboard
Copied
It's similar to getContainer: Listener trigger "play" argument actionSet is wrong value
Copy link to clipboard
Copied
Thank you. Didn't think it was so complicated!
Copy link to clipboard
Copied
No, it's quite easy:
function lS() {
return (s = typeIDToStringID(executeActionGet(ref)
.getEnumerationValue(sTT(ls = 'layerSection')))
.split(ls)[1].length - 7) + (!s ? 0 : 3)
}
sTT = stringIDToTypeID
bL = (lrs = activeDocument.layers)
[lrs.length - 1].isBackgroundLayer;
(ref = new ActionReference()).putEnumerated
(sTT('layer'), sTT('ordinal'), sTT('targetEnum'))
indx = (dsc = executeActionGet(ref)).getInteger(sTT('itemIndex')) - !!bL
lvl = lS() + 1; while(lvl && indx > 1) (ref = new ActionReference())
.putIndex(sTT('layer'), --indx), lvl += lS(); alert(!lvl)
Copy link to clipboard
Copied
It's right?
Copy link to clipboard
Copied
Later I reminded myself to include background layer. The code is corrected. Check it again 🙂
Copy link to clipboard
Copied
Copy link to clipboard
Copied
That's little oversight of undefined, as I forgot to use double exclamation mark before bL 😛