-
1. Re: python : get all selected layers
Paul Riggott Feb 27, 2013 1:40 AM (in response to Nicolas.k)Sorry I don't know python, but with JavaScript you can do this...
var sLayers = getSelectedLayersIdx(); var Names = new Array(); for (var a in sLayers){ Names.push(getLayerNameByIndex( Number(sLayers[a]) ) ); } alert(Names.join('\n')); function getLayerNameByIndex( idx ) { var ref = new ActionReference(); ref.putIndex( charIDToTypeID( "Lyr " ), idx ); return executeActionGet(ref).getString(charIDToTypeID( "Nm " )); }; function getSelectedLayersIdx(){ var selectedLayers = new Array; var ref = new ActionReference(); ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); var desc = executeActionGet(ref); if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){ desc = desc.getList( stringIDToTypeID( 'targetLayers' )); var c = desc.count var selectedLayers = new Array(); for(var i=0;i<c;i++){ try{ activeDocument.backgroundLayer; selectedLayers.push( desc.getReference( i ).getIndex() ); }catch(e){ selectedLayers.push( desc.getReference( i ).getIndex()+1 ); } } }else{ var ref = new ActionReference(); ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" )); ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); try{ activeDocument.backgroundLayer; selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))-1); }catch(e){ selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))); } var vis = app.activeDocument.activeLayer.visible; if(vis == true) app.activeDocument.activeLayer.visible = false; var desc9 = new ActionDescriptor(); var list9 = new ActionList(); var ref9 = new ActionReference(); ref9.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); list9.putReference( ref9 ); desc9.putList( charIDToTypeID('null'), list9 ); executeAction( charIDToTypeID('Shw '), desc9, DialogModes.NO ); if(app.activeDocument.activeLayer.visible == false) selectedLayers.shift(); app.activeDocument.activeLayer.visible = vis; } return selectedLayers; }; -
2. Re: python : get all selected layers
Nicolas.k Feb 27, 2013 1:49 AM (in response to Paul Riggott)Thanks Paul, I've seen this function looking for my problem but can't manage to transform it to python.
Really strange there isn't a simple way to get this, this is really something basic and usefull ...
-
3. Re: python : get all selected layers
Paul Riggott Feb 27, 2013 1:55 AM (in response to Nicolas.k)Maybe you could convert this function?
function createLayerset() { var desc82 = new ActionDescriptor(); var ref24 = new ActionReference(); ref24.putClass( stringIDToTypeID('layerSection') ); desc82.putReference( charIDToTypeID('null'), ref24 ); var ref25 = new ActionReference(); ref25.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); desc82.putReference( charIDToTypeID('From'), ref25 ); executeAction( charIDToTypeID('Mk '), desc82, DialogModes.NO ); };All it does is to create a layerset from the selected files, once you have a layerset you can iterate, get your information then undo the layerset creation?
-
4. Re: python : get all selected layers
Nicolas.k Feb 27, 2013 3:40 AM (in response to Paul Riggott)Thanks Again Paul,
The problem is that I dunno what to do in python with these :
ActionDescriptor()
ActionReference()
stringIDToTypeID
This works :
psActRef = Dispatch("Photoshop.ActionReference")
psActDesc = Dispatch("Photoshop.ActionDescriptor")
But all this stringIDToTypeID is nomanlands for me lol. I don't get
stringIDToTypeID stuff in ActionReference, maybe I should subclass it but dunno how to and what to do.
-
5. Re: python : get all selected layers
Paul Riggott Feb 27, 2013 3:50 AM (in response to Nicolas.k)There seems to be an example using Action Manager code in python here...
http://techarttiki.blogspot.co.uk/2008/08/photoshop-scripting-with-python.html
-
6. Re: python : get all selected layers
Paul Riggott Feb 27, 2013 4:16 AM (in response to Paul Riggott)There is another example using scriptlistener output here that might help...
http://peterhanshawart.blogspot.com.au/2012/05/python-and-photoshop-script-listener.html
-
7. Re: python : get all selected layers
Nicolas.k Feb 27, 2013 4:53 AM (in response to Paul Riggott)Ah, second link what helpfull indeed !! Got this script to works, so I can now decrypt and understand all this. I also downloaded scriptlistener so I may finnally get some stuff working like I want.
Many thanks Paul, really
Anyway, would be nice to see more complete stuff implemented in photoshop com ;-)
-
8. Re: python : get all selected layers
Nicolas.k Feb 27, 2013 7:37 AM (in response to Nicolas.k)And finnally, python code working like a charm !!
It is transcription into python from your first message, tested, working (win7 x64 cs6) :
from win32com.client import Dispatch
psApp = Dispatch("Photoshop.Application")
def _getLayerNameByIndex(idx=0):
ref = Dispatch("Photoshop.ActionReference")
ref.PutIndex(psApp.CharIDToTypeID("Lyr "), idx)
try:
return psApp.ExecuteActionGet(ref).GetString(psApp.CharIDToTypeID("Nm "))
except:
return False
#
def _getSelectedLayers():
selectedLayers = []
doc = psApp.Application.ActiveDocument
dialogMode = 3
ref = Dispatch("Photoshop.ActionReference")
ref.PutEnumerated(psApp.CharIDToTypeID("Dcmn"), psApp.CharIDToTypeID("Ordn"), psApp.CharIDToTypeID("Trgt"))
desc = psApp.ExecuteActionGet(ref)
if desc.HasKey(psApp.StringIDToTypeID('targetLayers')):
desc = desc.GetList(psApp.StringIDToTypeID('targetLayers'))
c = len(desc)
selectedLayers = []
for i in range(0, c):
try:
selectedLayers.append(desc.GetReference(i).GetIndex()+1)
except:
selectedLayers.append(desc.GetReference(i).GetIndex())
else:
ref = Dispatch("Photoshop.ActionReference")
ref.PutProperty(psApp.CharIDToTypeID("Prpr"), psApp.CharIDToTypeID( "ItmI" ))
ref.PutEnumerated(psApp.CharIDToTypeID("Lyr "), psApp.CharIDToTypeID("Ordn"), psApp.CharIDToTypeID("Trgt"))
try:
doc.ActiveLayer.IsBackgroundLayer = False
selectedLayers.append(psApp.ExecuteActionGet(ref).GetInteger(psApp.CharIDToTypeID("ItmI") ))
except:
doc.ActiveLayer.IsBackgroundLayer = False
selectedLayers.append(psApp.ExecuteActionGet(ref).GetInteger(psApp.CharIDToTypeID("ItmI") )+1)
vis = doc.ActiveLayer.Visible
if vis == True:
doc.ActiveLayer.Visible = False
desc9 = Dispatch("Photoshop.ActionDescriptor")
list9 = Dispatch("Photoshop.ActionList")
ref9 = Dispatch("Photoshop.ActionReference")
ref9.PutEnumerated(psApp.CharIDToTypeID("Lyr "), psApp.CharIDToTypeID("Ordn"), psApp.CharIDToTypeID("Trgt"))
list9.PutReference(ref9)
desc9.PutList(psApp.CharIDToTypeID("null"), list9)
psApp.ExecuteAction(psApp.CharIDToTypeID("Shw "), desc9, dialogMode)
if doc.ActiveLayer.Visible == False:
selectedLayers = selectedLayers.pop(0)
doc.ActiveLayer.Visible = vis
return selectedLayers[::-1]
#
for select in _getSelectedLayers(): print _getLayerNameByIndex(select)
-
9. Re: python : get all selected layers
Paul Riggott Feb 27, 2013 8:02 AM (in response to Nicolas.k)Fantastic, I am sure this will be a great help to other Python users!
-
10. Re: python : get all selected layers
Nicolas.k Feb 28, 2013 1:55 AM (in response to Paul Riggott)Ok, I have another problem, coming from above function.
When using _getLayerNameByIndex(idx), the index contains all layer, layerset and even end of group, from bottom to top.
But in python COM, when I use doc.Layers[idx].name this index start from top and contains only root layers (not artlayers in layerset and so on).
I should get it by doc.Layers[x].Layers[y].name
Indeed, COM and ActionReference doesn't refer to same index (last is an ordinnal index I guess).
So for example, I can get all selected layers, stock them in an array, but them I have no way to access them back in COM.
So in COM, is there a way to change doc.Layers[x].Layers[y].name into something like doc.OrdLayers[idx].name ? Something that it can take same index as ActionReference ?
My problem will be doing some stuff on all selected layers. I get an array of them in ordinnal index, but then I can't use this index to do stuff on them.
Something I would need, I guess, is getting layer object (COMObject) with some ActionReference so I can refer to same object layer.
example :
def _isLayer(item):
if item.typename == "ArtLayer":
return True
#
def _isGroup(item):
if item.typename == "LayerSet":
return True
#
selectedLayers = _getSelectedLayers()
for select in selectedLayers:
if ._isLayer(doc.Layers[select]):
print "Layer: ", select, _getLayerNameByIndex(select)
else:
print "Group: ", select, _getLayerNameByIndex(select)
This give totally wrong result, as _getSelectedLayers() and _getLayerNameByIndex() works from ordinnal index, and _isLayer() works on root limited index.
Hope you understand what I mean :/
So I'm trying to get some functions with ActionReference but for example, why this doesn't work ? It is the same as _getLayerNameByIndex(), just wanting the 'type' of layer.
def _getType(idx=0):
ref = Dispatch("Photoshop.ActionReference")
ref.PutIndex(psApp.CharIDToTypeID("Lyr "), idx)
try:
return psApp.ExecuteActionGet(ref).GetString(psApp.CharIDToTypeID("Type"))
except:
return False
-
11. Re: python : get all selected layers
Nicolas.k Feb 28, 2013 4:08 AM (in response to Nicolas.k)Ok, finnally ...
Some fact (with my actul knownledge) :
COM interface only access layers by a root based index.
ExecuteAction can return full bottom based index
But these index, which are not the same (first boom!), change when you move or add or delete layers.
So, some methodologie:
ExecuteAction can return IDs of layers, which are uniques, whatever you do (adding, deleting, moving layers). For the current doc of course.
So, I will transform all my functions to return IDs
Then, I will have to do some new function like _getSelectedID, _moveByID, etc
Finnally, I will be able in python to get select a layer by ID, then do some COM stuff on it !
Just in case some python scripter are there, to let you know.
Please share any feedback !
I guess the COM interface hasn't been touched by Adobe since Photoshop allow sub layersets and so on. We really would need a COM way of doing stuff on a layer by referecing it by its ID, and not only by its root index, which is a total code nosense !!
-
12. Re: python : get all selected layers
Paul Riggott Feb 28, 2013 5:11 AM (in response to Nicolas.k)Yes it is not easy working with layers, the Layer ID is unique and stays with the layer if it moved, the index is just the position of the layer.
You might be able to convert some of these functions that should help....
//returns layer ID from active layer function getLayerID(){ var ref = new ActionReference(); ref.putEnumerated( charIDToTypeID('Lyr '),charIDToTypeID('Ordn'),charIDToTypeID('Trgt') ); var desc = executeActionGet(ref); return desc.getInteger(stringIDToTypeID( 'layerID' )); }; //get layer ID from supplied Index function getLayerIDfromIDX(idx) { var ref = new ActionReference(); ref.putIndex( charIDToTypeID( "Lyr " ), idx ); return executeActionGet(ref).getInteger(stringIDToTypeID( "layerID" )); }; //Select layer using it's Index function selectLayerByIndex(index,add){ add = (add == undefined) ? add = false : add; var ref = new ActionReference(); ref.putIndex(charIDToTypeID("Lyr "), index); var desc = new ActionDescriptor(); desc.putReference(charIDToTypeID("null"), ref ); if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); desc.putBoolean( charIDToTypeID( "MkVs" ), false ); try{ executeAction(charIDToTypeID("slct"), desc, DialogModes.NO ); }catch(e){} }; //Select layer using it's ID function selectLayerById(ID, add) { add = (add == undefined) ? add = false : add; var ref = new ActionReference(); ref.putIdentifier(charIDToTypeID('Lyr '), ID); var desc = new ActionDescriptor(); desc.putReference(charIDToTypeID('null'), ref); if (add) { desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection')); } desc.putBoolean(charIDToTypeID('MkVs'), false); executeAction(charIDToTypeID('slct'), desc, DialogModes.NO); }; //No layers selected function deselectLayers() { var desc01 = new ActionDescriptor(); var ref01 = new ActionReference(); ref01.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); desc01.putReference( charIDToTypeID('null'), ref01 ); executeAction( stringIDToTypeID('selectNoLayers'), desc01, DialogModes.NO ); }; -
13. Re: python : get all selected layers
Nicolas.k Feb 28, 2013 7:12 AM (in response to Paul Riggott)Many thanks Paul, once more !
I've transformed these functions to python and all works fine.
One that I need now is getSelectedLayers returning IDs. I get it working with converting index list to ID list with the function getLayerIDbyIndex but it's not clean, I would prefer getting IDs directly.
I've change this :
selectedLayers.append(desc.GetReference(i).GetIndex())
to:
selectedLayers.append(desc.GetReference(i).GetInteger(psApp.StringIDToTypeID("layerID")))
but it doesn't work ... Any idea ? Seems you have an astonishing bank of code snippet in your case lol !
Once all done, I will post all python code here, and finnally begin real work with all this :-)
-
14. Re: python : get all selected layers
Paul Riggott Feb 28, 2013 7:45 AM (in response to Nicolas.k)There is no clean way of doing this as the numbers come from the document descripter.
The only thing you could do is call a function to get the ID ....
alert(getSelectedLayersIdx().join('\n')); function getSelectedLayersIdx(){ var selectedLayers = new Array; var ref = new ActionReference(); ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); var desc = executeActionGet(ref); if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){ desc = desc.getList( stringIDToTypeID( 'targetLayers' )); var c = desc.count var selectedLayers = new Array(); for(var i=0;i<c;i++){ try{ activeDocument.backgroundLayer; selectedLayers.push(getLayerIDfromIDX( desc.getReference( i ).getIndex() )); }catch(e){ selectedLayers.push(getLayerIDfromIDX( desc.getReference( i ).getIndex()+1 )); } } }else{ var ref = new ActionReference(); ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" )); ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); try{ activeDocument.backgroundLayer; selectedLayers.push(getLayerIDfromIDX( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))-1)); }catch(e){ selectedLayers.push( getLayerIDfromIDX(executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" )))); } var vis = app.activeDocument.activeLayer.visible; if(vis == true) app.activeDocument.activeLayer.visible = false; var desc9 = new ActionDescriptor(); var list9 = new ActionList(); var ref9 = new ActionReference(); ref9.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') ); list9.putReference( ref9 ); desc9.putList( charIDToTypeID('null'), list9 ); executeAction( charIDToTypeID('Shw '), desc9, DialogModes.NO ); if(app.activeDocument.activeLayer.visible == false) selectedLayers.shift(); app.activeDocument.activeLayer.visible = vis; } return selectedLayers; }; function getLayerIDfromIDX(idx) { var ref = new ActionReference(); ref.putIndex( charIDToTypeID( "Lyr " ), idx ); return executeActionGet(ref).getInteger(stringIDToTypeID( "layerID" )); }; -
15. Re: python : get all selected layers
Nicolas.k Feb 28, 2013 7:58 AM (in response to Paul Riggott)Yes it's exactly what I do actually. Not very clean, but fast anyway so yes, I will keep it like that.
I'm testing all this and will post code soon.

