Skip to main content
Inspiring
August 12, 2021
Answered

.jsx script extremely slow

  • August 12, 2021
  • 6 replies
  • 5924 views

Hi,

I've tried to work a little with photoshop scripting, and I tried to make a thing that removes groups if it fits some criteria.

The problem I am facing is - it's VERY VERY slow. Let's say we have a file that contains 10 groups, each group contains 10 sub-groups, and each of these groups contains 10 layers.

 

I made a recursion that checks if the first child layer is a group, if it is a group, it moves in (recursion), if it's not, then skip. At the end, remove group. (This is simplified, but it is basically the thing).

 

From my previous programming experience, I'd say this should run under a second without any issues. But what I've found out is, that it takes several seconds to remove one group.

 

This is just straight up unacceptable. Can anyone point me in the right direction on how to solve this? Or explain to me, why is such a popular app so so so badly made? (In this specific case)

 
To continue, I'll provide with the actual real stuff, time, code ...
 

These results show, that any photoshop call takes quite a long time. Any suggestions on how to improve this? I'd need it to improve dramatically in speed (at least 10x).

 

Second issue:

I've now noticed a second problem - the first group is marked visible immediatelly, so it doens't get removed. Any idea why this happens?

 

Intel core i7-7700, 32 GB RAM, Adobe Photoshop 2021

 

 

Recreate demo:

Photoshop file:

 

create new, printing, A4, remove layer, add empty layer, dulicate so you have 10 empty layers. Now group these 10 layers into one group, and duplicate 9 more times. Group these groups together and duplicate 9 more times.

So there are 10 top groups, each contains 10 sub groups, each sub group contains 10 empty groups.

 

My code:

 

var start_time = new Date().getTime();

var doc = activeDocument;
var objectString;


var textFile = File(doc.path + '/time.txt');
textFile.encoding = 'UTF-8';
textFile.open('a');

textFile.write("Initialization: ", new Date().getTime() - start_time, "\n");

loopTopGroups();

textFile.write("Total time: ", new Date().getTime() - start_time, "\n");


function loopTopGroups() {

    var time_before = new Date().getTime();

    var len = doc.layers.length;
    var layers = doc.layers;

    textFile.write("Get layers: ", new Date().getTime() - time_before, "\n");
    
    for (var i = len - 1; i >= 0; i--) {
        var currentLayer = layers[i];
        
        if (!currentLayer.visible) {
            loopGroups(currentLayer);
        }

        if (currentLayer.layers.length == 0) {
            var time_before = new Date().getTime();

            currentLayer.remove();

            textFile.write("Out remove: ", new Date().getTime() - time_before, "\n");
        }
    }
}


function loopGroups(parentLayer) {
    
    var time_before = new Date().getTime();

    var len = parentLayer.layers.length;
    var layers = parentLayer.layers;

    textFile.write("Get inner layers: ", new Date().getTime() - time_before, "\n");

    for (var i = len - 1; i >= 0; i--) {
        var currentLayer = layers[i];
        
        if (currentLayer.typename == 'LayerSet') {
            if (currentLayer.layers[0].typename == 'LayerSet') {
                loopGroups(currentLayer);
            } else {
                var time_before = new Date().getTime();

                currentLayer.remove();

                textFile.write("Remove: ", new Date().getTime() - time_before, "\n");
            }
        }
    }
}

 

 

Output:

Initialization: 1
Get layers: 257
Get inner layers: 256
Remove: 249
Remove: 227
Remove: 224
Remove: 225
Remove: 223
Remove: 227
Remove: 370
Remove: 222
Remove: 324
Remove: 180
Out remove: 183
Get inner layers: 240
Remove: 222
Remove: 240
Remove: 226
Remove: 304
Remove: 234
Remove: 219
Remove: 218
Remove: 215
Remove: 291
Remove: 201
Out remove: 179
Get inner layers: 249
Remove: 218
Remove: 236
Remove: 226
Remove: 253
Remove: 279
Remove: 302
Remove: 290
Remove: 215
Remove: 465
Remove: 199
Out remove: 247
Get inner layers: 233
Remove: 239
Remove: 301
Remove: 254
Remove: 291
Remove: 255
Remove: 230
Remove: 211
Remove: 213
Remove: 220
Remove: 214
Out remove: 185
Get inner layers: 192
Remove: 208
Remove: 211
Remove: 209
Remove: 219
Remove: 217
Remove: 244
Remove: 222
Remove: 216
Remove: 203
Remove: 163
Out remove: 160
Get inner layers: 135
Remove: 234
Remove: 212
Remove: 222
Remove: 205
Remove: 305
Remove: 211
Remove: 224
Remove: 195
Remove: 227
Remove: 157
Out remove: 144
Get inner layers: 108
Remove: 197
Remove: 195
Remove: 196
Remove: 196
Remove: 224
Remove: 217
Remove: 217
Remove: 209
Remove: 217
Remove: 134
Out remove: 132
Get inner layers: 79
Remove: 194
Remove: 192
Remove: 190
Remove: 201
Remove: 196
Remove: 192
Remove: 196
Remove: 215
Remove: 191
Remove: 196
Out remove: 127
Get inner layers: 55
Remove: 218
Remove: 195
Remove: 218
Remove: 194
Remove: 224
Remove: 185
Remove: 186
Remove: 169
Remove: 166
Remove: 124
Out remove: 164
Total time: 85440
This topic has been closed for replies.
Correct answer Samuel_PFD

After some talk with my team, the target changed a little, to make it easier to work with.

 

Right now what the script is supposed to do - ignore groups that are visible on top level.

For the rest of the groups, find those that are in the objects.txt file. Remove everything else (except parent groups of groups to keep). It also deletes the top groups first to make it faster.

 

Huge thanks to this community, I wouldn't have been able to make it at all without you.

 

removeGroups(loadObjectsFile());


// Load objects.txt file, to lowercase and some clean-up
function loadObjectsFile() {

    var title = getObjectProperty('document', 'title');
    var full_path = String(getObjectProperty('document', 'fileReference')).split('%20').join(' ');

    var textFile = File(full_path.replace(title, 'objects.txt'));
    textFile.encoding = 'UTF-8';
    textFile.open('r');

    return textFile.read().toLowerCase();
}


// Hide all groups the script will work with
function hideAll(start, end) {

    var toDo = [];

    for (var i = end - 1; i >= start; i--) {
        var section = getLayerPropertyByIndex(i, 'layerSection').value;
        
        // It's a group
        if (section == 'layerSectionStart') {
            var ID = getLayerPropertyByIndex(i, 'layerID');

            // Ignore groups that are visible on top level
            if (!isTopVisible(ID)) {
                toDo.push(ID);
            }
        }
    }

    // Hide all at once
    if (toDo.length != 0) {
        executeActionOnLayers('hide', toDo);
    }
}


// Show all groups that should be kept (but not top level), return top level groups to keep
function showTarget(start, end, objectString) {

    var toDo = [];
    var topGroups = [];

    for (var i = end - 1; i >= start; i--) {
        var section = getLayerPropertyByIndex(i, 'layerSection').value;
        
        // It's a group
        if (section == 'layerSectionStart') {
            var ID = getLayerPropertyByIndex(i, 'layerID');

            if (!isTopVisible(ID)) {
                var name = getLayerPropertyByIndex(i, 'name');

                if (objectString.indexOf(String(name).toLowerCase()) != -1) {
                    if (!arrayContains(toDo, ID)) {
                        toDo.push(ID);
                    }
                    
                    var parents = getParentGroups(ID);
                    topGroups.push(parents[parents.length - 1]);

                    for (j in parents) {
                        if (!arrayContains(toDo, parents[j])) {
                            toDo.push(parents[j]);
                        }
                    }
                }
            }
        }
    }

    // Show all at once
    if (toDo.length != 0) {
        executeActionOnLayers('show', toDo);
    }

    return topGroups;
}


// Delete all groups that are not visible, keep top level array groups
function deleteRest(start, end, topGroups) {

    var toDo = [];

    // Loop through all layers
    for (var i = end - 1; i >= start; i--) {
        var section = getLayerPropertyByIndex(i, 'layerSection').value;
        
        // It's a group
        if (section == 'layerSectionStart') {
            var ID = getLayerPropertyByIndex(i, 'layerID');
            var visible = getLayerPropertyByID(ID, 'visible');

            // Only push if a parent group is not in list, and group is hidden
            if ((!isTopVisible(ID) || isParentInList(ID, topGroups)) && !visible) {
                toDo.push(ID);
            }
        }
    }

    // Delete all at once
    if (toDo.length != 0) {
        executeActionOnLayers('delete', toDo);
    }
}


// Remove all groups that are not in the objectString
function removeGroups(objectString) {

    var start = getObjectProperty('document', 'hasBackgroundLayer') ? 0 : 1;
    var end = getObjectProperty('document', 'numberOfLayers');

    hideAll(start, end);
    var topGroups = showTarget(start, end, objectString);
    deleteRest(start, end, topGroups);
}




// Return if top group is visible
function isTopVisible(ID) {

    var parentID = getLayerPropertyByID(ID, 'parentLayerID');

    while (parentID != -1) {

        ID = getLayerPropertyByID(ID, 'parentLayerID');
        parentID = getLayerPropertyByID(ID, 'parentLayerID');
    }

    return getLayerPropertyByID(ID, 'visible');
}


// Return if any parent is in a list
function isParentInList(ID, list) {

    if (list.length == 0) {
        return false;
    }
    
    var parentID = getLayerPropertyByID(ID, 'parentLayerID');

    if (arrayContains(list, parentID)) {
        return true;
    }

    while (parentID != -1) {
        ID = getLayerPropertyByID(ID, 'parentLayerID');
        parentID = getLayerPropertyByID(ID, 'parentLayerID');

        if (arrayContains(list, parentID)) {
            return true;
        }
    }

    return false;
}


// Return IDs of all parent groups
function getParentGroups(ID) {

    var parentID = getLayerPropertyByID(ID, 'parentLayerID');
    var parents = [];

    while (parentID != -1) {

        parents.push(parentID);
        ID = getLayerPropertyByID(ID, 'parentLayerID');
        parentID = getLayerPropertyByID(ID, 'parentLayerID');
    }

    return parents;
}


// Return if array contains an element
function arrayContains(array, element) {

    for (var i = 0; i < array.length; i++) {
        if (array[i] == element) {
            return true;
        }
    }

    return false;
}


function s2t(s) { return stringIDToTypeID(s); }
function t2s(t) { return typeIDToStringID(t); }


function getObjectProperty(obj, property) {

    var ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property));
    ref.putEnumerated(s2t(obj), s2t('ordinal'), s2t('targetEnum'));
    return getDescValue(executeActionGet(ref), s2t(property));
}


function getLayerPropertyByIndex(index, property) {

    ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property))
    ref.putIndex(s2t('layer'), index);
    var desc = executeActionGet(ref);
    return getDescValue(desc, s2t(property));
}


function getLayerPropertyByID(ID, property) {

    ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property))
    ref.putIdentifier(s2t('layer'), ID);
    var desc = executeActionGet(ref);
    return getDescValue(desc, s2t(property));
}


function executeActionOnLayers(action, IDs) {

    ref = new ActionReference();

    for (i in IDs) {
        ref.putIdentifier(s2t('layer'), IDs[i]);
    }

    var d = new ActionDescriptor();
    d.putReference(s2t('null'), ref);

    executeAction(s2t(action), d);
}


function getDescValue(descriptor, property) {
    switch (descriptor.getType(property)) {
        case DescValueType.OBJECTTYPE: return { type: t2s(descriptor.getObjectType(property)), value: descriptor.getObjectValue(property) };
        case DescValueType.LISTTYPE: return descriptor.getList(property);
        case DescValueType.REFERENCETYPE: return descriptor.getReference(property);
        case DescValueType.BOOLEANTYPE: return descriptor.getBoolean(property);
        case DescValueType.STRINGTYPE: return descriptor.getString(property);
        case DescValueType.INTEGERTYPE: return descriptor.getInteger(property);
        case DescValueType.LARGEINTEGERTYPE: return descriptor.getLargeInteger(property);
        case DescValueType.DOUBLETYPE: return descriptor.getDouble(property);
        case DescValueType.ALIASTYPE: return descriptor.getPath(property);
        case DescValueType.CLASSTYPE: return descriptor.getClass(property);
        case DescValueType.UNITDOUBLE: return (descriptor.getUnitDoubleValue(property));
        case DescValueType.ENUMERATEDTYPE: return { type: t2s(descriptor.getEnumerationType(property)), value: t2s(descriptor.getEnumerationValue(property)) };
        default: return 0;
    };
}

6 replies

Known Participant
October 30, 2021

Why is java script files are slow, I think may be some issue. 

I found the answar but not understand :- .jsx script extremely slow

 

There, DOM is slower than AM. I can't indentify which code is DOM or AM

Could you give the example of DOM or AM For Understand. I have searched on google ,but didnot get the answar.

Kukurykus
Brainiac
October 31, 2021
Known Participant
October 31, 2021

There, I can't determine which code is AM Code, Could you give example of AM Code For Understanding

I can't identify to AM Code or DOM Code

Samuel_PFDAuthorCorrect answer
Inspiring
August 17, 2021

After some talk with my team, the target changed a little, to make it easier to work with.

 

Right now what the script is supposed to do - ignore groups that are visible on top level.

For the rest of the groups, find those that are in the objects.txt file. Remove everything else (except parent groups of groups to keep). It also deletes the top groups first to make it faster.

 

Huge thanks to this community, I wouldn't have been able to make it at all without you.

 

removeGroups(loadObjectsFile());


// Load objects.txt file, to lowercase and some clean-up
function loadObjectsFile() {

    var title = getObjectProperty('document', 'title');
    var full_path = String(getObjectProperty('document', 'fileReference')).split('%20').join(' ');

    var textFile = File(full_path.replace(title, 'objects.txt'));
    textFile.encoding = 'UTF-8';
    textFile.open('r');

    return textFile.read().toLowerCase();
}


// Hide all groups the script will work with
function hideAll(start, end) {

    var toDo = [];

    for (var i = end - 1; i >= start; i--) {
        var section = getLayerPropertyByIndex(i, 'layerSection').value;
        
        // It's a group
        if (section == 'layerSectionStart') {
            var ID = getLayerPropertyByIndex(i, 'layerID');

            // Ignore groups that are visible on top level
            if (!isTopVisible(ID)) {
                toDo.push(ID);
            }
        }
    }

    // Hide all at once
    if (toDo.length != 0) {
        executeActionOnLayers('hide', toDo);
    }
}


// Show all groups that should be kept (but not top level), return top level groups to keep
function showTarget(start, end, objectString) {

    var toDo = [];
    var topGroups = [];

    for (var i = end - 1; i >= start; i--) {
        var section = getLayerPropertyByIndex(i, 'layerSection').value;
        
        // It's a group
        if (section == 'layerSectionStart') {
            var ID = getLayerPropertyByIndex(i, 'layerID');

            if (!isTopVisible(ID)) {
                var name = getLayerPropertyByIndex(i, 'name');

                if (objectString.indexOf(String(name).toLowerCase()) != -1) {
                    if (!arrayContains(toDo, ID)) {
                        toDo.push(ID);
                    }
                    
                    var parents = getParentGroups(ID);
                    topGroups.push(parents[parents.length - 1]);

                    for (j in parents) {
                        if (!arrayContains(toDo, parents[j])) {
                            toDo.push(parents[j]);
                        }
                    }
                }
            }
        }
    }

    // Show all at once
    if (toDo.length != 0) {
        executeActionOnLayers('show', toDo);
    }

    return topGroups;
}


// Delete all groups that are not visible, keep top level array groups
function deleteRest(start, end, topGroups) {

    var toDo = [];

    // Loop through all layers
    for (var i = end - 1; i >= start; i--) {
        var section = getLayerPropertyByIndex(i, 'layerSection').value;
        
        // It's a group
        if (section == 'layerSectionStart') {
            var ID = getLayerPropertyByIndex(i, 'layerID');
            var visible = getLayerPropertyByID(ID, 'visible');

            // Only push if a parent group is not in list, and group is hidden
            if ((!isTopVisible(ID) || isParentInList(ID, topGroups)) && !visible) {
                toDo.push(ID);
            }
        }
    }

    // Delete all at once
    if (toDo.length != 0) {
        executeActionOnLayers('delete', toDo);
    }
}


// Remove all groups that are not in the objectString
function removeGroups(objectString) {

    var start = getObjectProperty('document', 'hasBackgroundLayer') ? 0 : 1;
    var end = getObjectProperty('document', 'numberOfLayers');

    hideAll(start, end);
    var topGroups = showTarget(start, end, objectString);
    deleteRest(start, end, topGroups);
}




// Return if top group is visible
function isTopVisible(ID) {

    var parentID = getLayerPropertyByID(ID, 'parentLayerID');

    while (parentID != -1) {

        ID = getLayerPropertyByID(ID, 'parentLayerID');
        parentID = getLayerPropertyByID(ID, 'parentLayerID');
    }

    return getLayerPropertyByID(ID, 'visible');
}


// Return if any parent is in a list
function isParentInList(ID, list) {

    if (list.length == 0) {
        return false;
    }
    
    var parentID = getLayerPropertyByID(ID, 'parentLayerID');

    if (arrayContains(list, parentID)) {
        return true;
    }

    while (parentID != -1) {
        ID = getLayerPropertyByID(ID, 'parentLayerID');
        parentID = getLayerPropertyByID(ID, 'parentLayerID');

        if (arrayContains(list, parentID)) {
            return true;
        }
    }

    return false;
}


// Return IDs of all parent groups
function getParentGroups(ID) {

    var parentID = getLayerPropertyByID(ID, 'parentLayerID');
    var parents = [];

    while (parentID != -1) {

        parents.push(parentID);
        ID = getLayerPropertyByID(ID, 'parentLayerID');
        parentID = getLayerPropertyByID(ID, 'parentLayerID');
    }

    return parents;
}


// Return if array contains an element
function arrayContains(array, element) {

    for (var i = 0; i < array.length; i++) {
        if (array[i] == element) {
            return true;
        }
    }

    return false;
}


function s2t(s) { return stringIDToTypeID(s); }
function t2s(t) { return typeIDToStringID(t); }


function getObjectProperty(obj, property) {

    var ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property));
    ref.putEnumerated(s2t(obj), s2t('ordinal'), s2t('targetEnum'));
    return getDescValue(executeActionGet(ref), s2t(property));
}


function getLayerPropertyByIndex(index, property) {

    ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property))
    ref.putIndex(s2t('layer'), index);
    var desc = executeActionGet(ref);
    return getDescValue(desc, s2t(property));
}


function getLayerPropertyByID(ID, property) {

    ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property))
    ref.putIdentifier(s2t('layer'), ID);
    var desc = executeActionGet(ref);
    return getDescValue(desc, s2t(property));
}


function executeActionOnLayers(action, IDs) {

    ref = new ActionReference();

    for (i in IDs) {
        ref.putIdentifier(s2t('layer'), IDs[i]);
    }

    var d = new ActionDescriptor();
    d.putReference(s2t('null'), ref);

    executeAction(s2t(action), d);
}


function getDescValue(descriptor, property) {
    switch (descriptor.getType(property)) {
        case DescValueType.OBJECTTYPE: return { type: t2s(descriptor.getObjectType(property)), value: descriptor.getObjectValue(property) };
        case DescValueType.LISTTYPE: return descriptor.getList(property);
        case DescValueType.REFERENCETYPE: return descriptor.getReference(property);
        case DescValueType.BOOLEANTYPE: return descriptor.getBoolean(property);
        case DescValueType.STRINGTYPE: return descriptor.getString(property);
        case DescValueType.INTEGERTYPE: return descriptor.getInteger(property);
        case DescValueType.LARGEINTEGERTYPE: return descriptor.getLargeInteger(property);
        case DescValueType.DOUBLETYPE: return descriptor.getDouble(property);
        case DescValueType.ALIASTYPE: return descriptor.getPath(property);
        case DescValueType.CLASSTYPE: return descriptor.getClass(property);
        case DescValueType.UNITDOUBLE: return (descriptor.getUnitDoubleValue(property));
        case DescValueType.ENUMERATEDTYPE: return { type: t2s(descriptor.getEnumerationType(property)), value: t2s(descriptor.getEnumerationValue(property)) };
        default: return 0;
    };
}
Kukurykus
Brainiac
August 17, 2021

It's appropriate to mark correct answer of user (jazz-y) that helped you due to your original request, than the solution to somehow changed problem, but still with code based on originally provided.

Inspiring
August 17, 2021

That's a good point, however that code wasn't working for me due to something.

 

If it's fixed, I will mark that instead.

Inspiring
August 13, 2021

After hours of pain and suffering, I made my own solution.

 

@jazz-y  I really appreciate you helping (and your older posts where you explained some basics and how to start), without you, I wouldn't have been able to do anything.

 

I would have straight up used your solution, but it had some errors, and at that time, I had no knowledge of this magic API, so I wasn't capable of fixing it -> so I learned the basics and adapted them in my solution.

 

Again, huge thanks to you.

 

loopGroups(loadObjectsFile());


// Load objects.txt file
function loadObjectsFile() {

    var title = getProperty('document', 'title');
    var full_path = String(getProperty('document', 'fileReference')).split('%20').join(' ');

    var textFile = File(full_path.replace(title, 'objects.txt'));
    textFile.encoding = 'UTF-8';
    textFile.open('r');

    return textFile.read().toLowerCase();
}


// Return if top group is visible
function isTopVisible(index) {

    var parentID = getLayerPropertyByIndex(index, 'parentLayerID');
    var ID = getLayerPropertyByIndex(index, 'layerID');

    while (parentID != -1) {

        ID = getLayerPropertyByID(ID, 'parentLayerID');
        parentID = getLayerPropertyByID(ID, 'parentLayerID');
    }

    return getLayerPropertyByID(ID, 'visible');
}


function arrayContains(array, element) {

    for (var i = 0; i < array.length; i++) {
        if (array[i] == element) {
            return true;
        }
    }

    return false;
}


function loopGroups(objectString) {

    var start = getProperty('document', 'hasBackgroundLayer') ? 0 : 1;
    var end = getProperty('document', 'numberOfLayers');
    var markedIDs = [];

    for (var i = end - 1; i >= start; i--) {
        var ID = getLayerPropertyByIndex(i, 'layerID');

        if (arrayContains(markedIDs, ID)) {
            continue;
        }

        var section = getLayerPropertyByIndex(i, 'layerSection').value;
        var removed = false;

        // It's a group
        if (section == 'layerSectionStart') {
            if (!isTopVisible(i)) {
                var name = getLayerPropertyByIndex(i, 'name');

                if (objectString.indexOf(String(name).toLowerCase()) == -1) {
                    removeLayerByID(ID);
                    
                    i = getProperty('document', 'numberOfLayers');
                    removed = true;
                }
            }
        }

        if (!removed) {
            markedIDs.push(ID);
        }
    }
}


function s2t(s) { return stringIDToTypeID(s); }
function t2s(t) { return typeIDToStringID(t); }


function getProperty(obj, property) {

    var ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property));
    ref.putEnumerated(s2t(obj), s2t('ordinal'), s2t('targetEnum'));
    return getDescValue(executeActionGet(ref), s2t(property));
}


function getLayerPropertyByIndex(index, property) {

    ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property))
    ref.putIndex(s2t('layer'), index);
    var desc = executeActionGet(ref);
    return getDescValue(desc, s2t(property));
}


function getLayerPropertyByID(ID, property) {

    ref = new ActionReference();
    ref.putProperty(s2t('property'), s2t(property))
    ref.putIdentifier(s2t('layer'), ID);
    var desc = executeActionGet(ref);
    return getDescValue(desc, s2t(property));
}


function removeLayerByID(ID) {

    ref = new ActionReference();
    ref.putIdentifier(s2t('layer'), ID);

    var d = new ActionDescriptor();
    d.putReference(s2t('null'), ref);

    executeAction(s2t('delete'), d);
}


function getDescValue(descriptor, property) {
    switch (descriptor.getType(property)) {
        case DescValueType.OBJECTTYPE: return { type: t2s(descriptor.getObjectType(property)), value: descriptor.getObjectValue(property) };
        case DescValueType.LISTTYPE: return descriptor.getList(property);
        case DescValueType.REFERENCETYPE: return descriptor.getReference(property);
        case DescValueType.BOOLEANTYPE: return descriptor.getBoolean(property);
        case DescValueType.STRINGTYPE: return descriptor.getString(property);
        case DescValueType.INTEGERTYPE: return descriptor.getInteger(property);
        case DescValueType.LARGEINTEGERTYPE: return descriptor.getLargeInteger(property);
        case DescValueType.DOUBLETYPE: return descriptor.getDouble(property);
        case DescValueType.ALIASTYPE: return descriptor.getPath(property);
        case DescValueType.CLASSTYPE: return descriptor.getClass(property);
        case DescValueType.UNITDOUBLE: return (descriptor.getUnitDoubleValue(property));
        case DescValueType.ENUMERATEDTYPE: return { type: t2s(descriptor.getEnumerationType(property)), value: t2s(descriptor.getEnumerationValue(property)) };
        default: return 0;
    };
}

 

Inspiring
August 13, 2021

Edit - I still don't know how to edit a comment, so here it is

it's not as fast as I expected - takes like 10-20 seconds on large files, but that will have to do for now.

Kukurykus
Brainiac
August 13, 2021

Why don't you use deletion method from my posted snippet to accelerate your script?

Kukurykus
Brainiac
August 12, 2021

My version is with no recursion that surely would be helpful in other layerSets tree. You may use $.hiresTimer at beginning and end of code to check it takes a half of second. Use fully AM to speed it up:

 

sTT = stringIDToTypeID, lSs = [].slice.call(activeDocument.layerSets, o = {})
.sort(function(v){(vsble = v.visible) && o[v.id] = ''; return !vsble}).splice(o.__count__)
ref=new ActionReference(); while(lSs.length) ref.putIdentifier(sTT('layer'),lSs.shift().id);
(dsc=new ActionDescriptor()).putReference(sTT('null'), ref),executeAction(sTT('delete'),dsc)

 

Stephen Marsh
Community Expert
August 12, 2021

Posting cropped screenshots of the fully expanded layers panel in a before/after would help to illustrate.

Inspiring
August 12, 2021

would help illustrate ... what?

before: 10 groups, each has 10 subgroups, each has 10 layers.

after: 1 group, with 10 subgroups, each with 10 layers

Inspiring
August 12, 2021

Edit:

before - all top groups are hidden

after - the only top group remaining is visible

Brainiac
August 12, 2021

To significantly speed up the script's work, you need to use the Action Manager code.

So I understand that besides the slow work, your script also does not work exactly as you wanted. Briefly describe what result of this script you would like to get?

Inspiring
August 12, 2021

Any idea why regular old coding doesn't produce up to speed results?

Any references toward the Action Manager code?

Right now, I want the script to remove all hidden groups. The problem is that when it starts, it makes the first hidden group visible, so it won't remove it later on.

 

Thanks for your input.

Brainiac
August 12, 2021

In simple words, when working with the DOM, the script receives all the properties of an object at the time of accessing it (even if you don't need them). Action manager allows you to get only those properties that are needed at the moment. This greatly speeds up the script. I'm busy at the moment, but a little later I can give you a sample code that removes invisible groups. Perhaps other users will help you too