Skip to main content
Participating Frequently
February 21, 2024
Answered

Script to generate gif from folder of images

  • February 21, 2024
  • 4 replies
  • 2032 views

Not super familar with scripting, how would one create a script that you could point towards a folder, and it would itterate through each subfolder, turning it's contents into a gif with the name of the subfolder? The images themselves in each subfolder are ordered, so there would be no major concern of it getting frames wrong.

Thanks!

This topic has been closed for replies.
Correct answer Stephen Marsh

@111aaa11 – Here is a new version to automatically process all sub-folders under the selected top-level folder.

 

EDIT: Original code updated to 1.1 to correct an oversight where %20 characters were output instead of word spaces in saved filenames.

 

/* 
Create GIF89a files from PNG Files in All Sub-folders of Selected Folder.jsx
v1.1 - 24th February 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-generate-gif-from-folder-of-images/td-p/14438104
*/

#target photoshop

// Recursive loop over all 1st level sub-folders under the selected parent/root folder by c.pfaffenbichler (2022)
var theFolder = Folder.selectDialog('Please select the input folder:');
var theFolders = theFolder.getFiles(isFolder);
//theFolders.sort().reverse();
theFolders.sort();
for (var m = 0; m < theFolders.length; m++) {
    var inputFolder = theFolders[m];

    cTID = function (s) {
        return app.charIDToTypeID(s);
    };
    sTID = function (s) {
        return app.stringIDToTypeID(s);
    };
    // Call the main function
    gifAnimFromSubfolders();
}


// Functions

function isFolder(theFile) {
    if (theFile.constructor.name == "Folder") {
        return true;
    } else {
        return false;
    }
}

function gifAnimFromSubfolders() {

    // CAPTURE AND SET THE APP PREFS
    var savedDisplayDialogs = app.displayDialogs;
    app.displayDialogs = DialogModes.NO;
    var origUnits = app.preferences.rulerUnits;
    app.preferences.rulerUnits = Units.PIXELS;

    // STACK THE FILES TO LAYERS
    var inputFiles = inputFolder.getFiles(/\.png$/i);
    // inputFiles.sort().reverse();
    inputFiles.sort();
    app.displayDialogs = DialogModes.NO;
    var baseDoc = open(inputFiles[0]);
    baseDoc = app.activeDocument;
    var savePath = baseDoc.path.fsName.replace(/(^.+\/)(.+$)/, '$1');
    var saveName = inputFolder.fsName.replace(/(^.+\/)(.+$)/, '$2');
    baseDoc.duplicate(saveName, false);
    baseDoc.close(SaveOptions.DONOTSAVECHANGES);
    for (var i = 0; i < inputFiles.length; i++) {
        // true = linked | false = embedded
        placeFile(new File(inputFiles[i]), false, 0, 0);
        // Remove the filename extension from the layer name
        app.activeDocument.activeLayer.name = inputFiles[i].name.replace(/\.[^\.]+$/, '');
    }
    // Remove the duplicate base layer
    app.activeDocument.layers[app.activeDocument.layers.length - 1].remove();
    //app.runMenuItem(stringIDToTypeID("selectAllLayers"));
    //reverseLayerStack();
    // Reset the app prefs
    app.displayDialogs = savedDisplayDialogs;
    app.preferences.rulerUnits = origUnits;


    // MAKE ANIMATION FRAME
    var idmakeFrameAnimation = stringIDToTypeID("makeFrameAnimation");
    executeAction(idmakeFrameAnimation, undefined, DialogModes.NO);


    // MAKE ANIMATION FRAMES FROM LAYERS
    var idanimationFramesFromLayers = stringIDToTypeID("animationFramesFromLayers");
    var desc203 = new ActionDescriptor();
    executeAction(idanimationFramesFromLayers, desc203, DialogModes.NO);


    // SELECT ALL ANIMATION FRAMES
    var idanimationSelectAll = stringIDToTypeID("animationSelectAll");
    var desc208 = new ActionDescriptor();
    executeAction(idanimationSelectAll, desc208, DialogModes.NO);


    // SET THE ANIMATION FRAME DELAY TO 1 SECOND
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var descriptor2 = new ActionDescriptor();
    var reference = new ActionReference();
    reference.putEnumerated(s2t("animationFrameClass"), s2t("ordinal"), s2t("targetEnum"));
    descriptor.putReference(s2t("null"), reference);
    descriptor2.putDouble(s2t("animationFrameDelay"), 1.000000);
    descriptor.putObject(s2t("to"), s2t("animationFrameClass"), descriptor2);
    executeAction(s2t("set"), descriptor, DialogModes.NO);


    // SAVE FOR WEB
    var c2t = function (s) {
        return app.charIDToTypeID(s);
    };
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var descriptor2 = new ActionDescriptor();
    var descriptor3 = new ActionDescriptor();
    var descriptor4 = new ActionDescriptor();
    var descriptor5 = new ActionDescriptor();
    var descriptor6 = new ActionDescriptor();
    var descriptor7 = new ActionDescriptor();
    var descriptor8 = new ActionDescriptor();
    var descriptor9 = new ActionDescriptor();
    var descriptor10 = new ActionDescriptor();
    var descriptor11 = new ActionDescriptor();
    var descriptor12 = new ActionDescriptor();
    var descriptor13 = new ActionDescriptor();
    var descriptor14 = new ActionDescriptor();
    var descriptor15 = new ActionDescriptor();
    var descriptor16 = new ActionDescriptor();
    var descriptor17 = new ActionDescriptor();
    var list = new ActionList();
    var list2 = new ActionList();
    descriptor2.putEnumerated(c2t("Op  "), c2t("SWOp"), c2t("OpSa"));
    descriptor2.putBoolean(c2t("DIDr"), true);
    descriptor2.putPath(s2t("in"), new File(savePath)); // thePath
    descriptor2.putString(c2t("ovFN"), activeDocument.name + ".gif"); // theName
    descriptor2.putEnumerated(s2t("format"), c2t("IRFm"), c2t("GIFf"));
    descriptor2.putBoolean(s2t("interfaceIconFrameDimmed"), false);
    descriptor2.putEnumerated(c2t("RedA"), c2t("IRRd"), c2t("Sltv"));
    descriptor2.putBoolean(c2t("RChT"), false);
    descriptor2.putBoolean(c2t("RChV"), false);
    descriptor2.putBoolean(c2t("AuRd"), false);
    descriptor2.putInteger(c2t("NCol"), 256);
    descriptor2.putInteger(c2t("DChS"), 0);
    descriptor2.putInteger(c2t("DCUI"), 0);
    descriptor2.putBoolean(c2t("DChT"), false);
    descriptor2.putBoolean(c2t("DChV"), false);
    descriptor2.putInteger(c2t("WebS"), 0);
    descriptor2.putEnumerated(c2t("TDth"), c2t("IRDt"), s2t("none"));
    descriptor2.putInteger(c2t("TDtA"), 100);
    descriptor2.putInteger(c2t("Loss"), 0);
    descriptor2.putInteger(c2t("LChS"), 0);
    descriptor2.putInteger(c2t("LCUI"), 100);
    descriptor2.putBoolean(c2t("LChT"), false);
    descriptor2.putBoolean(c2t("LChV"), false);
    descriptor2.putBoolean(s2t("transparency"), true);
    descriptor2.putBoolean(c2t("Mtt "), true);
    descriptor2.putEnumerated(s2t("dither"), c2t("IRDt"), s2t("diffusion"));
    descriptor2.putInteger(s2t("ditherAmount"), 100);
    descriptor2.putInteger(c2t("MttR"), 255);
    descriptor2.putInteger(c2t("MttG"), 255);
    descriptor2.putInteger(c2t("MttB"), 255);
    descriptor2.putBoolean(c2t("SHTM"), false);
    descriptor2.putBoolean(c2t("SImg"), true);
    descriptor2.putEnumerated(c2t("SWsl"), c2t("STsl"), c2t("SLAl"));
    descriptor2.putEnumerated(c2t("SWch"), c2t("STch"), c2t("CHsR"));
    descriptor2.putEnumerated(c2t("SWmd"), c2t("STmd"), c2t("MDNn"));
    descriptor2.putBoolean(c2t("ohXH"), false);
    descriptor2.putBoolean(c2t("ohIC"), true);
    descriptor2.putBoolean(c2t("ohAA"), true);
    descriptor2.putBoolean(c2t("ohQA"), true);
    descriptor2.putBoolean(c2t("ohCA"), false);
    descriptor2.putBoolean(c2t("ohIZ"), true);
    descriptor2.putEnumerated(c2t("ohTC"), c2t("SToc"), c2t("OC03"));
    descriptor2.putEnumerated(c2t("ohAC"), c2t("SToc"), c2t("OC03"));
    descriptor2.putInteger(c2t("ohIn"), -1);
    descriptor2.putEnumerated(c2t("ohLE"), c2t("STle"), c2t("LE03"));
    descriptor2.putEnumerated(c2t("ohEn"), c2t("STen"), c2t("EN00"));
    descriptor2.putBoolean(c2t("olCS"), false);
    descriptor2.putEnumerated(c2t("olEC"), c2t("STst"), c2t("ST00"));
    descriptor2.putEnumerated(c2t("olWH"), c2t("STwh"), c2t("WH01"));
    descriptor2.putEnumerated(c2t("olSV"), c2t("STsp"), c2t("SP04"));
    descriptor2.putEnumerated(c2t("olSH"), c2t("STsp"), c2t("SP04"));
    descriptor3.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC00"));
    list.putObject(c2t("SCnc"), descriptor3);
    descriptor4.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC19"));
    list.putObject(c2t("SCnc"), descriptor4);
    descriptor5.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC28"));
    list.putObject(c2t("SCnc"), descriptor5);
    descriptor6.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list.putObject(c2t("SCnc"), descriptor6);
    descriptor7.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list.putObject(c2t("SCnc"), descriptor7);
    descriptor8.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list.putObject(c2t("SCnc"), descriptor8);
    descriptor2.putList(c2t("olNC"), list);
    descriptor2.putBoolean(c2t("obIA"), true);
    descriptor2.putString(c2t("obIP"), "");
    descriptor2.putEnumerated(c2t("obCS"), c2t("STcs"), c2t("CS01"));
    descriptor9.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC01"));
    list2.putObject(c2t("SCnc"), descriptor9);
    descriptor10.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC20"));
    list2.putObject(c2t("SCnc"), descriptor10);
    descriptor11.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC02"));
    list2.putObject(c2t("SCnc"), descriptor11);
    descriptor12.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC19"));
    list2.putObject(c2t("SCnc"), descriptor12);
    descriptor13.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC06"));
    list2.putObject(c2t("SCnc"), descriptor13);
    descriptor14.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list2.putObject(c2t("SCnc"), descriptor14);
    descriptor15.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list2.putObject(c2t("SCnc"), descriptor15);
    descriptor16.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list2.putObject(c2t("SCnc"), descriptor16);
    descriptor17.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC22"));
    list2.putObject(c2t("SCnc"), descriptor17);
    descriptor2.putList(c2t("ovNC"), list2);
    descriptor2.putBoolean(c2t("ovCM"), false);
    descriptor2.putBoolean(c2t("ovCW"), false);
    descriptor2.putBoolean(c2t("ovCU"), false);
    descriptor2.putBoolean(c2t("ovSF"), true);
    descriptor2.putBoolean(c2t("ovCB"), true);
    descriptor2.putString(c2t("ovSN"), "images");
    descriptor.putObject(s2t("using"), s2t("SaveForWeb"), descriptor2);
    executeAction(s2t("export"), descriptor, DialogModes.NO);


    // CLOSE THE TEMP WORKING DOC
    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);


    ///// FUNCTIONS /////

    function placeFile(null2, linked, horizontal, vertical) {
        var s2t = function (s) {
            return app.stringIDToTypeID(s);
        };
        var AD = new ActionDescriptor();
        AD.putInteger(s2t("ID"), 1);
        AD.putPath(s2t("null"), null2);
        AD.putBoolean(s2t("linked"), linked); // false for embedded
        AD.putEnumerated(s2t("freeTransformCenterState"), s2t("quadCenterState"), s2t("QCSAverage"));
        AD.putUnitDouble(s2t("horizontal"), s2t("pixelsUnit"), horizontal);
        AD.putUnitDouble(s2t("vertical"), s2t("pixelsUnit"), vertical);
        AD.putObject(s2t("offset"), s2t("offset"), AD);
        executeAction(s2t("placeEvent"), AD, DialogModes.NO);
    }

    function reverseLayerStack() {
        var idreverse = stringIDToTypeID("reverse");
        var desc4653 = new ActionDescriptor();
        var idnull = stringIDToTypeID("null");
        var ref2335 = new ActionReference();
        var idlayer = stringIDToTypeID("layer");
        var idordinal = stringIDToTypeID("ordinal");
        var idtargetEnum = stringIDToTypeID("targetEnum");
        ref2335.putEnumerated(idlayer, idordinal, idtargetEnum);
        desc4653.putReference(idnull, ref2335);
        executeAction(idreverse, desc4653, DialogModes.NO);
    }

}

 

4 replies

Stephen Marsh
Community Expert
Stephen MarshCommunity ExpertCorrect answer
Community Expert
February 23, 2024

@111aaa11 – Here is a new version to automatically process all sub-folders under the selected top-level folder.

 

EDIT: Original code updated to 1.1 to correct an oversight where %20 characters were output instead of word spaces in saved filenames.

 

/* 
Create GIF89a files from PNG Files in All Sub-folders of Selected Folder.jsx
v1.1 - 24th February 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-generate-gif-from-folder-of-images/td-p/14438104
*/

#target photoshop

// Recursive loop over all 1st level sub-folders under the selected parent/root folder by c.pfaffenbichler (2022)
var theFolder = Folder.selectDialog('Please select the input folder:');
var theFolders = theFolder.getFiles(isFolder);
//theFolders.sort().reverse();
theFolders.sort();
for (var m = 0; m < theFolders.length; m++) {
    var inputFolder = theFolders[m];

    cTID = function (s) {
        return app.charIDToTypeID(s);
    };
    sTID = function (s) {
        return app.stringIDToTypeID(s);
    };
    // Call the main function
    gifAnimFromSubfolders();
}


// Functions

function isFolder(theFile) {
    if (theFile.constructor.name == "Folder") {
        return true;
    } else {
        return false;
    }
}

function gifAnimFromSubfolders() {

    // CAPTURE AND SET THE APP PREFS
    var savedDisplayDialogs = app.displayDialogs;
    app.displayDialogs = DialogModes.NO;
    var origUnits = app.preferences.rulerUnits;
    app.preferences.rulerUnits = Units.PIXELS;

    // STACK THE FILES TO LAYERS
    var inputFiles = inputFolder.getFiles(/\.png$/i);
    // inputFiles.sort().reverse();
    inputFiles.sort();
    app.displayDialogs = DialogModes.NO;
    var baseDoc = open(inputFiles[0]);
    baseDoc = app.activeDocument;
    var savePath = baseDoc.path.fsName.replace(/(^.+\/)(.+$)/, '$1');
    var saveName = inputFolder.fsName.replace(/(^.+\/)(.+$)/, '$2');
    baseDoc.duplicate(saveName, false);
    baseDoc.close(SaveOptions.DONOTSAVECHANGES);
    for (var i = 0; i < inputFiles.length; i++) {
        // true = linked | false = embedded
        placeFile(new File(inputFiles[i]), false, 0, 0);
        // Remove the filename extension from the layer name
        app.activeDocument.activeLayer.name = inputFiles[i].name.replace(/\.[^\.]+$/, '');
    }
    // Remove the duplicate base layer
    app.activeDocument.layers[app.activeDocument.layers.length - 1].remove();
    //app.runMenuItem(stringIDToTypeID("selectAllLayers"));
    //reverseLayerStack();
    // Reset the app prefs
    app.displayDialogs = savedDisplayDialogs;
    app.preferences.rulerUnits = origUnits;


    // MAKE ANIMATION FRAME
    var idmakeFrameAnimation = stringIDToTypeID("makeFrameAnimation");
    executeAction(idmakeFrameAnimation, undefined, DialogModes.NO);


    // MAKE ANIMATION FRAMES FROM LAYERS
    var idanimationFramesFromLayers = stringIDToTypeID("animationFramesFromLayers");
    var desc203 = new ActionDescriptor();
    executeAction(idanimationFramesFromLayers, desc203, DialogModes.NO);


    // SELECT ALL ANIMATION FRAMES
    var idanimationSelectAll = stringIDToTypeID("animationSelectAll");
    var desc208 = new ActionDescriptor();
    executeAction(idanimationSelectAll, desc208, DialogModes.NO);


    // SET THE ANIMATION FRAME DELAY TO 1 SECOND
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var descriptor2 = new ActionDescriptor();
    var reference = new ActionReference();
    reference.putEnumerated(s2t("animationFrameClass"), s2t("ordinal"), s2t("targetEnum"));
    descriptor.putReference(s2t("null"), reference);
    descriptor2.putDouble(s2t("animationFrameDelay"), 1.000000);
    descriptor.putObject(s2t("to"), s2t("animationFrameClass"), descriptor2);
    executeAction(s2t("set"), descriptor, DialogModes.NO);


    // SAVE FOR WEB
    var c2t = function (s) {
        return app.charIDToTypeID(s);
    };
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var descriptor = new ActionDescriptor();
    var descriptor2 = new ActionDescriptor();
    var descriptor3 = new ActionDescriptor();
    var descriptor4 = new ActionDescriptor();
    var descriptor5 = new ActionDescriptor();
    var descriptor6 = new ActionDescriptor();
    var descriptor7 = new ActionDescriptor();
    var descriptor8 = new ActionDescriptor();
    var descriptor9 = new ActionDescriptor();
    var descriptor10 = new ActionDescriptor();
    var descriptor11 = new ActionDescriptor();
    var descriptor12 = new ActionDescriptor();
    var descriptor13 = new ActionDescriptor();
    var descriptor14 = new ActionDescriptor();
    var descriptor15 = new ActionDescriptor();
    var descriptor16 = new ActionDescriptor();
    var descriptor17 = new ActionDescriptor();
    var list = new ActionList();
    var list2 = new ActionList();
    descriptor2.putEnumerated(c2t("Op  "), c2t("SWOp"), c2t("OpSa"));
    descriptor2.putBoolean(c2t("DIDr"), true);
    descriptor2.putPath(s2t("in"), new File(savePath)); // thePath
    descriptor2.putString(c2t("ovFN"), activeDocument.name + ".gif"); // theName
    descriptor2.putEnumerated(s2t("format"), c2t("IRFm"), c2t("GIFf"));
    descriptor2.putBoolean(s2t("interfaceIconFrameDimmed"), false);
    descriptor2.putEnumerated(c2t("RedA"), c2t("IRRd"), c2t("Sltv"));
    descriptor2.putBoolean(c2t("RChT"), false);
    descriptor2.putBoolean(c2t("RChV"), false);
    descriptor2.putBoolean(c2t("AuRd"), false);
    descriptor2.putInteger(c2t("NCol"), 256);
    descriptor2.putInteger(c2t("DChS"), 0);
    descriptor2.putInteger(c2t("DCUI"), 0);
    descriptor2.putBoolean(c2t("DChT"), false);
    descriptor2.putBoolean(c2t("DChV"), false);
    descriptor2.putInteger(c2t("WebS"), 0);
    descriptor2.putEnumerated(c2t("TDth"), c2t("IRDt"), s2t("none"));
    descriptor2.putInteger(c2t("TDtA"), 100);
    descriptor2.putInteger(c2t("Loss"), 0);
    descriptor2.putInteger(c2t("LChS"), 0);
    descriptor2.putInteger(c2t("LCUI"), 100);
    descriptor2.putBoolean(c2t("LChT"), false);
    descriptor2.putBoolean(c2t("LChV"), false);
    descriptor2.putBoolean(s2t("transparency"), true);
    descriptor2.putBoolean(c2t("Mtt "), true);
    descriptor2.putEnumerated(s2t("dither"), c2t("IRDt"), s2t("diffusion"));
    descriptor2.putInteger(s2t("ditherAmount"), 100);
    descriptor2.putInteger(c2t("MttR"), 255);
    descriptor2.putInteger(c2t("MttG"), 255);
    descriptor2.putInteger(c2t("MttB"), 255);
    descriptor2.putBoolean(c2t("SHTM"), false);
    descriptor2.putBoolean(c2t("SImg"), true);
    descriptor2.putEnumerated(c2t("SWsl"), c2t("STsl"), c2t("SLAl"));
    descriptor2.putEnumerated(c2t("SWch"), c2t("STch"), c2t("CHsR"));
    descriptor2.putEnumerated(c2t("SWmd"), c2t("STmd"), c2t("MDNn"));
    descriptor2.putBoolean(c2t("ohXH"), false);
    descriptor2.putBoolean(c2t("ohIC"), true);
    descriptor2.putBoolean(c2t("ohAA"), true);
    descriptor2.putBoolean(c2t("ohQA"), true);
    descriptor2.putBoolean(c2t("ohCA"), false);
    descriptor2.putBoolean(c2t("ohIZ"), true);
    descriptor2.putEnumerated(c2t("ohTC"), c2t("SToc"), c2t("OC03"));
    descriptor2.putEnumerated(c2t("ohAC"), c2t("SToc"), c2t("OC03"));
    descriptor2.putInteger(c2t("ohIn"), -1);
    descriptor2.putEnumerated(c2t("ohLE"), c2t("STle"), c2t("LE03"));
    descriptor2.putEnumerated(c2t("ohEn"), c2t("STen"), c2t("EN00"));
    descriptor2.putBoolean(c2t("olCS"), false);
    descriptor2.putEnumerated(c2t("olEC"), c2t("STst"), c2t("ST00"));
    descriptor2.putEnumerated(c2t("olWH"), c2t("STwh"), c2t("WH01"));
    descriptor2.putEnumerated(c2t("olSV"), c2t("STsp"), c2t("SP04"));
    descriptor2.putEnumerated(c2t("olSH"), c2t("STsp"), c2t("SP04"));
    descriptor3.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC00"));
    list.putObject(c2t("SCnc"), descriptor3);
    descriptor4.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC19"));
    list.putObject(c2t("SCnc"), descriptor4);
    descriptor5.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC28"));
    list.putObject(c2t("SCnc"), descriptor5);
    descriptor6.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list.putObject(c2t("SCnc"), descriptor6);
    descriptor7.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list.putObject(c2t("SCnc"), descriptor7);
    descriptor8.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list.putObject(c2t("SCnc"), descriptor8);
    descriptor2.putList(c2t("olNC"), list);
    descriptor2.putBoolean(c2t("obIA"), true);
    descriptor2.putString(c2t("obIP"), "");
    descriptor2.putEnumerated(c2t("obCS"), c2t("STcs"), c2t("CS01"));
    descriptor9.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC01"));
    list2.putObject(c2t("SCnc"), descriptor9);
    descriptor10.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC20"));
    list2.putObject(c2t("SCnc"), descriptor10);
    descriptor11.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC02"));
    list2.putObject(c2t("SCnc"), descriptor11);
    descriptor12.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC19"));
    list2.putObject(c2t("SCnc"), descriptor12);
    descriptor13.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC06"));
    list2.putObject(c2t("SCnc"), descriptor13);
    descriptor14.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list2.putObject(c2t("SCnc"), descriptor14);
    descriptor15.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list2.putObject(c2t("SCnc"), descriptor15);
    descriptor16.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC24"));
    list2.putObject(c2t("SCnc"), descriptor16);
    descriptor17.putEnumerated(c2t("ncTp"), c2t("STnc"), c2t("NC22"));
    list2.putObject(c2t("SCnc"), descriptor17);
    descriptor2.putList(c2t("ovNC"), list2);
    descriptor2.putBoolean(c2t("ovCM"), false);
    descriptor2.putBoolean(c2t("ovCW"), false);
    descriptor2.putBoolean(c2t("ovCU"), false);
    descriptor2.putBoolean(c2t("ovSF"), true);
    descriptor2.putBoolean(c2t("ovCB"), true);
    descriptor2.putString(c2t("ovSN"), "images");
    descriptor.putObject(s2t("using"), s2t("SaveForWeb"), descriptor2);
    executeAction(s2t("export"), descriptor, DialogModes.NO);


    // CLOSE THE TEMP WORKING DOC
    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);


    ///// FUNCTIONS /////

    function placeFile(null2, linked, horizontal, vertical) {
        var s2t = function (s) {
            return app.stringIDToTypeID(s);
        };
        var AD = new ActionDescriptor();
        AD.putInteger(s2t("ID"), 1);
        AD.putPath(s2t("null"), null2);
        AD.putBoolean(s2t("linked"), linked); // false for embedded
        AD.putEnumerated(s2t("freeTransformCenterState"), s2t("quadCenterState"), s2t("QCSAverage"));
        AD.putUnitDouble(s2t("horizontal"), s2t("pixelsUnit"), horizontal);
        AD.putUnitDouble(s2t("vertical"), s2t("pixelsUnit"), vertical);
        AD.putObject(s2t("offset"), s2t("offset"), AD);
        executeAction(s2t("placeEvent"), AD, DialogModes.NO);
    }

    function reverseLayerStack() {
        var idreverse = stringIDToTypeID("reverse");
        var desc4653 = new ActionDescriptor();
        var idnull = stringIDToTypeID("null");
        var ref2335 = new ActionReference();
        var idlayer = stringIDToTypeID("layer");
        var idordinal = stringIDToTypeID("ordinal");
        var idtargetEnum = stringIDToTypeID("targetEnum");
        ref2335.putEnumerated(idlayer, idordinal, idtargetEnum);
        desc4653.putReference(idnull, ref2335);
        executeAction(idreverse, desc4653, DialogModes.NO);
    }

}

 

111aaa11Author
Participating Frequently
February 23, 2024

Works flawlessly! If it could save the gifs to the main folder rather than the subfolders that would be really nice (if not no big deal cause adobe bridge exists)


Thank you so much!

Stephen Marsh
Community Expert
Community Expert
February 23, 2024
quote

Works flawlessly! If it could save the gifs to the main folder rather than the subfolders that would be really nice (if not no big deal cause adobe bridge exists)


Thank you so much!


By @111aaa11

 

They should be saving to the main folder!?

 

I selected the main root/parent folder "Animation Root Folder" and the GIF89a files were created in this folder, not in their respective source sub-folders which only contain the PNG files. Screenshot from my Mac:

 

Stephen Marsh
Community Expert
Community Expert
February 22, 2024

@111aaa11 – I believe that I have found workable Windows code for the recursive folder/file selection. I don't know why the code I was using only works on the Mac.

 

Before I incorporate the folder/file processing code, please confirm that the following script works as intended. This code is only for selecting one sub-folder at a time under the root/parent folder.

 

If this works as required, I can add the code to process all top-level sub-folders under a selected root folder.

 

EDIT: Original code updated to 1.1 to correct an oversight where %20 characters were output instead of word spaces in saved filenames.

 

/* 
Create GIF Animation from PNG Files in Selected Folder.jsx
v1.1 - 24th February 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/script-to-generate-gif-from-folder-of-images/td-p/14438104
*/


#target photoshop


// CAPTURE AND SET THE APP PREFS
var savedDisplayDialogs = app.displayDialogs;
app.displayDialogs = DialogModes.NO;
var origUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;


/* HOPEFULLY TO BE REPLACED WITH CODE TO LOOP OVER SUB-FOLDERS UNDER THE ROOT FOLDER */
var inputFolder = Folder.selectDialog('Please select the input folder:');


// STACK THE FILES TO LAYERS
var inputFiles = inputFolder.getFiles(/\.png$/i);
// inputFiles.sort().reverse();
inputFiles.sort();
app.displayDialogs = DialogModes.NO;
var baseDoc = open(inputFiles[0]);
baseDoc = app.activeDocument;
var savePath = baseDoc.path.fsName.replace(/(^.+\/)(.+$)/, '$1');
var saveName = inputFolder.fsName.replace(/(^.+\/)(.+$)/, '$2');
baseDoc.duplicate(saveName, false);
baseDoc.close(SaveOptions.DONOTSAVECHANGES);
for (var i = 0; i < inputFiles.length; i++) {
    // true = linked | false = embedded
    placeFile(new File(inputFiles[i]), false, 0, 0);
    // Remove the filename extension from the layer name
    app.activeDocument.activeLayer.name = inputFiles[i].name.replace(/\.[^\.]+$/, '');
}
// Remove the duplicate base layer
app.activeDocument.layers[app.activeDocument.layers.length - 1].remove();
//app.runMenuItem(stringIDToTypeID("selectAllLayers"));
//reverseLayerStack();
// Reset the app prefs
app.displayDialogs = savedDisplayDialogs;
app.preferences.rulerUnits = origUnits;


// MAKE ANIMATION FRAME
var idmakeFrameAnimation = stringIDToTypeID( "makeFrameAnimation" );
executeAction( idmakeFrameAnimation, undefined, DialogModes.NO );


// MAKE ANIMATION FRAMES FROM LAYERS
var idanimationFramesFromLayers = stringIDToTypeID( "animationFramesFromLayers" );
    var desc203 = new ActionDescriptor();
executeAction( idanimationFramesFromLayers, desc203, DialogModes.NO );


// SELECT ALL ANIMATION FRAMES
var idanimationSelectAll = stringIDToTypeID( "animationSelectAll" );
    var desc208 = new ActionDescriptor();
executeAction(idanimationSelectAll, desc208, DialogModes.NO);


// SET THE ANIMATION FRAME DELAY TO 1 SECOND
var s2t = function (s) {
	return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var reference = new ActionReference();
reference.putEnumerated( s2t( "animationFrameClass" ), s2t( "ordinal" ), s2t( "targetEnum" ));
descriptor.putReference( s2t( "null" ), reference );
descriptor2.putDouble( s2t( "animationFrameDelay" ), 1.000000 );
descriptor.putObject( s2t( "to" ), s2t( "animationFrameClass" ), descriptor2 );
executeAction(s2t( "set" ), descriptor, DialogModes.NO);


// SAVE FOR WEB
var c2t = function (s) {
	return app.charIDToTypeID(s);
};
var s2t = function (s) {
	return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var descriptor2 = new ActionDescriptor();
var descriptor3 = new ActionDescriptor();
var descriptor4 = new ActionDescriptor();
var descriptor5 = new ActionDescriptor();
var descriptor6 = new ActionDescriptor();
var descriptor7 = new ActionDescriptor();
var descriptor8 = new ActionDescriptor();
var descriptor9 = new ActionDescriptor();
var descriptor10 = new ActionDescriptor();
var descriptor11 = new ActionDescriptor();
var descriptor12 = new ActionDescriptor();
var descriptor13 = new ActionDescriptor();
var descriptor14 = new ActionDescriptor();
var descriptor15 = new ActionDescriptor();
var descriptor16 = new ActionDescriptor();
var descriptor17 = new ActionDescriptor();
var list = new ActionList();
var list2 = new ActionList();
descriptor2.putEnumerated( c2t( "Op  " ), c2t( "SWOp" ), c2t( "OpSa" ));
descriptor2.putBoolean( c2t( "DIDr" ), true );
descriptor2.putPath( s2t( "in" ), new File( savePath ) ); // thePath
descriptor2.putString( c2t( "ovFN" ), activeDocument.name + ".gif" ); // theName
descriptor2.putEnumerated( s2t( "format" ), c2t( "IRFm" ), c2t( "GIFf" ));
descriptor2.putBoolean( s2t( "interfaceIconFrameDimmed" ), false );
descriptor2.putEnumerated( c2t( "RedA" ), c2t( "IRRd" ), c2t( "Sltv" ));
descriptor2.putBoolean( c2t( "RChT" ), false );
descriptor2.putBoolean( c2t( "RChV" ), false );
descriptor2.putBoolean( c2t( "AuRd" ), false );
descriptor2.putInteger( c2t( "NCol" ), 256 );
descriptor2.putInteger( c2t( "DChS" ), 0 );
descriptor2.putInteger( c2t( "DCUI" ), 0 );
descriptor2.putBoolean( c2t( "DChT" ), false );
descriptor2.putBoolean( c2t( "DChV" ), false );
descriptor2.putInteger( c2t( "WebS" ), 0 );
descriptor2.putEnumerated( c2t( "TDth" ), c2t( "IRDt" ), s2t( "none" ));
descriptor2.putInteger( c2t( "TDtA" ), 100 );
descriptor2.putInteger( c2t( "Loss" ), 0 );
descriptor2.putInteger( c2t( "LChS" ), 0 );
descriptor2.putInteger( c2t( "LCUI" ), 100 );
descriptor2.putBoolean( c2t( "LChT" ), false );
descriptor2.putBoolean( c2t( "LChV" ), false );
descriptor2.putBoolean( s2t( "transparency" ), true );
descriptor2.putBoolean( c2t( "Mtt " ), true );
descriptor2.putEnumerated( s2t( "dither" ), c2t( "IRDt" ), s2t( "diffusion" ));
descriptor2.putInteger( s2t( "ditherAmount" ), 100 );
descriptor2.putInteger( c2t( "MttR" ), 255 );
descriptor2.putInteger( c2t( "MttG" ), 255 );
descriptor2.putInteger( c2t( "MttB" ), 255 );
descriptor2.putBoolean( c2t( "SHTM" ), false );
descriptor2.putBoolean( c2t( "SImg" ), true );
descriptor2.putEnumerated( c2t( "SWsl" ), c2t( "STsl" ), c2t( "SLAl" ));
descriptor2.putEnumerated( c2t( "SWch" ), c2t( "STch" ), c2t( "CHsR" ));
descriptor2.putEnumerated( c2t( "SWmd" ), c2t( "STmd" ), c2t( "MDNn" ));
descriptor2.putBoolean( c2t( "ohXH" ), false );
descriptor2.putBoolean( c2t( "ohIC" ), true );
descriptor2.putBoolean( c2t( "ohAA" ), true );
descriptor2.putBoolean( c2t( "ohQA" ), true );
descriptor2.putBoolean( c2t( "ohCA" ), false );
descriptor2.putBoolean( c2t( "ohIZ" ), true );
descriptor2.putEnumerated( c2t( "ohTC" ), c2t( "SToc" ), c2t( "OC03" ));
descriptor2.putEnumerated( c2t( "ohAC" ), c2t( "SToc" ), c2t( "OC03" ));
descriptor2.putInteger( c2t( "ohIn" ), -1 );
descriptor2.putEnumerated( c2t( "ohLE" ), c2t( "STle" ), c2t( "LE03" ));
descriptor2.putEnumerated( c2t( "ohEn" ), c2t( "STen" ), c2t( "EN00" ));
descriptor2.putBoolean( c2t( "olCS" ), false );
descriptor2.putEnumerated( c2t( "olEC" ), c2t( "STst" ), c2t( "ST00" ));
descriptor2.putEnumerated( c2t( "olWH" ), c2t( "STwh" ), c2t( "WH01" ));
descriptor2.putEnumerated( c2t( "olSV" ), c2t( "STsp" ), c2t( "SP04" ));
descriptor2.putEnumerated( c2t( "olSH" ), c2t( "STsp" ), c2t( "SP04" ));
descriptor3.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC00" ));
list.putObject( c2t( "SCnc" ), descriptor3 );
descriptor4.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC19" ));
list.putObject( c2t( "SCnc" ), descriptor4 );
descriptor5.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC28" ));
list.putObject( c2t( "SCnc" ), descriptor5 );
descriptor6.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC24" ));
list.putObject( c2t( "SCnc" ), descriptor6 );
descriptor7.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC24" ));
list.putObject( c2t( "SCnc" ), descriptor7 );
descriptor8.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC24" ));
list.putObject( c2t( "SCnc" ), descriptor8 );
descriptor2.putList( c2t( "olNC" ), list );
descriptor2.putBoolean( c2t( "obIA" ), true );
descriptor2.putString( c2t( "obIP" ), "" );
descriptor2.putEnumerated( c2t( "obCS" ), c2t( "STcs" ), c2t( "CS01" ));
descriptor9.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC01" ));
list2.putObject( c2t( "SCnc" ), descriptor9 );
descriptor10.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC20" ));
list2.putObject( c2t( "SCnc" ), descriptor10 );
descriptor11.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC02" ));
list2.putObject( c2t( "SCnc" ), descriptor11 );
descriptor12.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC19" ));
list2.putObject( c2t( "SCnc" ), descriptor12 );
descriptor13.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC06" ));
list2.putObject( c2t( "SCnc" ), descriptor13 );
descriptor14.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC24" ));
list2.putObject( c2t( "SCnc" ), descriptor14 );
descriptor15.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC24" ));
list2.putObject( c2t( "SCnc" ), descriptor15 );
descriptor16.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC24" ));
list2.putObject( c2t( "SCnc" ), descriptor16 );
descriptor17.putEnumerated( c2t( "ncTp" ), c2t( "STnc" ), c2t( "NC22" ));
list2.putObject( c2t( "SCnc" ), descriptor17 );
descriptor2.putList( c2t( "ovNC" ), list2 );
descriptor2.putBoolean( c2t( "ovCM" ), false );
descriptor2.putBoolean( c2t( "ovCW" ), false );
descriptor2.putBoolean( c2t( "ovCU" ), false );
descriptor2.putBoolean( c2t( "ovSF" ), true );
descriptor2.putBoolean( c2t( "ovCB" ), true );
descriptor2.putString( c2t( "ovSN" ), "images" );
descriptor.putObject( s2t( "using" ), s2t( "SaveForWeb" ), descriptor2 );
executeAction(s2t("export"), descriptor, DialogModes.NO);


// CLOSE THE TEMP WORKING DOC
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);


///// FUNCTIONS /////

function placeFile(null2, linked, horizontal, vertical) {
    var s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    var AD = new ActionDescriptor();
    AD.putInteger(s2t("ID"), 1);
    AD.putPath(s2t("null"), null2);
    AD.putBoolean(s2t("linked"), linked); // false for embedded
    AD.putEnumerated(s2t("freeTransformCenterState"), s2t("quadCenterState"), s2t("QCSAverage"));
    AD.putUnitDouble(s2t("horizontal"), s2t("pixelsUnit"), horizontal);
    AD.putUnitDouble(s2t("vertical"), s2t("pixelsUnit"), vertical);
    AD.putObject(s2t("offset"), s2t("offset"), AD);
    executeAction(s2t("placeEvent"), AD, DialogModes.NO);
}

function reverseLayerStack() {
    var idreverse = stringIDToTypeID("reverse");
    var desc4653 = new ActionDescriptor();
    var idnull = stringIDToTypeID("null");
    var ref2335 = new ActionReference();
    var idlayer = stringIDToTypeID("layer");
    var idordinal = stringIDToTypeID("ordinal");
    var idtargetEnum = stringIDToTypeID("targetEnum");
    ref2335.putEnumerated(idlayer, idordinal, idtargetEnum);
    desc4653.putReference(idnull, ref2335);
    executeAction(idreverse, desc4653, DialogModes.NO);
}

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

Participant
February 21, 2024

If you can put all images in a single folder with ordered names, you can use an Action.  The first item in the Action would be the menu item to Load Files Into Stack (under Files > Scripts).  Just point to the image folder and the rest can be automated with the Action.  No need for a new script.

Stephen Marsh
Community Expert
Community Expert
February 21, 2024

@mangurian1 wrote:

If you can put all images in a single folder with ordered names, you can use an Action.  The first item in the Action would be the menu item to Load Files Into Stack (under Files > Scripts).  Just point to the image folder and the rest can be automated with the Action.  No need for a new script.


 

Can you explain how the following requirement would be achieved?

 

quote

itterate through each subfolder, turning it's contents into a gif with the name of the subfolder

 

Participant
February 21, 2024

Read my first sentence carefully.

Stephen Marsh
Community Expert
Community Expert
February 21, 2024

@111aaa11 

 

Please provide a screenshot of the before and after directory structure and filenames. It's unclear if the sub-folder name would be a prefix or suffix.

 

111aaa11Author
Participating Frequently
February 21, 2024

The main folder and subfolders appear like so, https://imgur.com/a/906kxeu

The result would just be a folder containing gifs consprised of the frames found within each subfolder. Framerate, etc doesn't matter as they will be adjusted in the program I will be using these gifs for.

Stephen Marsh
Community Expert
Community Expert
February 21, 2024

You can attach images to your post using the web browser reply (not via email). Just in case the link breaks in the future:

 

 

If I understand your request correctly, a sub-directory name might be:

 

spr_player_mask

 

And it may contain multiple source PNG files, with similar names to:

 

0.png

1.png

2.png

 

And the final result should then be multiple static GIF files with an underscore _ separator using the sub-directory, separator and original image name? Such as:

 

spr_player_mask_0.png

spr_player_mask_1.png

spr_player_mask_2.png

 

Or do you wish to create an animated GIF in a single image file from each PNG frame?

 

What GIF conversion options are required for colour conversion from RGB to Indexed Color mode?