Skip to main content
Tom_01
Known Participant
February 15, 2018
Answered

Sort / Order Selected Layers (Alphabetically)?

  • February 15, 2018
  • 5 replies
  • 31085 views

Hi,

I'm looking for a script to order selected layers alphabetically. I'm familiar with  Adobe Photoshop Scripts | Trevor Morris Photographics​, but am looking for constraint to selection. I've tried using this script: get array of selected layers in photoshop via extendscript · GitHub in combination, however, I've hit a wall.

Thanks,

Tom

This topic has been closed for replies.
Correct answer r-bin

I reproduced the error ).

This should work

var idx_shift = 0; 

try { activeDocument.backgroundLayer } catch (e) { idx_shift = 1; } 

while (1) 

    { 

    var list = get_selected_layers(); 

 

    if (!list) { alert("No selected layers"); break; } 

 

    var list2 = new Array(); 

    for (var i in list) list2.push(list); 

 

    function cmp(a, b)  

        { 

        var x = expand_numbers(a[0]); 

        var y = expand_numbers(b[0]); 

 

        if (x > y) return -1; 

        if (x < y) return 1; 

        return 0; 

        } 

 

    list.sort(cmp); 

    var cont = false; 

 

    for (var i = 0; i < list.length; i++) 

        { 

        if (list2[1] != list[1])  

            { 

            set_layers_index(list2[1], list[1]); 

            cont = true; 

            break; 

            } 

        } 

 

    if (!cont) break; 

    } 

 

alert("Done!"); 

 

////////////////////////////////////////////////////////////////// 

function set_layers_index(cur_idx, new_idx) 

    { 

    try { 

        var d = new ActionDescriptor(); 

 

        var r1 = new ActionReference(); 

        r1.putIndex( charIDToTypeID( "Lyr " ), cur_idx); 

 

        var r2 = new ActionReference(); 

        r2.putIndex( charIDToTypeID( "Lyr " ), new_idx-idx_shift ); 

 

        d.putReference( charIDToTypeID( "null" ), r1 ); 

        d.putReference( charIDToTypeID( "T   " ), r2 ); 

 

        executeAction( charIDToTypeID( "move" ), d, DialogModes.NO ); 

        } 

    catch (e) { alert(e); throw(e); } 

    } 

 

////////////////////////////////////////////////////////////////// 

function get_selected_layers() 

    { 

    try { 

        var r = new ActionReference();     

        r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"));    

        r.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt")); 

 

        var list = executeActionGet(r).getList(stringIDToTypeID("targetLayers")); 

 

        var len = list.count; 

     

        var selected_layers = new Array(); 

     

        for (var i = 0; i < len; i++) 

            { 

            try  

                { 

                var idx = list.getReference(i).getIndex() + idx_shift; 

 

                var r = new ActionReference(); 

                r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("name"));    

                r.putIndex( charIDToTypeID( "Lyr " ), idx); 

 

                var ret = executeActionGet(r).getString(stringIDToTypeID("name")); 

 

                selected_layers.push([executeActionGet(r).getString(stringIDToTypeID("name")), idx]); 

                } 

 

            catch (e) { alert(e); return null; } 

            } 

     

        return selected_layers; 

        } 

 

    catch (e) { return null; } 

    } 

 

//////////////////////////////////////////////////////////////////////////////////////////// 

function expand_numbers(s, max_digit) 

    { 

    if (max_digit == undefined) max_digit = 10;     

 

    var digit_cnt; 

 

    s = s.toString(); 

     

    var len = s.length; 

 

    var s1 = ""; 

 

    for (var i = len-1; i >= 0; i--)  

        { 

        var c = s.charAt(i); 

 

        if (c >= "0" && c <="9") 

            { 

            if (digit_cnt == undefined)      

                digit_cnt = 1; 

            else                         

                ++digit_cnt; 

 

            s1 += c; 

            } 

        else if (digit_cnt != undefined)  

            { 

            if (digit_cnt < max_digit) for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0"; 

 

            s1 += c; 

            digit_cnt = undefined; 

            } 

        else 

            { 

            s1 += c; 

            } 

        } 

 

    if (digit_cnt != undefined && digit_cnt < max_digit) 

        for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0"; 

 

    len = s1.length; 

 

    var ret = ""; 

 

    for (var i = len-1; i >= 0; i--) ret += s1.charAt(i); 

 

    ret = ret.toUpperCase(); 

 

    return ret; 

    } 

5 replies

Stephen Marsh
Community Expert
Community Expert
June 28, 2024
Inspiring
July 9, 2022

Hi,

As I'm a bit of a newbie, it would be great if you could post what the script in the end looked like (I'm not entirely sure how you combined the two scripts you mentioned) 🙂

Best,
Christina

Participant
October 29, 2022

Same question as Chris201Chris above is asking,

 

Many Thanks to Members who take the time to respond to Complex Questions.

especially when it is difficult to put into words Apstract ideas.

 

My question ! ? :

I am quite good with Photoshop, but when it comes to Coding / Scripts,

i am completely in the dark, 

and a simple way of Sorting Text Layers Alphabetically is what i need.

nintenjo64
Participant
February 9, 2021

This dosnt work for me.. i simple her an error: 

https://www.dropbox.com/s/2rhkl0hmlo8wdpm/Screenshot%202021-02-09%20at%2009.56.23.png?dl=0

- Numerical value expected.

Line:75 

it seems to be erroring in the try-catch phase? Note that my document does not have a background layer.

Kukurykus
Legend
February 9, 2021

You mean the code of r-bin (that contains try..catch statement) or mine you updated of?

nintenjo64
Participant
February 10, 2021

Yes sorry, the answer posted by r-bin above was throwing the error.  I found an alternative script on Github that worked instead in the end. 

 

var layers = activeDocument.layers;
    var layersArray = [];
    var len = layers.length;
    


    // store all layers in an array
    for (var i = 0; i < len; i++) {
        layersArray.push(layers[i]);
    }

    // sort layer top to bottom
    layersArray.sort();

    for (i = 0; i < len; i++) {
        layersArray[i].move(layers[i], ElementPlacement.PLACEBEFORE);
    }

 

Kukurykus
Legend
February 26, 2018

Before you run script go to 'Layers' panel, select 'Panel Oprions' from dropdown menu (you open clicking icon in right upper corner of panel), make 'Add "copy" to copied Layers and Groups' box empty. Script will be working if that won't be done, but all layer(Set)s get 'copy' word in their names. It is possible to remove it by script, but I did not do it as because of Photoshop bug there is need to select each single layer before renaming what increases time of performance. If you want script worked extremaly fast, press 'tab' key to toggle off your panels (it's scriptable but I let user decide of it). Script works for background and all kind of layers (those nasted in all levels groups as well). If any group will be selected before running script it is going to be unselected. Sorting is based on modified order of ASCII characters, so generally it is the same for digits and non letter characters. Difference is that order for letters is like: AaBbCc(...)Zz. Script distinguishes letters case and numbers in names - not as single digits but row of them - so there will be for ex. this order applied: 0, 1, 2, 3, 10, 99, 100 and so on. I didn't sort for any possible case there can happen but probably noone uses so complex layers names it ever was needed to cover unusual namings. It works also for layers having same content and length, while for example 'A' named layer will be sorted before 'a' named layer. I did not play with (disabled) linked layers, however those selected keep their links to each other while lose to those they were unselected and disabled ones gets enabled. These properties are possible to retrieve but as far there is no need to do it I didn't spend time for it. Visibility, effects and transparency stay untouched. It took 7,5 second with toggled off panels for 299 layer with background, so it gives 1 second for 40 layers! If you get some errors let me know so I'll make fixes.

gT = new Date().getTime(), $.level = 0; function sTT(v) {return stringIDToTypeID(v)}

function arr(v) {

     (ref1 = new ActionReference()).putProperty(sTT('property'), tL = sTT('targetLayers'))

     ref1.putEnumerated(sTT('document'), sTT('ordinal'), sTT('targetEnum'))

     if ((dsc1 = executeActionGet(ref1)).hasKey(tL)) {for(lst = dsc1.getList(tL), i = 0; i < lst.count;) {

          (ref2 = new ActionReference()).putIndex(sTT('layer'), lst.getReference(i++).getIndex() + bG), s = 'Start'

          if (typeIDToStringID((dsc = executeActionGet(ref2)).getEnumerationValue(sTT(lS = 'layerSection'))) == lS + s)

               {ref2.putIdentifier(sTT('layer'), dsc.getInteger(sTT('layerID'))), dsc1.putReference(sTT('null'), ref2)

               dsc1.putEnumerated(sTT(sM = 'selectionModifier'), sTT(sM + 'Type'), sTT('removeFromSelection'))

               dsc1.putBoolean(sTT('makeVisible'), false), executeAction(sTT('select'), dsc1, DialogModes.NO)}

          else v.unshift([dsc.getString(sTT('name')), dsc.getInteger(sTT('layerID'))])}

     }

     return v

}

(ref = new ActionReference()).putIdentifier(sTT('layer'), 1)

try{bG = !(dsc = executeActionGet(ref)).getBoolean

(sTT('background'))} catch (err) {bG = 1}

if ((sL = arr([])).length > 1) {

     (srt = Array().slice.call(sL)).sort(function(v1, v2) {

          function l(v) {return v.length}; if ((v1 = v1[0]) != v2 = v2[0]) {

               for(g = 0; g < l(v1); g++) {

                    if ((v1g = v1) != v2g = v2) {

                         function dig(v) {return !isNaN(v)}

                         if (dig(v1g) && dig(v2g)) {

                              function slc(v) {

                                   return +String(v).slice(g).match(/\d+/)

                              }

                              return slc(v1) - slc(v2)

                         }

                         function cCA(v) {

                              return v.charCodeAt() -

                              (/[a-z]/.test(v) ? 31.5 : 0)

                         }

                         if (v1g && v2g) return cCA(v1g) - cCA(v2g)

                    }

                    if (!v1g || !v2g) return l(v1) - l(v2)

               }

          }

     });

     (ref1 = new ActionReference()).putEnumerated(sTT('layer'), sTT('ordinal'),

     sTT('targetEnum')); (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

     dsc1.putInteger(sTT('version'), 5), executeAction(sTT('duplicate'), dsc1, DialogModes.NO);

     dL = arr([]);

     (ref1 = new ActionReference()).putClass(sTT('layerSection'));

     (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

     (ref2 = new ActionReference()).putEnumerated(sTT('layer'),

     sTT('ordinal'), sTT('targetEnum')), dsc1.putReference(sTT

     ('from'), ref2), executeAction(sTT('make'), dsc1, DialogModes.NO)

     grp = executeActionGet(ref2).getInteger(sTT('layerID' ))

     function del(v1, v2) {

          eval("(ref1 = new ActionReference()).put" + v1 + "(sTT('layer'), v2)");

          (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1)

          executeAction(sTT('delete'), dsc1, DialogModes.NO)

     }

     for(i = 0; i < sL.length; i++) {

          for(j = 0; j < srt.length; j++) {

               if (sL[1] == srt[1]) {

                    (ref1 = new ActionReference()).putIdentifier(sTT('layer'), dL.shift()[1]);

                    (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

                    (ref1 = new ActionReference()).putIdentifier(sTT('layer'), sL[1])

                    t = executeActionGet(ref1).getInteger(sTT('itemIndex'));

                    (ref2 = new ActionReference()).putIndex(sTT('layer'), t)

                    dsc1.putReference(sTT('to'), ref2), executeAction

                    (sTT('move'), dsc1, DialogModes.NO);

                    del('Index', t - (bG ? 0 : 1))

                    if (!bG && t == 1) {

                         (ref1 = new ActionReference()).putClass(sTT('backgroundLayer'));

                         (dsc1 = new ActionDescriptor()).putReference(sTT('null'), ref1);

                         (ref2 = new ActionReference()).putIndex(sTT('layer'), t);

                         dsc1.putReference(sTT('using'), ref2), executeAction

                         (sTT('make'), dsc1, DialogModes.NO)

                    }

                    break

               }

          }

     }

     del('Identifier', grp), new Date().getTime() - gT

}

Legend
February 15, 2018

Try this code )

while (1)

    {

    var list = get_selected_layers();

    if (!list) { alert("No selected layers"); break; }

    var list2 = new Array();

    for (var i in list) list2.push(list);

    function cmp(a, b)

        {

        var x = expand_numbers(a[0]);

        var y = expand_numbers(b[0]);

        if (x > y) return -1;

        if (x < y) return 1;

        return 0;

        }

    list.sort(cmp);

    var cont = false;

    for (var i = 0; i < list.length; i++)

        {

        if (list2[1] != list[1])

            {

            set_layers_index(list2[1], list[1]);

            cont = true;

            break;

            }

        }

    if (!cont) break;

    }

alert("Done!");

//////////////////////////////////////////////////////////////////

function set_layers_index(cur_idx, new_idx)

    {

    try {

        var d = new ActionDescriptor();

        var r1 = new ActionReference();

        r1.putIndex( charIDToTypeID( "Lyr " ), cur_idx);

        var r2 = new ActionReference();

        r2.putIndex( charIDToTypeID( "Lyr " ), new_idx );

        d.putReference( charIDToTypeID( "null" ), r1 );

        d.putReference( charIDToTypeID( "T   " ), r2 );

        executeAction( charIDToTypeID( "move" ), d, DialogModes.NO );

        }

    catch (e) { alert(e);  }

    }

//////////////////////////////////////////////////////////////////

function get_selected_layers()

    {

    try {

        var r = new ActionReference();   

        r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"));  

        r.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));

        var list = executeActionGet(r).getList(stringIDToTypeID("targetLayers"));

        var n = 0;

        try { activeDocument.backgroundLayer } catch (e) { n = 1; }

        var len = list.count;

   

        var selected_layers = new Array();

   

        for (var i = 0; i < len; i++)

            {

            try

                {

                var idx = list.getReference(i).getIndex() + n;

                var r = new ActionReference();

                r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("name"));  

                r.putIndex( charIDToTypeID( "Lyr " ), idx);

                var ret = executeActionGet(r).getString(stringIDToTypeID("name"));

                selected_layers.push([executeActionGet(r).getString(stringIDToTypeID("name")), idx]);

                }

            catch (e) { alert(e); return null; }

            }

   

        return selected_layers;

        }

    catch (e) { return null; }

    }

////////////////////////////////////////////////////////////////////////////////////////////

function expand_numbers(s, max_digit)

    {

    if (max_digit == undefined) max_digit = 10;   

    var digit_cnt;

    s = s.toString();

   

    var len = s.length;

    var s1 = "";

    for (var i = len-1; i >= 0; i--)

        {

        var c = s.charAt(i);

        if (c >= "0" && c <="9")

            {

            if (digit_cnt == undefined)    

                digit_cnt = 1;

            else                       

                ++digit_cnt;

            s1 += c;

            }

        else if (digit_cnt != undefined)

            {

            if (digit_cnt < max_digit) for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0";

            s1 += c;

            digit_cnt = undefined;

            }

        else

            {

            s1 += c;

            }

        }

    if (digit_cnt != undefined && digit_cnt < max_digit)

        for (var n = 0; n < max_digit-digit_cnt; n++) s1 += "0";

    len = s1.length;

    var ret = "";

    for (var i = len-1; i >= 0; i--) ret += s1.charAt(i);

    ret = ret.toUpperCase();

    return ret;

    }

Tom_01
Tom_01Author
Known Participant
February 15, 2018

Thanks!

I ran the script and all but one of the selected layers got grouped into the group above them. I undid that and placed the group below all of the selected layers and ran again. Got a script alert: Error: General Photoshop error occurred. This functionality may not be available in this version of Photoshop.

- The command "Move" is not currently available.

I click OK or the x button and a new script alert appears (saying the same thing). I cannot exit Script Alerts...

Legend
February 15, 2018

Please post the screenshot of your layers structures and their selection. What version of Photoshop are you running?

upd. change

catch (e) { alert(e);  }

to

catch (e) { alert(e); throw(e);  }