Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
2

Save for Web needs a file size limiter tool that adjusts the dimensions of a GIF.

Explorer ,
Jun 13, 2025 Jun 13, 2025

For social media posts there are file size limits on GIFs. For instance, Facebook is 5MB. I typically will hit this target in the Save for Web panel by adjusting the dimensions of the GIF until the file size is under 5MB. This is a tedious process that can definitely be sped up. I suggest a tool that allows you to input the file size target. It then automatically adjusts the dimensions of the GIF accordingly.

TOPICS
macOS
262
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Jun 13, 2025 Jun 13, 2025

Looks like the Optimise to File Size... feature does work for animated GIF files, however, it has a max limit of 2048K and it doesn't resize the px dimensions:

 

2025-06-14_11-39-55.png

 

A custom script would be required to reduce dimensions to achieve a target size on drive, while retaining your other GIF options such as number of colours, dither etc.

 

EDIT: I have created a "proof of concept" script, it still needs further testing.

Translate
Adobe
Community Expert ,
Jun 13, 2025 Jun 13, 2025

Save for Web (Legacy) already has an option to limit via a target file size, however, I'm not sure if it works with animated GIFs or adjusting the dimensions. This might need to be scripted.

 

Also, as a (Legacy) feature, I wouldn't hold my breath on seeing any new features being added to this old code.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 13, 2025 Jun 13, 2025

Looks like the Optimise to File Size... feature does work for animated GIF files, however, it has a max limit of 2048K and it doesn't resize the px dimensions:

 

2025-06-14_11-39-55.png

 

A custom script would be required to reduce dimensions to achieve a target size on drive, while retaining your other GIF options such as number of colours, dither etc.

 

EDIT: I have created a "proof of concept" script, it still needs further testing.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 27, 2025 Jun 27, 2025
LATEST

Here is the script that I mentioned. Select a target file size between 1-5 MB in half increments and canvas resize in 5% or 10% increments:

 

Export GIF to Target File Size 1 of 2.png

Export GIF to Target File Size 2 of 2.png

/* 
Export GIF to Target File Size.jsx
Stephen Marsh
v1.0 - 14th June 2025
Info: Save the active document as GIF, scaling the canvas size down in 10% increments until the file size on drive is under specified limit
https://community.adobe.com/t5/photoshop-ecosystem-discussions/save-for-web-needs-a-file-size-limiter-tool-that-adjusts-the-dimensions-of-a-gif/td-p/15369326
*/

// Global variables
var theDirPath = "~/Desktop"; // Default directory path
var theDocName = app.activeDocument.name.replace(/\.[^\.]+$/, '');
var theFilePath;
var theScale = 100;
var minScale = 20; // Don't go below 20% scale
var scaleIncrement = 10; // Default scale reduction increment
var maxSize = 5 * 1024 * 1024; // Default 5MB in bytes
var colTableLength = 256; // Default color table length
var colorReductionAlgorithm = stringIDToTypeID("adaptive"); // Adaptive - stringIDToTypeID("adaptive") || Perceptual - charIDToTypeID( "Prcp" )


// Create UI
function createUI() {
    var dialog = new Window("dialog", "Export GIF to Target File Size (v1.0)");
    dialog.orientation = "column";
    dialog.alignChildren = "fill";
    dialog.spacing = 10;
    dialog.margins = 16;

    // Main panel
    var mainPanel = dialog.add("panel", undefined, "Export Settings");
    mainPanel.orientation = "column";
    mainPanel.alignChildren = "fill";
    mainPanel.spacing = 10;
    mainPanel.margins = 16;

    // Directory selection group
    var dirGroup = mainPanel.add("group");
    dirGroup.orientation = "row";
    dirGroup.alignChildren = "center";
    dirGroup.spacing = 10;

    dirGroup.add("statictext", undefined, "Output Directory:");
    var dirDisplay = dirGroup.add("edittext", undefined, theDirPath);
    dirDisplay.preferredSize.width = 300;
    dirDisplay.enabled = false;

    var browseButton = dirGroup.add("button", undefined, "Browse...");
    browseButton.preferredSize.width = 80;

    // File size dropdown group
    var sizeGroup = mainPanel.add("group");
    sizeGroup.orientation = "row";
    sizeGroup.alignChildren = "center";
    sizeGroup.spacing = 10;

    sizeGroup.add("statictext", undefined, "Maximum File Size (MB):");
    var sizeArray = [1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5];
    var sizeDropdown = sizeGroup.add("dropdownlist", undefined, sizeArray);
    sizeDropdown.selection = 8; // Default to 5MB (index 8)
    sizeDropdown.preferredSize.width = 80;

    // Scale increment dropdown group
    var scaleGroup = mainPanel.add("group");
    scaleGroup.orientation = "row";
    scaleGroup.alignChildren = "center";
    scaleGroup.spacing = 10;

    scaleGroup.add("statictext", undefined, "Canvas Scale Reduction:");
    var scaleArray = ["5%", "10%"];
    var scaleDropdown = scaleGroup.add("dropdownlist", undefined, scaleArray);
    scaleDropdown.selection = 1; // Default to 10% (index 1)
    scaleDropdown.preferredSize.width = 80;

    // Button group
    var buttonGroup = dialog.add("group");
    buttonGroup.orientation = "row";
    buttonGroup.alignment = "right";
    buttonGroup.spacing = 10;

    var cancelButton = buttonGroup.add("button", undefined, "Cancel");
    var okButton = buttonGroup.add("button", undefined, "OK");

    // Event handlers
    browseButton.onClick = function () {
        var folder = Folder.selectDialog("Select Output Directory", theDirPath);
        if (folder) {
            theDirPath = folder.fsName;
            dirDisplay.text = theDirPath;
        }
    };

    cancelButton.onClick = function () {
        dialog.close(0);
    };

    okButton.onClick = function () {
        if (sizeDropdown.selection && scaleDropdown.selection) {
            maxSize = sizeDropdown.selection.text * 1024 * 1024; // Convert MB to bytes
            scaleIncrement = parseInt(scaleDropdown.selection.text); // Extract number from "5%" or "10%"
            dialog.close(1);
        } else {
            alert("Please select both maximum file size and scale reduction step.");
        }
    };

    return dialog;
}

(function () {
    try {
        // Check if there's an active document
        if (!app.documents.length) {
            alert("No active document found. Please open a document first.");
            return;
        }

        // Show UI dialog
        var dialog = createUI();
        var result = dialog.show();

        // Exit if user cancelled
        if (result === 0) {
            return;
        }

        // Set the file path
        theFilePath = theDirPath + "/" + theDocName + ".gif";
        var fileObj = new File(theFilePath);

        // Calculate maximum attempts
        var maxAttempts = Math.floor((100 - minScale) / scaleIncrement) + 1;
        var currentAttempt = 1;

        // Create progress window
        var progressWindow = createProgressWindow();

        try {
            // Loop: Save and check file size, reduce scale if needed
            while (true) {
                // Check if user cancelled
                if (progressWindow.isCancelled()) {
                    return;
                }

                // Update progress
                progressWindow.updateProgress(theScale, null, currentAttempt, maxAttempts);

                saveForWebGIF(theDirPath, theFilePath, theScale, theScale);

                // Wait to ensure that the file is written before checking its size
                $.sleep(500);

                fileObj = new File(theFilePath);
                if (fileObj.exists) {
                    fileObj.open("r");
                    var fileSize = fileObj.length;
                    fileObj.close();

                    // Update progress with file size
                    progressWindow.updateProgress(theScale, fileSize, currentAttempt, maxAttempts);

                    if (fileSize <= maxSize) {
                        progressWindow.close();
                        alert("GIF saved under " + (maxSize / 1024 / 1024) + "MB at " + theScale + "% scale. File size: " + (fileSize / 1024).toFixed(2) + " KB");
                        break;
                    } else {
                        theScale -= scaleIncrement;
                        currentAttempt++;
                        if (theScale < minScale) {
                            progressWindow.close();
                            alert("Could not reduce file under " + (maxSize / 1024 / 1024) + "MB even at minimum (" + minScale + "% scale). File size: " + (fileSize / 1024).toFixed(2) + " KB");
                            break;
                        }
                    }
                } else {
                    progressWindow.close();
                    alert("Failed to save GIF file.");
                    break;
                }
            }
        } catch (e) {
            progressWindow.close();
            throw e;
        }
    } catch (e) {
        alert("Error: " + e.message);
    }
})();


///// Functions /////
function saveForWebGIF(outputDirPath, outputDirFilePath, hScale, vScale) {
    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(charIDToTypeID("Op  "), charIDToTypeID("SWOp"), charIDToTypeID("OpSa"));
    descriptor2.putBoolean(charIDToTypeID("DIDr"), true);
    descriptor2.putPath(stringIDToTypeID("in"), new File(outputDirPath));
    descriptor2.putString(stringIDToTypeID("pathName"), outputDirFilePath);
    descriptor2.putEnumerated(stringIDToTypeID("format"), charIDToTypeID("IRFm"), charIDToTypeID("GIFf"));
    descriptor2.putBoolean(stringIDToTypeID("interfaceIconFrameDimmed"), false);
    descriptor2.putEnumerated(charIDToTypeID("RedA"), charIDToTypeID("IRRd"), colorReductionAlgorithm); // Adaptive or Perceptual
    descriptor2.putBoolean(charIDToTypeID("RChT"), false);
    descriptor2.putBoolean(charIDToTypeID("RChV"), false);
    descriptor2.putBoolean(charIDToTypeID("AuRd"), false);
    descriptor2.putInteger(charIDToTypeID("NCol"), colTableLength); // Number of colors in the color table
    descriptor2.putInteger(charIDToTypeID("DChS"), 0);
    descriptor2.putInteger(charIDToTypeID("DCUI"), 0);
    descriptor2.putBoolean(charIDToTypeID("DChT"), false);
    descriptor2.putBoolean(charIDToTypeID("DChV"), false);
    descriptor2.putInteger(charIDToTypeID("WebS"), 0);
    descriptor2.putEnumerated(charIDToTypeID("TDth"), charIDToTypeID("IRDt"), stringIDToTypeID("none"));
    descriptor2.putInteger(charIDToTypeID("TDtA"), 100);
    descriptor2.putInteger(charIDToTypeID("Loss"), 0);
    descriptor2.putInteger(charIDToTypeID("LChS"), 0);
    descriptor2.putInteger(charIDToTypeID("LCUI"), 100);
    descriptor2.putBoolean(charIDToTypeID("LChT"), false);
    descriptor2.putBoolean(charIDToTypeID("LChV"), false);
    descriptor2.putBoolean(stringIDToTypeID("transparency"), true);
    descriptor2.putBoolean(charIDToTypeID("Mtt "), true);
    descriptor2.putEnumerated(stringIDToTypeID("dither"), charIDToTypeID("IRDt"), stringIDToTypeID("diffusion"));
    descriptor2.putInteger(stringIDToTypeID("ditherAmount"), 100);
    descriptor2.putInteger(charIDToTypeID("MttR"), 255);
    descriptor2.putInteger(charIDToTypeID("MttG"), 255);
    descriptor2.putInteger(charIDToTypeID("MttB"), 255);
    descriptor2.putUnitDouble(charIDToTypeID("HScl"), stringIDToTypeID("percentUnit"), hScale);
    descriptor2.putUnitDouble(charIDToTypeID("VScl"), stringIDToTypeID("percentUnit"), vScale);
    descriptor2.putBoolean(charIDToTypeID("SHTM"), false);
    descriptor2.putBoolean(charIDToTypeID("SImg"), true);
    descriptor2.putEnumerated(charIDToTypeID("SWsl"), charIDToTypeID("STsl"), charIDToTypeID("SLAl"));
    descriptor2.putEnumerated(charIDToTypeID("SWch"), charIDToTypeID("STch"), charIDToTypeID("CHsR"));
    descriptor2.putEnumerated(charIDToTypeID("SWmd"), charIDToTypeID("STmd"), charIDToTypeID("MDNn")); // "MDNn" for no metadata | "MDAl" for all metadata
    descriptor2.putBoolean(charIDToTypeID("ohXH"), false);
    descriptor2.putBoolean(charIDToTypeID("ohIC"), true);
    descriptor2.putBoolean(charIDToTypeID("ohAA"), true);
    descriptor2.putBoolean(charIDToTypeID("ohQA"), true);
    descriptor2.putBoolean(charIDToTypeID("ohCA"), false);
    descriptor2.putBoolean(charIDToTypeID("ohIZ"), true);
    descriptor2.putEnumerated(charIDToTypeID("ohTC"), charIDToTypeID("SToc"), charIDToTypeID("OC03"));
    descriptor2.putEnumerated(charIDToTypeID("ohAC"), charIDToTypeID("SToc"), charIDToTypeID("OC03"));
    descriptor2.putInteger(charIDToTypeID("ohIn"), -1);
    descriptor2.putEnumerated(charIDToTypeID("ohLE"), charIDToTypeID("STle"), charIDToTypeID("LE03"));
    descriptor2.putEnumerated(charIDToTypeID("ohEn"), charIDToTypeID("STen"), charIDToTypeID("EN00"));
    descriptor2.putBoolean(charIDToTypeID("olCS"), false);
    descriptor2.putEnumerated(charIDToTypeID("olEC"), charIDToTypeID("STst"), charIDToTypeID("ST00"));
    descriptor2.putEnumerated(charIDToTypeID("olWH"), charIDToTypeID("STwh"), charIDToTypeID("WH01"));
    descriptor2.putEnumerated(charIDToTypeID("olSV"), charIDToTypeID("STsp"), charIDToTypeID("SP04"));
    descriptor2.putEnumerated(charIDToTypeID("olSH"), charIDToTypeID("STsp"), charIDToTypeID("SP04"));
    descriptor3.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC00"));
    list.putObject(charIDToTypeID("SCnc"), descriptor3);
    descriptor4.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC19"));
    list.putObject(charIDToTypeID("SCnc"), descriptor4);
    descriptor5.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC28"));
    list.putObject(charIDToTypeID("SCnc"), descriptor5);
    descriptor6.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC24"));
    list.putObject(charIDToTypeID("SCnc"), descriptor6);
    descriptor7.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC24"));
    list.putObject(charIDToTypeID("SCnc"), descriptor7);
    descriptor8.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC24"));
    list.putObject(charIDToTypeID("SCnc"), descriptor8);
    descriptor2.putList(charIDToTypeID("olNC"), list);
    descriptor2.putBoolean(charIDToTypeID("obIA"), true);
    descriptor2.putString(charIDToTypeID("obIP"), "");
    descriptor2.putEnumerated(charIDToTypeID("obCS"), charIDToTypeID("STcs"), charIDToTypeID("CS01"));
    descriptor9.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC01"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor9);
    descriptor10.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC20"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor10);
    descriptor11.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC02"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor11);
    descriptor12.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC19"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor12);
    descriptor13.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC06"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor13);
    descriptor14.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC24"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor14);
    descriptor15.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC24"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor15);
    descriptor16.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC24"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor16);
    descriptor17.putEnumerated(charIDToTypeID("ncTp"), charIDToTypeID("STnc"), charIDToTypeID("NC22"));
    list2.putObject(charIDToTypeID("SCnc"), descriptor17);
    descriptor2.putList(charIDToTypeID("ovNC"), list2);
    descriptor2.putBoolean(charIDToTypeID("ovCM"), false);
    descriptor2.putBoolean(charIDToTypeID("ovCW"), false);
    descriptor2.putBoolean(charIDToTypeID("ovCU"), false);
    descriptor2.putBoolean(charIDToTypeID("ovSF"), true);
    descriptor2.putBoolean(charIDToTypeID("ovCB"), true);
    descriptor2.putString(charIDToTypeID("ovSN"), "images");
    descriptor.putObject(stringIDToTypeID("using"), stringIDToTypeID("SaveForWeb"), descriptor2);
    executeAction(stringIDToTypeID("export"), descriptor, DialogModes.NO);
}

function createProgressWindow() {
    var progressWindow = new Window("window", "Exporting GIF...");
    progressWindow.orientation = "column";
    progressWindow.alignChildren = "fill";
    progressWindow.spacing = 10;
    progressWindow.margins = 16;
    progressWindow.preferredSize.width = 400;

    // Status text
    var statusText = progressWindow.add("statictext", undefined, "Initializing export...");
    statusText.preferredSize.width = 380;

    // Progress bar
    var progressBar = progressWindow.add("progressbar", undefined, 0, 100);
    progressBar.preferredSize.width = 380;
    progressBar.preferredSize.height = 10;

    // Scale and file size info
    var scaleText = progressWindow.add("statictext", undefined, "Scale: 100%");
    var sizeText = progressWindow.add("statictext", undefined, "File size: Calculating...");

    // Cancel button
    var buttonGroup = progressWindow.add("group");
    buttonGroup.alignment = "center";
    var cancelButton = buttonGroup.add("button", undefined, "Cancel");

    var cancelled = false;
    cancelButton.onClick = function () {
        cancelled = true;
        progressWindow.close();
    };

    progressWindow.show();

    return {
        window: progressWindow,
        statusText: statusText,
        progressBar: progressBar,
        scaleText: scaleText,
        sizeText: sizeText,
        isCancelled: function () { return cancelled; },
        updateProgress: function (scale, fileSize, attempt, maxAttempts) {
            if (cancelled) return;

            var progress = ((100 - scale + 10) / (100 - minScale + 10)) * 100;
            this.progressBar.value = Math.min(progress, 100);

            this.statusText.text = "Attempt " + attempt + " of " + maxAttempts + " - Testing scale " + scale + "%";
            this.scaleText.text = "Scale: " + scale + "%";

            if (fileSize) {
                var sizeMB = (fileSize / 1024 / 1024).toFixed(2);
                var targetMB = (maxSize / 1024 / 1024).toFixed(1);
                this.sizeText.text = "File size: " + sizeMB + "MB (Target: <" + targetMB + "MB)";
            }

            this.window.update();
        },
        close: function () {
            this.window.close();
        }
    };
}

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 19, 2025 Jun 19, 2025

@Josh32367144i052 

 

Are you still out there?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 19, 2025 Jun 19, 2025

I find this very amusing - welcome to my life in 1997 when I had to make animated banner ads that had to be less than 10k. You need to old school it to get those files sizes down - reduce the number of colors, the dithering makes the file size larger, etc. We didnt have fancy tools to help us back then. Sounds like Stephen has some better ideas. 

Melissa Piccone | Adobe Trainer | Online Courses Author | Fine Artist
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 21, 2025 Jun 21, 2025

@melissapiccone 

 

Having gone through things the hard way with banner ads and restricitve specs back in the late 90's, you have a great grounding!

 

I'm guessing that in this case @Josh32367144i052 is just wanting to upload a long "animated gif silent video" which is why there is a 5mb limit and the pixel dimensions are irrelevant.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines