0

Unlike this question, is there a way to return an array of currently selected layers, without having to loop over all the layers and therefore removing/readjusting that selection?

function get_selected_layers()
{
  var layers = app.activeDocument.activeLayer;
 // only works with *last* selected layer
 // not *all* selected layers
}

var thelayers = get_selected_layers;
alert(thelayers);
Ghoul Fool
  • 6,249
  • 10
  • 67
  • 125

1 Answers1

1

Sort of but not really. There's no native way of getting an array of selected artLayer objects. But there's a Action Manager way of getting descriptors of selected layers — and from descriptors you can get everything you want. Here's a snippet that returns an array of selected layers names, indexes and ids — using different getters on layer descriptor (desc) it's possible to get everything else. As a bonus a function to select artLayers by IDs if you want to get artLayer DOM objects. And yes, this works on groups and artboards.

var layers = getSelectedLayersInfo();

// if we _really_ want to get artLayers we can select them one by one with IDs
for (var i = 0; i < layers.length; i++) {
  selectByID(layers[i].id);
  alert(activeDocument.activeLayer.name);
}

// and reselecting everything back
for (var i = 0; i < layers.length; i++) {
  selectByID(layers[i].id, true);
}


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  "));
    lyrs.push(lyr);
  }

  return lyrs;
}

function selectByID(id, add) {
    if (add == undefined) add = false;
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putIdentifier(charIDToTypeID('Lyr '), id);
    desc1.putReference(charIDToTypeID('null'), ref1);
    if (add) desc1.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
    executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
} // end of selectByID()
Sergey Kritskiy
  • 2,199
  • 2
  • 15
  • 20
  • This script doesn't work if there is only one layer selected (active). At least on Photoshop CS6. – Zax Jun 11 '21 at 05:57
  • @Zax did you also test it in CS2? – Sergey Kritskiy Jun 11 '21 at 07:06
  • No, sorry. I only have CS6. I dont' understand AM syntax but I think a try-catch should be added with specific AM code if there is only one layer selected. – Zax Jun 11 '21 at 08:21
  • Is it possible to adapt this to only return the top-level hierarchy of layer sets selected, even if nested layer sets are selected? Your code will return ALL the layer names, including those nested inside each selected layer set, but that's overkill for my application. – Patrick Hennessey Apr 23 '22 at 07:13
  • @PatrickHennessey sure. I'd check if a layer on top is a layer set, if yes — continue to check until it's not, meaning you've reached the top layer in hierarchy – Sergey Kritskiy Apr 24 '22 at 08:33