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

Exporting artboards to webp format?

Community Beginner ,
May 11, 2022 May 11, 2022

Great that the latest Photoshop has "full" webp support, but lacking is the ability to export artboards to webp format. I build a lot of my website graphics as artboards, but it looks like I will need an intermediary step of saving the artboards as PSD files first, and then exporting them as webp? Or am I missing something?

 

Thanks,

 

Judi

TOPICS
Windows
24.2K
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 2 Correct answers

Community Beginner , Jun 12, 2022 Jun 12, 2022

@Stephen Marsh Solved! Your script works perfectly. The problem was that I had the "Open As Layer" event running in the Script Events Manager. Turning that off solved the errors I was getting, plus a whole heap of other stuff relating to exporting artboards. I rely hugely on Open As Layer to help document my compositing workflow, but hadn't connected the dots to its impact on other scripts. But it's easy to toggle the event on and off as needed. Thank you so much for all your help on this, and f

...
Translate
Community Expert , Jul 26, 2025 Jul 26, 2025

Here is the 2.1 script version:

 

Artboards-to-WEBP-PS2025-scriptUI-GUI-v2-1.png

 

* Batch Output to WebP - Automatically saves all your artboards to WebP format in one go, saving you from the tedious process of saving each artboard individually

 

* Dual Format Support - Can export both WebP and JPEG versions simultaneously, so you get modern WebP files for performance plus JPEG fallbacks for compatibility

 

* Flexible Compression Options - Choose between lossy and lossless WebP compression with a quality slider (0-100), giving you control

...
Translate
Adobe
Community Expert ,
May 11, 2022 May 11, 2022

@Art by JLM – The Artboards to Files JavaScript files would need to be updated to support another format.

 

EDIT: If you make a new post as an "Idea" I would upvote it to add webp support, this is something that should be shipping as standard with the software, IMO.

 

As this is a script, any user with the knowledge and time could update it to include webp, however, it is often easier said than done for the complex scripts that ship with Photoshop.

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 ,
May 13, 2022 May 13, 2022

@Art by JLM 

 

You can try this script to save the current open doc's artboards to WebP lossy 100% quality using the doc name + artboard name:

 

/*
Artboards-to-WEBP-PS2022.jsx
14th May 2022, v1.1 - Stephen Marsh

* Only for Photoshop 2022 (v23.x.x) or later!
* Saves artboards as lossy WebP - Quality: 100
* Prompts for a save location and saves using the filename + artboard name
* Existing files will be silently overwritten

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

// Original script author below:

// =========================================================================
// artboardsToPNG.jsx - Adobe Photoshop Script
// Version: 0.6.0
// Requirements: Adobe Photoshop CC 2015, or higher
// Author: Anton Lyubushkin (nvkz.nemo@gmail.com)
// Website: http://lyubushkin.pro/
// =========================================================================

#target photoshop

app.bringToFront();

// Ensure that version 2022 or later is being used
var versionNumber = app.version.split(".");
var versionCheck = parseInt(versionNumber);
if (versionCheck < 23) {
    alert("You must use Photoshop 2022 or later to save using native WebP format...");

} else {
    if (app.documents.length !== 0) {

        var docRef = app.activeDocument,
            allArtboards,
            artboardsCount = 0,
            inputFolder = Folder.selectDialog("Select an output folder to save the artboards as WebP:");

        if (inputFolder) {
            function getAllArtboards() {
                try {
                    var ab = [];
                    var theRef = new ActionReference();
                    theRef.putProperty(charIDToTypeID('Prpr'), stringIDToTypeID("artboards"));
                    theRef.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
                    var getDescriptor = new ActionDescriptor();
                    getDescriptor.putReference(stringIDToTypeID("null"), theRef);
                    var abDesc = executeAction(charIDToTypeID("getd"), getDescriptor, DialogModes.NO).getObjectValue(stringIDToTypeID("artboards"));
                    var abCount = abDesc.getList(stringIDToTypeID('list')).count;
                    if (abCount > 0) {
                        for (var i = 0; i < abCount; ++i) {
                            var abObj = abDesc.getList(stringIDToTypeID('list')).getObjectValue(i);
                            var abTopIndex = abObj.getInteger(stringIDToTypeID("top"));
                            ab.push(abTopIndex);

                        }
                    }
                    return [abCount, ab];
                } catch (e) {
                    alert(e.line + '\n' + e.message);
                }
            }

            function selectLayerByIndex(index, add) {
                add = undefined ? add = false : add
                var ref = new ActionReference();
                ref.putIndex(charIDToTypeID("Lyr "), index + 1);
                var desc = new ActionDescriptor();
                desc.putReference(charIDToTypeID("null"), ref);
                if (add) desc.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
                desc.putBoolean(charIDToTypeID("MkVs"), false);
                executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
            }

            function ungroupLayers() {
                var desc1 = new ActionDescriptor();
                var ref1 = new ActionReference();
                ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
                desc1.putReference(charIDToTypeID('null'), ref1);
                executeAction(stringIDToTypeID('ungroupLayersEvent'), desc1, DialogModes.NO);
            }

            function crop() {
                var desc1 = new ActionDescriptor();
                desc1.putBoolean(charIDToTypeID('Dlt '), true);
                executeAction(charIDToTypeID('Crop'), desc1, DialogModes.NO);
            }

            function saveAsWebP(_name) {
                var s2t = function (s) {
                    return app.stringIDToTypeID(s);
                };
                var descriptor = new ActionDescriptor();
                var descriptor2 = new ActionDescriptor();
                descriptor2.putEnumerated(s2t("compression"), s2t("WebPCompression"), s2t("compressionLossy"));
                descriptor2.putInteger(s2t("quality"), 100);
                descriptor2.putBoolean(s2t("includeXMPData"), true);
                descriptor2.putBoolean(s2t("includeEXIFData"), true);
                descriptor2.putBoolean(s2t("includePsExtras"), true);
                descriptor.putObject(s2t("as"), s2t("WebPFormat"), descriptor2);
                descriptor.putPath(s2t("in"), new File(inputFolder + '/' + _name + '.webp'), true);
                descriptor.putInteger(s2t("documentID"), 237);
                descriptor.putBoolean(s2t("lowerCase"), true);
                descriptor.putEnumerated(s2t("saveStage"), s2t("saveStageType"), s2t("saveSucceeded"));
                executeAction(s2t("save"), descriptor, DialogModes.NO);
            }

            function main(i) {
                selectLayerByIndex(allArtboards[1][i]);
                // RegEx remove filename extension
                var docName = app.activeDocument.name.replace(/\.[^\.]+$/, '');
                // RegEx replace illegal filename characters with a hyphen
                var artboardName = docName + " - " + app.activeDocument.activeLayer.name.replace(/[:\/\\*\?\"\<\>\|\\\r\\\n.]/g, "-"); // "/\:*?"<>|\r\n" -> "-"
                    
                executeAction(stringIDToTypeID("newPlacedLayer"), undefined, DialogModes.NO);
                executeAction(stringIDToTypeID("placedLayerEditContents"), undefined, DialogModes.NO);
                app.activeDocument.selection.selectAll();
                try {
                    ungroupLayers();
                } catch (e) {
                    alert("There was an unexpected error with the ungroupLayers function!")
                    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                }
                crop();
                saveAsWebP(artboardName);
                app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
            }

            allArtboards = getAllArtboards();

            artboardsCount = allArtboards[0];

            for (var i = 0; i < artboardsCount; i++) {
                docRef.suspendHistory('Artboards to WebP', 'main(' + i + ')');
                app.refresh();
                app.activeDocument.activeHistoryState = app.activeDocument.historyStates[app.activeDocument.historyStates.length - 2];
            }
        }

        app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
        alert('WebP files saved to: ' + '\r' + inputFolder.fsName);
        // inputFolder.execute();

    } else {
        alert('You must have a document open!');
    }
}

 

Quickstart instructions for saving and running:

  1. Copy the code text to the clipboard
  2. Open a new blank file in a plain-text editor (not in a word processor)
  3. Paste the code in
  4. Save the text file as .txt
  5. Rename the file extension from .txt to .jsx
  6. Install or browse to the .jsx file to run (see below):

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

 

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 Beginner ,
May 13, 2022 May 13, 2022

Wow thank you for the script! I got it installed without problem, but when I run it, I get this error when the first psb file (generated from the first artboard) is created. I'm running the latest PS.

ArtbyJLM_0-1652501789527.png

I tried again with another document with multiple artboards with the same result. I then created a very basic doc with 2 artboards with just one simple layer on each (no linked files, no smart objects), with the same error.

 

Hopefully it's something obvious - is perhaps the ungroupLayersEvent a script I need to install too?

 

Judi

 

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 ,
May 13, 2022 May 13, 2022

I obviously don't get that error... I'm on version 23.3.1 on Mac 11.6.5 (Big Sur).

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 ,
May 13, 2022 May 13, 2022

Hi again Judi,

 

Please try this 1.4 version, I have replaced the function with a different way to call the same code.

 

/*
Artboards-to-WEBP-PS2022.jsx
14th May 2022, v1.4 - Stephen Marsh

* Only for Photoshop 2022 (v23.x.x) or later!
* Saves artboards as lossy WebP - Quality: 100
* Prompts for a save location and saves using the filename + artboard name
* Existing files will be silently overwritten

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

// Original script author below:

// =========================================================================
// artboardsToPNG.jsx - Adobe Photoshop Script
// Version: 0.6.0
// Requirements: Adobe Photoshop CC 2015, or higher
// Author: Anton Lyubushkin (nvkz.nemo@gmail.com)
// Website: http://lyubushkin.pro/
// =========================================================================

#target photoshop

app.bringToFront();

// Ensure that version 2022 or later is being used
var versionNumber = app.version.split(".");
var versionCheck = parseInt(versionNumber);
if (versionCheck < 23) {
    alert("You must use Photoshop 2022 or later to save using native WebP format...");

} else {
    if (app.documents.length !== 0) {

        var docRef = app.activeDocument,
            allArtboards,
            artboardsCount = 0,
            inputFolder = Folder.selectDialog("Select an output folder to save the artboards as WebP:");

        if (inputFolder) {
            function getAllArtboards() {
                try {
                    var ab = [];
                    var theRef = new ActionReference();
                    theRef.putProperty(charIDToTypeID('Prpr'), stringIDToTypeID("artboards"));
                    theRef.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
                    var getDescriptor = new ActionDescriptor();
                    getDescriptor.putReference(stringIDToTypeID("null"), theRef);
                    var abDesc = executeAction(charIDToTypeID("getd"), getDescriptor, DialogModes.NO).getObjectValue(stringIDToTypeID("artboards"));
                    var abCount = abDesc.getList(stringIDToTypeID('list')).count;
                    if (abCount > 0) {
                        for (var i = 0; i < abCount; ++i) {
                            var abObj = abDesc.getList(stringIDToTypeID('list')).getObjectValue(i);
                            var abTopIndex = abObj.getInteger(stringIDToTypeID("top"));
                            ab.push(abTopIndex);

                        }
                    }
                    return [abCount, ab];
                } catch (e) {
                    alert(e.line + '\n' + e.message);
                }
            }

            function selectLayerByIndex(index, add) {
                add = undefined ? add = false : add
                var ref = new ActionReference();
                ref.putIndex(charIDToTypeID("Lyr "), index + 1);
                var desc = new ActionDescriptor();
                desc.putReference(charIDToTypeID("null"), ref);
                if (add) desc.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
                desc.putBoolean(charIDToTypeID("MkVs"), false);
                executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
            }

            function ungroupLayers() {
                app.runMenuItem(stringIDToTypeID('ungroupLayersEvent'));
            }

            function crop() {
                var desc1 = new ActionDescriptor();
                desc1.putBoolean(charIDToTypeID('Dlt '), true);
                executeAction(charIDToTypeID('Crop'), desc1, DialogModes.NO);
            }

            function saveAsWebP(_name) {
                var s2t = function (s) {
                    return app.stringIDToTypeID(s);
                };
                var descriptor = new ActionDescriptor();
                var descriptor2 = new ActionDescriptor();
                descriptor2.putEnumerated(s2t("compression"), s2t("WebPCompression"), s2t("compressionLossy"));
                descriptor2.putInteger(s2t("quality"), 100);
                descriptor2.putBoolean(s2t("includeXMPData"), true);
                descriptor2.putBoolean(s2t("includeEXIFData"), true);
                descriptor2.putBoolean(s2t("includePsExtras"), true);
                descriptor.putObject(s2t("as"), s2t("WebPFormat"), descriptor2);
                descriptor.putPath(s2t("in"), new File(inputFolder + '/' + _name + '.webp'), true);
                descriptor.putInteger(s2t("documentID"), 237);
                descriptor.putBoolean(s2t("lowerCase"), true);
                descriptor.putEnumerated(s2t("saveStage"), s2t("saveStageType"), s2t("saveSucceeded"));
                executeAction(s2t("save"), descriptor, DialogModes.NO);
            }

            function main(i) {
                selectLayerByIndex(allArtboards[1][i]);
                // RegEx remove filename extension
                var docName = app.activeDocument.name.replace(/\.[^\.]+$/, '');
                // RegEx replace illegal filename characters with a hyphen
                var artboardName = docName + " - " + app.activeDocument.activeLayer.name.replace(/[:\/\\*\?\"\<\>\|\\\r\\\n.]/g, "-"); // "/\:*?"<>|\r\n" -> "-"

                executeAction(stringIDToTypeID("newPlacedLayer"), undefined, DialogModes.NO);
                executeAction(stringIDToTypeID("placedLayerEditContents"), undefined, DialogModes.NO);
                app.activeDocument.selection.selectAll();
                try {
                    ungroupLayers();
                } catch (e) {
                    alert("There was an unexpected error with the ungroupLayers function!")
                    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                }
                crop();
                saveAsWebP(artboardName);
                app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
            }

            allArtboards = getAllArtboards();

            artboardsCount = allArtboards[0];

            for (var i = 0; i < artboardsCount; i++) {
                docRef.suspendHistory('Artboards to WebP', 'main(' + i + ')');
                app.refresh();
                app.activeDocument.activeHistoryState = app.activeDocument.historyStates[app.activeDocument.historyStates.length - 2];
            }
        }

        app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
        alert('WebP files saved to: ' + '\r' + inputFolder.fsName);
        // inputFolder.execute();

    } else {
        alert('You must have a document open!');
    }
}

 

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 Beginner ,
May 13, 2022 May 13, 2022

Kia ora Stephen

(I'm on Windows 10 running PS 23.2.2)

This time I get this "helpful" error and the script hangs. 

ArtbyJLM_0-1652504791120.png

The first webp file is created (woohoo!), but not the second, and you can see how the first Artboard is still a smart object.

ArtbyJLM_1-1652504897851.png

Ngā mihi nui,

Judi

 

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 ,
May 13, 2022 May 13, 2022

G'day!

 

You'll need to close the PSD without saving changes.

 

Looks like I'll need to test on Windows...

 

@Art by JLM – EDIT:

 

The previous code ran fine for me in Windows 10/Photoshop 2022.

 

I have updated the code to a 1.3 version using the ungroup code from Windows, which I believe is the same.

 

After that I'm out of ideas, perhaps another scripting person will have a suggestion.

 

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 ,
May 13, 2022 May 13, 2022

@Art by JLM 

 

My last-ditch final attempt v1.4 code posted above... I can't reproduce your issues in Windows it all just works!

 

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 Beginner ,
May 14, 2022 May 14, 2022

really appreciate your efforts! v1.4 results in 

ArtbyJLM_0-1652511514105.png

then the "unexpected error". If I continue, it results in a single webp file with both artboards and the PSD file closes.

 

Tomorrow I'll take a look at the code and see what I can figure out. I will also consult with the java expert in the household 🙂

 

Kind regards,

 

Judi

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
New Here ,
Sep 23, 2022 Sep 23, 2022

Hi @Stephen Marsh ,

thanks for your script ! I have tried the 1.4 version.

I had also the error The command "Select" is not currently available, then "The was an unexpected error with yhe ungroupLayers function!" and finally the alert in attachment. In my case I had an empty artboard. I've added a solid-color fill layer and it solved !

Thanks,

Raphaël

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 Beginner ,
Jul 18, 2025 Jul 18, 2025

@Stephen Marsh You are amazing. Is there any way to update the script to save @2x scale as well? Yours is the only one I can get to work reliably (vs. chat gpt) but I need to export 2x larger and am not savvy enough to know where/how to insert that into the script. If possible, thank you in advance!!

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 ,
Jul 18, 2025 Jul 18, 2025

@raven250 

 

As I review this old  topic thread, I can see that there were various user issues and feature requests. I think that the script was last at v1.6.

 

Which version number and date is in the header of the script that you would like the x2 sizing option added?

 

Additionally, what resizing interpolation algorithm should be used for the 200% enlargement?

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 Beginner ,
Jul 21, 2025 Jul 21, 2025

@Stephen Marsh  Apologies for not replying to the latest version! I tried several of them. Just confirmed this morning that this one below worked. Though your post date was June 28, 2023, yet the revision noted was 1.8 from June 18, 2024. 

Re: the interpolation, I think bilinear interpolation would be what's needed (based on doing some online digging)? I also see that for Photoshop, Bicubic Smoother could be an option: since this option is specifically designed for enlarging images. This can also be a good choice as it provides even smoother results than standard bicubic interpolation.

I'm not sure what your code limitations are. 

------

 

Community Expert ,
Jun 28, 2023

@alexandrum2701 

 

I forgot to reply/update, here is a new 1.6 version that converts to sRGB if the mode isn't RGB:

 

/*
Artboards-to-WEBP-PS2022.jsx
18th June 2024, v1.8 - Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/exporting-artboards-to-webp-format/td-p/12937135

* Only for Photoshop 2022 (v23.x.x) or later!
* Saves artboards as lossy WebP - Quality: 100
* Prompts for a save location and prompts for a prefix to be added to the artboard name (uses the doc name by default)
* Existing files will be silently overwritten
* Converts non-RGB to sRGB color space, RGB color mode and 8 bpc
* If RGB the original color space is retained, beware if using ProPhoto RGB!
* Added a "script running" window to provide feedback during the script execution
* Creates a temporary working document

Instructions for saving and installing:
https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html
*/
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 Beginner ,
Jul 21, 2025 Jul 21, 2025

Also, @Stephen Marsh  here's the link to your reply with that 1.8 (or 1.6?) version. Sorry, I just realized I could click the date to copy the link. https://community.adobe.com/t5/photoshop-ecosystem-discussions/exporting-artboards-to-webp-format/m-...

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 ,
Jul 21, 2025 Jul 21, 2025

@raven250 

 

Ah, yes, my forum comment was for v1.6, however, the latest code header was for 1.8, I see how I became confused and have now updated the comment.

 

I think Bicubic Smoother is the right choice for upscale with brief comparisions against Export As.

 

Try this v1.9 code below for x2 scale. Use the old v1.8 for 100% size.

 

I can't test it properly now due to errors reported in later versions that were not triggered back in the earlier versions of Photoshop. I think that the code needs a major overhaul and rewrite adding various options in a single script interface.

 

/*
Artboards-to-WEBP-PS2022.jsx
v1.9, 22nd July 2025 - Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/exporting-artboards-to-webp-format/td-p/12937135

* Only for Photoshop 2022 (v23.x.x) or later!
* Saves artboards as lossy WebP - Quality: 100
* Prompts for a save location and prompts for a prefix to be added to the artboard name (uses the doc name by default)
* Existing files will be silently overwritten
* Converts non-RGB to sRGB color space, RGB color mode and 8 bpc
* If RGB the original color space is retained, beware if using ProPhoto RGB!
* Added a "script running" window to provide feedback during the script execution
* Creates a temporary working document
* Resizes the (document) artboards to 200% of their original size

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

// =========================================================================
// Original script author:
// artboardsToPNG.jsx - Adobe Photoshop Script
// Version: 0.6.0
// Requirements: Adobe Photoshop CC 2015, or higher
// Author: Anton Lyubushkin (nvkz.nemo@gmail.com)
// Website: http://lyubushkin.pro/
// =========================================================================

#target photoshop

    (function () {

        app.bringToFront();

        // Ensure that version 2022 or later is being used
        var versionNumber = app.version.split(".");
        var versionCheck = parseInt(versionNumber);
        if (versionCheck < 23) {
            alert("You must use Photoshop 2022 or later to save using native WebP format...");

        } else {
            if (app.documents.length !== 0) {

                var docRef = app.activeDocument,
                    allArtboards,
                    artboardsCount = 0;

                var outputFolder = Folder.selectDialog("Select an output folder to save the artboards as WebP:");
                // Test if Cancel button returns null, then do nothing
                if (outputFolder === null) {
                    app.beep();
                    return;
                }

                var preFix = prompt("Add the prefix including separator character to the artboard name:", docRef.name.replace(/\.[^\.]+$/, '') + "_");
                // Test if Cancel button returns null, then do nothing
                if (preFix === null) {
                    app.beep();
                    return;
                }

                // Hide the Photoshop panels
                app.togglePalettes();

                if (outputFolder) {

                    // Dupe to a temp doc
                    app.activeDocument.duplicate(app.activeDocument.name.replace(/\.[^\.]+$/, ''), false);

                    // Clean out unwanted metadata
                    deleteDocumentAncestorsMetadata();
                    removeCRSmeta();

                    // If the doc isn't in RGB mode
                    if (activeDocument.mode !== DocumentMode.RGB)
                        // Convert to sRGB
                        activeDocument.convertProfile("sRGB IEC61966-2.1", Intent.RELATIVECOLORIMETRIC, true, false);
                    // Ensure that the doc mode is RGB (to correctly handle Indexed Color mode)
                    activeDocument.changeMode(ChangeMode.RGB);
                    activeDocument.bitsPerChannel = BitsPerChannelType.EIGHT;

                    // 2x Resize
                    imageSize(200, true, true);

                    allArtboards = getAllArtboards();
                    artboardsCount = allArtboards[0];

                    // Loop over the artboards and run the main function
                    for (var i = 0; i < artboardsCount; i++) {

                        // Script running notification window - courtesy of William Campbell
                        // https://www.marspremedia.com/download?asset=adobe-script-tutorial-11.zip
                        // https://youtu.be/JXPeLi6uPv4?si=Qx0OVNLAOzDrYPB4
                        var working;
                        working = new Window("palette");
                        working.preferredSize = [300, 80];
                        working.add("statictext");
                        working.t = working.add("statictext");
                        working.add("statictext");
                        working.display = function (message) {
                            this.t.text = message || "Script running, please wait...";
                            this.show();
                            app.refresh();
                        };
                        working.display();

                        // Call the main function
                        docRef.suspendHistory('Artboards to WebP', 'main(' + i + ')');
                        app.refresh();
                        app.activeDocument.activeHistoryState = app.activeDocument.historyStates[app.activeDocument.historyStates.length - 2];

                        // Ensure Photoshop has focus before closing the running script notification window
                        app.bringToFront();
                        working.close();
                    }
                }

                app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

                // Restore the Photoshop panels
                app.togglePalettes();

                // End of script notification
                app.beep();
                alert(artboardsCount + ' WebP files saved to: ' + '\r' + outputFolder.fsName);

                // Open the output folder in Windows Explorer or the Mac Finder
                // outputFolder.execute();


                ///// FUNCTIONS /////

                function getAllArtboards() {
                    try {
                        var ab = [];
                        var theRef = new ActionReference();
                        theRef.putProperty(charIDToTypeID('Prpr'), stringIDToTypeID("artboards"));
                        theRef.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
                        var getDescriptor = new ActionDescriptor();
                        getDescriptor.putReference(stringIDToTypeID("null"), theRef);
                        var abDesc = executeAction(charIDToTypeID("getd"), getDescriptor, DialogModes.NO).getObjectValue(stringIDToTypeID("artboards"));
                        var abCount = abDesc.getList(stringIDToTypeID('list')).count;
                        if (abCount > 0) {
                            for (var i = 0; i < abCount; ++i) {
                                var abObj = abDesc.getList(stringIDToTypeID('list')).getObjectValue(i);
                                var abTopIndex = abObj.getInteger(stringIDToTypeID("top"));
                                ab.push(abTopIndex);

                            }
                        }
                        return [abCount, ab];
                    } catch (e) {
                        alert(e.line + '\n' + e.message);
                    }
                }

                function selectLayerByIndex(index, add) {
                    add = undefined ? add = false : add;
                    var ref = new ActionReference();
                    ref.putIndex(charIDToTypeID("Lyr "), index + 1);
                    var desc = new ActionDescriptor();
                    desc.putReference(charIDToTypeID("null"), ref);
                    if (add) desc.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
                    desc.putBoolean(charIDToTypeID("MkVs"), false);
                    executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
                }

                function ungroupLayers() {
                    app.runMenuItem(stringIDToTypeID('ungroupLayersEvent'));
                }

                function crop() {
                    var desc1 = new ActionDescriptor();
                    desc1.putBoolean(charIDToTypeID('Dlt '), true);
                    executeAction(charIDToTypeID('Crop'), desc1, DialogModes.NO);
                }

                function saveAsWebP(_name) {
                    var s2t = function (s) {
                        return app.stringIDToTypeID(s);
                    };
                    var descriptor = new ActionDescriptor();
                    var descriptor2 = new ActionDescriptor();
                    descriptor2.putEnumerated(s2t("compression"), s2t("WebPCompression"), s2t("compressionLossy"));
                    descriptor2.putInteger(s2t("quality"), 100);
                    descriptor2.putBoolean(s2t("includeXMPData"), true);
                    descriptor2.putBoolean(s2t("includeEXIFData"), true);
                    descriptor2.putBoolean(s2t("includePsExtras"), true);
                    descriptor.putObject(s2t("as"), s2t("WebPFormat"), descriptor2);
                    descriptor.putPath(s2t("in"), new File(outputFolder + '/' + _name + '.webp'), true);
                    descriptor.putBoolean(s2t("lowerCase"), true);
                    descriptor.putEnumerated(s2t("saveStage"), s2t("saveStageType"), s2t("saveSucceeded"));
                    executeAction(s2t("save"), descriptor, DialogModes.NO);
                }

                // The main working function
                function main(i) {

                    selectLayerByIndex(allArtboards[1][i]);
                    // RegEx replace illegal filename characters with a hyphen
                    var artboardName = preFix + app.activeDocument.activeLayer.name.replace(/[:\/\\*\?\"\<\>\|\\\r\\\n.]/g, "_"); // "/\:*?"<>|\r\n" -> "-"

                    executeAction(stringIDToTypeID("newPlacedLayer"), undefined, DialogModes.NO);
                    executeAction(stringIDToTypeID("placedLayerEditContents"), undefined, DialogModes.NO);
                    app.activeDocument.selection.selectAll();
                    try {
                        ungroupLayers();
                    } catch (e) {
                        alert("There was an unexpected error with the ungroupLayers function!");
                        app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                    }
                    crop();
                    saveAsWebP(artboardName);
                    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                }

                function removeCRSmeta() {
                    //community.adobe.com/t5/photoshop/remove-crs-metadata/td-p/10306935
                    if (!documents.length) return;
                    if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                    var xmp = new XMPMeta(app.activeDocument.xmpMetadata.rawData);
                    XMPUtils.removeProperties(xmp, XMPConst.NS_CAMERA_RAW, "", XMPConst.REMOVE_ALL_PROPERTIES);
                    app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                }

                function deleteDocumentAncestorsMetadata() {
                    whatApp = String(app.name); //String version of the app name
                    if (whatApp.search("Photoshop") > 0) { //Check for photoshop specifically, or this will cause errors
                        if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                        var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
                        // Begone foul Document Ancestors!
                        xmp.deleteProperty(XMPConst.NS_PHOTOSHOP, "DocumentAncestors");
                        app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                    }
                }

                function imageSize(width, scaleStyles, constrainProportions) {
                    var s2t = function (s) {
                        return app.stringIDToTypeID(s);
                    };
                    var descriptor = new ActionDescriptor();
                    descriptor.putUnitDouble(s2t("width"), s2t("percentUnit"), width);
                    descriptor.putBoolean(s2t("scaleStyles"), scaleStyles);
                    descriptor.putBoolean(s2t("constrainProportions"), constrainProportions);
                    descriptor.putEnumerated(s2t("interfaceIconFrameDimmed"), s2t("interpolationType"), s2t("bicubicSmoother"));
                    executeAction(s2t("imageSize"), descriptor, DialogModes.NO);
                }

            } else {
                alert('You must have a document open!');
            }
        }

    })();

 

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

 

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 Beginner ,
Jul 21, 2025 Jul 21, 2025

@Stephen Marsh  You are amazing. Thank you so much. V 1.9 worked! The only thing I noticed was that the file sizes were quite a bit larger, however, based on other comments you've made here, I went into the code and created a version that was at 80% quality and that brought them down in line with what I was getting on manual export. 

I appreciate all of your time and energy over the years, doing what should be standard at this point in the game.  Sending you all of the pluses!

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 ,
Jul 23, 2025 Jul 23, 2025
quote

I can't test it properly now due to errors reported in later versions that were not triggered back in the earlier versions of Photoshop. I think that the code needs a major overhaul and rewrite adding various options in a single script interface.

 


By @Stephen Marsh

 

I have rewritten the script. This v2.0 is the basic framework which I will use to add a custom interface in the next release.

 

It has not had exhaustive testing with complex artboards. This new ground-up rewrite uses different processing for the artboards (no longer based on smart objects), so we'll need to see how the results are with feedback from diverse users and use cases. It should be faster than the previous scripts.

 

This version does not offer 200% sizing or JPEG options, but they are easy enough to transplant if needed.

 

The next 2.1 version will offer these and other features.

 

/*
Artboards-to-WEBP-PS2025-v2.jsx
22nd July 2025, v2.0 - Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/exporting-artboards-to-webp-format/td-p/12937135

* Artboard processing rewritten from the original v1.0-1.9 scripts to avoid errors in later versions of Photoshop
* Only for Photoshop 2022 (v23.x.x) or later!
* Saves artboards as lossy WebP, quality: 75
* Select a save location and prefix + separator to be added to the artboard name (uses the doc name by default)
* Filename word spaces (%20) are converted to web-friendly hyphens
* Existing files will be silently overwritten
* Converts non-RGB mode to sRGB color space, RGB color mode and 8 bpc
* If RGB mode, the original color space is retained - beware if using wide gamut spaces such as ProPhoto RGB!
* Artboard content is constrained to the artboard bounds
* Metadata is removed and the document ICC profile is embedded
* Output directory automatically opened
*/

#target photoshop

    (function () {

        try {

            app.bringToFront();

            // Ensure that version 2022 or later is being used
            var versionNumber = app.version.split(".");
            var versionCheck = parseInt(versionNumber);
            if (versionCheck < 23) {
                alert("You must use Photoshop 2022 or later to save using native WebP format...");
                return;
            }

            // Ensure a document is open
            if (app.documents.length === 0) {
                alert("Please open a document first!");
                return;
            }

            // Ensure that the doc has an artboard
            if (!hasArtboards()) {
                alert("No artboards found, script canceled!");
                return;
            }

            // Get the path of the active document (only if it's saved)
            var defaultPath = (app.activeDocument && app.activeDocument.fullName)
                ? app.activeDocument.fullName.parent : Folder("~/Desktop");
            var outputFolder = Folder.selectDialog(
                "Select an output folder to save the artboards as WebP:",
                defaultPath
            );
            if (outputFolder === null) {
                app.beep();
                return;
            }

            var doc = app.activeDocument;
            var layerSets = doc.layerSets;

            // Create a ScriptUI dialog to get the prefix
            var dlg = new Window("dialog", "Enter Prefix");
            dlg.orientation = "column";
            dlg.alignChildren = ["fill", "top"];
            dlg.spacing = 10;
            dlg.margins = 16;
            var defaultPrefix = doc.name.replace(/\.[^\.]+$/, '').replace(/ /g, '-') + "_";
            dlg.add("statictext", undefined, "Add the prefix including separator character to the artboard name:");
            var input = dlg.add("edittext", undefined, defaultPrefix);
            input.characters = 40;
            input.active = true;
            var btnGroup = dlg.add("group"); // OK and Cancel buttons
            btnGroup.alignment = "right";
            var okBtn = btnGroup.add("button", undefined, "OK");
            var cancelBtn = btnGroup.add("button", undefined, "Cancel");
            var preFix; // Result handling
            okBtn.onClick = function () {
                preFix = input.text;
                dlg.close(1);
            };
            cancelBtn.onClick = function () {
                dlg.close(0);
            };

            if (dlg.show() !== 1) {
                app.beep();
                return;
            }

            // Hide the Photoshop panels
            app.togglePalettes();

            // Create the progress bar window
            var progressWin = new Window("palette", "Processing Artboards", undefined, { closeButton: false });
            progressWin.orientation = "column";
            progressWin.alignChildren = ["fill", "top"];
            progressWin.spacing = 10;
            progressWin.margins = 16;
            var progressText = progressWin.add("statictext", undefined, "Starting...");
            var progressBar = progressWin.add("progressbar", undefined, 0, layerSets.length);
            progressBar.preferredSize = [300, 20];
            progressWin.show();

            doc.duplicate(doc.name.replace(/\.[^\.]+$/, '').replace(/ /g, '-'), false);

            // If the doc isn't in RGB mode
            if (activeDocument.mode !== DocumentMode.RGB)
                // Convert to sRGB
                activeDocument.convertProfile("sRGB IEC61966-2.1", Intent.RELATIVECOLORIMETRIC, true, false);
            // Ensure that the doc mode is RGB (to correctly handle Indexed Color mode)
            activeDocument.changeMode(ChangeMode.RGB);
            activeDocument.bitsPerChannel = BitsPerChannelType.EIGHT;

            // Clean out unwanted metadata
            deleteDocumentAncestorsMetadata();
            removeCRSmeta();

            var dupedDoc = app.activeDocument;
            var dupedDoclayerSets = app.activeDocument.layerSets;
            var fileCounter = 0;

            // Process the artboards
            for (var i = dupedDoclayerSets.length - 1; i >= 0; i--) {

                var currentSet = dupedDoclayerSets[i];

                // Select the layerSet
                dupedDoc.activeLayer = currentSet;

                // Update progress bar window
                progressText.text = "Processing: " + currentSet.name + " (" + (fileCounter + 1) + " of " + layerSets.length + ")";
                progressBar.value = fileCounter + 1;
                app.refresh();

                // Conditionally process artboards - not layerSets or frames
                if (isArtboard() === true) {

                    // Dupe artboard to new doc
                    dupeActiveLayer(currentSet.name, currentSet.name);

                    trimTransparency(true, true, true, true);

                    // Combine the prefix with the filename, RegEx replace illegal filename characters with a hyphen
                    var artboardName = preFix + app.activeDocument.activeLayer.name.replace(/[:\/\\*\?\"\<\>\|\\\r\\\n. ]/g, "-");

                    saveAsWebP(artboardName);

                    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

                    fileCounter++;
                }
            }

            dupedDoc.close(SaveOptions.DONOTSAVECHANGES);

            // Ensure Photoshop has focus before closing the progress bar window
            app.bringToFront();
            progressWin.close();

            // Restore the Photoshop panels
            app.togglePalettes();

            // End of script notification
            app.beep();
            alert(fileCounter + ' WebP files saved to: ' + '\r' + outputFolder.fsName);

            // Open the output folder in Windows Explorer or the Mac Finder
            outputFolder.execute();


            ///// FUNCTIONS /////

            function hasArtboards() {
                try {
                    for (var i = 0; i < activeDocument.layerSets.length; i++) {
                        activeDocument.activeLayer = activeDocument.layerSets[i];
                        var r = new ActionReference();
                        r.putEnumerated(stringIDToTypeID('layer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
                        var options = executeActionGet(r);
                        if (options.hasKey(stringIDToTypeID('artboard'))) return true;
                    }
                    return false;
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function isArtboard() {
                try {
                    var d = new ActionDescriptor();
                    var r = new ActionReference();
                    r.putEnumerated(stringIDToTypeID('layer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
                    var options = executeActionGet(r);
                    return options.hasKey(stringIDToTypeID('artboard'));
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function dupeActiveLayer(docName, layerName) {
                try {
                    var c2t = function (s) {
                        return app.charIDToTypeID(s);
                    };
                    var s2t = function (s) {
                        return app.stringIDToTypeID(s);
                    };
                    var descriptor = new ActionDescriptor();
                    var reference = new ActionReference();
                    var reference2 = new ActionReference();
                    reference.putClass(s2t("document"));
                    descriptor.putReference(c2t("null"), reference);
                    descriptor.putString(s2t("name"), docName); // Doc name
                    reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
                    descriptor.putReference(s2t("using"), reference2);
                    descriptor.putString(s2t("layerName"), layerName); // Layer name
                    executeAction(s2t("make"), descriptor, DialogModes.NO);
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function trimTransparency(top, bottom, left, right) {
                try {
                    var c2t = function (s) {
                        return app.charIDToTypeID(s);
                    };
                    var s2t = function (s) {
                        return app.stringIDToTypeID(s);
                    };
                    var descriptor = new ActionDescriptor();
                    descriptor.putEnumerated(s2t("trimBasedOn"), s2t("trimBasedOn"), c2t("Trns"));
                    descriptor.putBoolean(s2t("top"), top);
                    descriptor.putBoolean(s2t("bottom"), bottom);
                    descriptor.putBoolean(s2t("left"), left);
                    descriptor.putBoolean(s2t("right"), right);
                    executeAction(s2t("trim"), descriptor, DialogModes.NO);
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function removeCRSmeta() {
                try {
                    if (!documents.length) return;
                    if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                    var xmp = new XMPMeta(app.activeDocument.xmpMetadata.rawData);
                    XMPUtils.removeProperties(xmp, XMPConst.NS_CAMERA_RAW, "", XMPConst.REMOVE_ALL_PROPERTIES);
                    app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function deleteDocumentAncestorsMetadata() {
                try {
                    whatApp = String(app.name);
                    if (whatApp.search("Photoshop") > 0) {
                        if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                        var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
                        xmp.deleteProperty(XMPConst.NS_PHOTOSHOP, "DocumentAncestors");
                        app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                    }
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function saveAsWebP(saveName) {
                try {
                    var s2t = function (s) {
                        return app.stringIDToTypeID(s);
                    };
                    var descriptor = new ActionDescriptor();
                    var descriptor2 = new ActionDescriptor();
                    descriptor2.putEnumerated(s2t("compression"), s2t("WebPCompression"), s2t("compressionLossy"));
                    descriptor2.putInteger(s2t("quality"), 75);
                    descriptor2.putBoolean(s2t("includeXMPData"), false);
                    descriptor2.putBoolean(s2t("includeEXIFData"), false);
                    descriptor2.putBoolean(s2t("includePsExtras"), false);
                    descriptor.putObject(s2t("as"), s2t("WebPFormat"), descriptor2);
                    descriptor.putPath(s2t("in"), new File(outputFolder + '/' + saveName + '.webp'), true);
                    descriptor.putBoolean(s2t("lowerCase"), true);
                    descriptor.putEnumerated(s2t("saveStage"), s2t("saveStageType"), s2t("saveSucceeded"));
                    executeAction(s2t("save"), descriptor, DialogModes.NO);
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

        } catch (e) {
            alert("Error:\n" + e.message + "\nLine: " + e.line);
        }

    })();

  

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 ,
Jul 26, 2025 Jul 26, 2025

Here is the 2.1 script version:

 

Artboards-to-WEBP-PS2025-scriptUI-GUI-v2-1.png

 

* Batch Output to WebP - Automatically saves all your artboards to WebP format in one go, saving you from the tedious process of saving each artboard individually

 

* Dual Format Support - Can export both WebP and JPEG versions simultaneously, so you get modern WebP files for performance plus JPEG fallbacks for compatibility

 

* Flexible Compression Options - Choose between lossy and lossless WebP compression with a quality slider (0-100), giving you control over file size vs. image quality

 

* Batch Resizing - Resize all artboards by percentage in one operation, perfect for creating multiple asset sizes for responsive designs or different screen densities

 

* Automatic File Management - Handles filename sanitization, removes special characters, and can optionally add timestamps to prevent overwriting existing files

 

* Color Profile Optimization - Automatically converts non-RGB files to sRGB color space. Optionally convert RGB mode files to sRGB

 

* Metadata Cleanup - Strips out metadata, to keep file sizes as small as possible

 

/*
Artboards-to-WEBP-PS2025-scriptUI-GUI-v2-2.jsx
30th July 2025, v2.2 - Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/exporting-artboards-to-webp-format/td-p/12937135

* Artboard processing rewritten from the original v1.0-1.9 scripts to avoid errors in later versions of Photoshop
* Only for Photoshop 2022 (v23.x.x) or later!
* Saves artboards as WebP with lossless/lossy quality options
* Resize artboard by % option, a filename suffix such as '_200' is added to indicate a 200% resize
* Filename word spaces (%20) are converted to web-friendly hyphens
* Artboard content is constrained to the artboard bounds
* Metadata is removed and the document ICC profile is embedded
* Optional JPEG save checkbox with quality level dropdown menu
* Option to overwrite existing files or to add a date-timestamp suffix '_YYYYMMDD-HHMMSS'
* Optionally convert RGB images to sRGB color profile, RGB color mode and 8 bpc (non-RGB images are automatically converted to sRGB 8 BPC)
*/

#target photoshop

    (function () {

        try {

            app.bringToFront();

            var versionNumber = app.version.split(".");
            var versionCheck = parseInt(versionNumber);
            if (versionCheck < 23) {
                alert("You must use Photoshop 2022 or later to save using native WebP format...");
                return;
            }

            if (app.documents.length === 0) {
                alert("Please open a document first!");
                return;
            }

            var doc = app.activeDocument;
            var layerSets = doc.layerSets;

            try {
                // var docPath = decodeURI(app.activeDocument.path);
                var docPath = app.activeDocument.path;
            } catch (e) {
                docPath = Folder("~/Desktop");
            }

            if (!hasArtboards()) {
                alert("No artboards found, script canceled!");
                return;
            }

            // ScriptUI settings dialog defaults
            var exportSettings = {
                outputFolder: docPath,
                prefix: doc.name.replace(/\.[^\.]+$/, '').replace(/ /g, '-') + "_",
                quality: 75,
                isLossy: true,
                overwrite: true,
                openFolder: true,
                enableResize: false,
                resizeWidth: 200,
                scaleStyles: true,
                constrainProportions: true,
                jpegQuality: 9,
                saveJPEG: true
            };

            var dlg = new Window("dialog", "Export Artboards to WebP (v2.2)");
            dlg.orientation = "column";
            dlg.alignChildren = ["fill", "top"];
            dlg.spacing = 10;
            dlg.margins = 16;

            var settingsGroup = dlg.add("panel", undefined, ""); // Possibly add an "Export Options" label
            settingsGroup.orientation = "column";
            settingsGroup.alignChildren = ["fill", "top"];
            settingsGroup.margins = 10;
            settingsGroup.spacing = 8;

            var folderGroup = settingsGroup.add("group");
            folderGroup.orientation = "column";
            folderGroup.alignChildren = ["fill", "top"];
            folderGroup.add("statictext", undefined, "Output folder:");
            var folderSubGroup = folderGroup.add("group");
            var browseBtn = folderSubGroup.add("button", undefined, "Browse...");
            var folderText = folderSubGroup.add("statictext", undefined, exportSettings.outputFolder ? decodeURI(exportSettings.outputFolder.fsName) : "None selected", { truncate: 'middle' });
            folderText.alignment = ["fill", "left"];
            browseBtn.onClick = function () {
                var folder = Folder.selectDialog("Select Output Folder");
                if (folder) {
                    exportSettings.outputFolder = folder;
                    folderText.text = decodeURI(folder.fsName);
                }
            };

            var prefixGroup = settingsGroup.add("group");
            prefixGroup.orientation = "column";
            prefixGroup.alignChildren = ["fill", "top"];
            prefixGroup.add("statictext", undefined, "Filename prefix:");
            var prefixInput = prefixGroup.add("edittext", undefined, exportSettings.prefix);
            prefixInput.characters = 30;

            var compGroup = settingsGroup.add("group");
            compGroup.orientation = "column";
            compGroup.alignChildren = ["fill", "top"];
            var radioGroup = compGroup.add("group");
            radioGroup.orientation = "row";
            radioGroup.add("statictext", undefined, "Compression:");
            var lossyRadio = radioGroup.add("radiobutton", undefined, "Lossy");
            var losslessRadio = radioGroup.add("radiobutton", undefined, "Lossless");
            lossyRadio.value = true;

            var qualityGroup = compGroup.add("group");
            qualityGroup.orientation = "row";
            qualityGroup.alignChildren = ["left", "center"];
            qualityGroup.add("statictext", undefined, "Image quality (0-100):");
            var qualitySlider = qualityGroup.add("slider", undefined, exportSettings.quality, 0, 100);
            qualitySlider.preferredSize.width = 150;
            var qualityValue = qualityGroup.add("statictext", undefined, exportSettings.quality.toString());
            qualitySlider.onChanging = function () {
                qualityValue.text = Math.round(qualitySlider.value).toString();
            };
            qualitySlider.onChange = function () {
                qualityValue.text = Math.round(qualitySlider.value).toString();
            };

            lossyRadio.onClick = function () {
                qualitySlider.enabled = true;
                qualityValue.enabled = true;
            };

            losslessRadio.onClick = function () {
                qualitySlider.enabled = false;
                qualityValue.enabled = false;
            };

            var resizeGroup = settingsGroup.add("group");
            resizeGroup.orientation = "column";
            resizeGroup.alignChildren = ["fill", "top"];
            var resizeCheck = resizeGroup.add("checkbox", undefined, "Resize artboards");
            resizeCheck.value = false;
            resizeCheck.helpTip = "Resize artboards, filename suffix such as '_200' added";
            var resizeOptionsGroup = resizeGroup.add("group");
            resizeOptionsGroup.orientation = "row";
            resizeOptionsGroup.alignChildren = ["left", "center"];
            resizeOptionsGroup.enabled = false;
            resizeOptionsGroup.add("statictext", undefined, "Resize %:");
            var widthInput = resizeOptionsGroup.add("editnumber", undefined, exportSettings.resizeWidth.toString());
            widthInput.characters = 5;
            resizeCheck.onClick = function () {
                resizeOptionsGroup.enabled = resizeCheck.value;
            };

            var checkGroup = settingsGroup.add("group");
            checkGroup.orientation = "column";
            checkGroup.alignChildren = ["left", "top"];
            var convertRGBCheck = checkGroup.add("checkbox", undefined, "Convert to sRGB");
            convertRGBCheck.value = true;
            convertRGBCheck.helpTip = "Converts RGB mode files which are not sRGB to sRGB";
            var overwriteCheck = checkGroup.add("checkbox", undefined, "Overwrite existing files");
            overwriteCheck.value = true;
            overwriteCheck.helpTip = "If unchecked, will add a date-time suffix i.e. '_YYYYMMDD-HHMMSS' to avoid overwriting existing files";
            var openFolderCheck = checkGroup.add("checkbox", undefined, "Open folder after export");
            openFolderCheck.value = false;

            var jpegGroup = checkGroup.add("group");
            jpegGroup.orientation = "row";
            jpegGroup.alignChildren = ["left", "center"];
            var saveJPEGCheck = jpegGroup.add("checkbox", undefined, "Save JPEG copy");
            saveJPEGCheck.helpTip = "Save additional JPEG versions";
            saveJPEGCheck.value = false;
            var jpegQualityLabel = jpegGroup.add("statictext", undefined, "Quality:");
            var jpegQualityDropdown = jpegGroup.add("dropdownlist", undefined, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]);
            jpegQualityDropdown.selection = 9; // Default to "9"
            jpegQualityLabel.enabled = false;
            jpegQualityDropdown.enabled = false;
            saveJPEGCheck.onClick = function () {
                jpegQualityLabel.enabled = saveJPEGCheck.value;
                jpegQualityDropdown.enabled = saveJPEGCheck.value;
            };

            var btnGroup = dlg.add("group");
            btnGroup.alignment = "right";
            var cancelBtn = btnGroup.add("button", undefined, "Cancel");
            var okBtn = btnGroup.add("button", undefined, "OK");
            cancelBtn.onClick = function () {
                dlg.close(0);
            };
            okBtn.onClick = function () {
                if (!exportSettings.outputFolder) {
                    alert("Please select an output folder.");
                    return;
                }
                exportSettings.prefix = prefixInput.text;
                exportSettings.quality = Math.round(qualitySlider.value);
                exportSettings.isLossy = lossyRadio.value;
                exportSettings.overwrite = overwriteCheck.value;
                exportSettings.openFolder = openFolderCheck.value;
                exportSettings.enableResize = resizeCheck.value;
                exportSettings.resizeWidth = parseInt(widthInput.text) || 100;
                exportSettings.saveJPEG = saveJPEGCheck.value; // Capture JPEG checkbox value
                if (saveJPEGCheck.value && jpegQualityDropdown.selection !== null) {
                    exportSettings.jpegQuality = parseInt(jpegQualityDropdown.selection.text);
                }
                exportSettings.convertRGB = convertRGBCheck.value;
                dlg.close(1);
            };

            if (dlg.show() !== 1) {
                app.beep();
                return;
            }

            // Hide Photoshop panels
            app.togglePalettes();

            // Progress bar window
            var progressWin = new Window("palette", "Processing Artboards", undefined, { closeButton: false });
            progressWin.orientation = "column";
            progressWin.alignChildren = ["fill", "top"];
            progressWin.spacing = 10;
            progressWin.margins = 16;
            var progressText = progressWin.add("statictext", undefined, "Starting...");
            var progressBar = progressWin.add("progressbar", undefined, 0, layerSets.length);
            progressBar.preferredSize = [300, 20];
            progressWin.show();

            // Temp doc unexpected error handling
            var dupedDoc = null;
            try {
                // Duplicate the original document
                dupedDoc = doc.duplicate(doc.name.replace(/\.[^\.]+$/, '').replace(/ /g, '-'), false);
                app.activeDocument = dupedDoc;

                if (activeDocument.mode !== DocumentMode.RGB) {
                    activeDocument.convertProfile("sRGB IEC61966-2.1", Intent.RELATIVECOLORIMETRIC, true, false);
                    activeDocument.changeMode(ChangeMode.RGB);
                } else if (exportSettings.convertRGB) {
                    activeDocument.convertProfile("sRGB IEC61966-2.1", Intent.RELATIVECOLORIMETRIC, true, false);
                }
                activeDocument.bitsPerChannel = BitsPerChannelType.EIGHT;

                // These steps are redundant as each artboard is duplicated to a new doc, but it can't hurt to leave them in
                deleteDocumentAncestorsMetadata();
                removeCRSmeta();
                removeXMP();

                var dupedDoclayerSets = app.activeDocument.layerSets;
                var webpCounter = 0;
                var jpegCounter = 0;

                for (var i = dupedDoclayerSets.length - 1; i >= 0; i--) {
                    var currentSet = dupedDoclayerSets[i];
                    dupedDoc.activeLayer = currentSet;

                    progressText.text = "Processing: " + currentSet.name + " (" + (webpCounter + 1) + " of " + layerSets.length + ")";
                    progressBar.value = webpCounter + 1;
                    app.refresh();

                    if (isArtboard() === true) {
                        dupeActiveLayer(currentSet.name, currentSet.name);
                        trimTransparency(true, true, true, true);

                        if (exportSettings.enableResize && exportSettings.resizeWidth !== 100) {
                            imageSize(exportSettings.resizeWidth, exportSettings.scaleStyles, exportSettings.constrainProportions);
                        }

                        artboardName = exportSettings.prefix + app.activeDocument.activeLayer.name
                            .replace(/[:\/\\*\?\"\<\>\|\\\r\\\n. ]+/g, "-")
                            .replace(/-+$/, '')
                            .replace(/^-+/, '');

                        if (exportSettings.enableResize) {
                            artboardName += "_" + exportSettings.resizeWidth.toString();
                        }

                        var finalFileName = artboardName;
                        if (!exportSettings.overwrite) {
                            finalFileName = artboardName + "_" + getTimestamp();
                        }

                        saveAsWebP(finalFileName);
                        if (exportSettings.saveJPEG) {
                            saveAsJPEG(finalFileName);
                            jpegCounter++;
                        }
                        app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                        webpCounter++;
                    }
                }
                // v2.2 revision, mistakenly missed from the original release!
                dupedDoc.close(SaveOptions.DONOTSAVECHANGES);
            } catch (e) {
                alert("Unexpected error during processing:\n" + e.message + "\nLine: " + e.line);
            } finally {
                try {
                    if (dupedDoc && app.documents.length && app.documents.indexOf(dupedDoc) !== -1) {
                        dupedDoc.close(SaveOptions.DONOTSAVECHANGES);
                    }
                } catch (e) {}
                app.bringToFront();
                progressWin.close();
                app.togglePalettes();
            }

            // End of script notification
            app.togglePalettes();
            app.beep();
            var fileCounter = webpCounter + jpegCounter;
            alert(fileCounter + ' files saved to: ' + '\r' + exportSettings.outputFolder.fsName);

            // Open folder in Finder or Explorer conditional for checkbox
            if (exportSettings.openFolder) {
                exportSettings.outputFolder.execute();
            }


            ////// FUNCTIONS //////

            function imageSize(width, scaleStyles, constrainProportions) {
                try {
                    var s2t = function (s) {
                        return app.stringIDToTypeID(s);
                    };
                    var descriptor = new ActionDescriptor();
                    descriptor.putUnitDouble(s2t("width"), s2t("percentUnit"), width);
                    descriptor.putBoolean(s2t("scaleStyles"), scaleStyles);
                    descriptor.putBoolean(s2t("constrainProportions"), constrainProportions);
                    descriptor.putEnumerated(s2t("interfaceIconFrameDimmed"), s2t("interpolationType"), s2t("bicubicAutomatic"));
                    executeAction(s2t("imageSize"), descriptor, DialogModes.NO);
                } catch (e) {
                    alert("Error in imageSize:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function hasArtboards() {
                try {
                    for (var i = 0; i < activeDocument.layerSets.length; i++) {
                        activeDocument.activeLayer = activeDocument.layerSets[i];
                        var r = new ActionReference();
                        r.putEnumerated(stringIDToTypeID('layer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
                        var options = executeActionGet(r);
                        if (options.hasKey(stringIDToTypeID('artboard'))) return true;
                    }
                    return false;
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function isArtboard() {
                try {
                    var r = new ActionReference();
                    r.putEnumerated(stringIDToTypeID('layer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
                    var options = executeActionGet(r);
                    return options.hasKey(stringIDToTypeID('artboard'));
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function dupeActiveLayer(docName, layerName) {
                try {
                    var s2t = function (s) { return stringIDToTypeID(s); };
                    var descriptor = new ActionDescriptor();
                    var reference = new ActionReference();
                    var reference2 = new ActionReference();
                    reference.putClass(s2t("document"));
                    descriptor.putReference(charIDToTypeID("null"), reference);
                    descriptor.putString(s2t("name"), docName);
                    reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
                    descriptor.putReference(s2t("using"), reference2);
                    descriptor.putString(s2t("layerName"), layerName);
                    executeAction(s2t("make"), descriptor, DialogModes.NO);
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function trimTransparency(top, bottom, left, right) {
                try {
                    var c2t = function (s) { return charIDToTypeID(s); };
                    var s2t = function (s) { return stringIDToTypeID(s); };
                    var descriptor = new ActionDescriptor();
                    descriptor.putEnumerated(s2t("trimBasedOn"), s2t("trimBasedOn"), c2t("Trns"));
                    descriptor.putBoolean(s2t("top"), top);
                    descriptor.putBoolean(s2t("bottom"), bottom);
                    descriptor.putBoolean(s2t("left"), left);
                    descriptor.putBoolean(s2t("right"), right);
                    executeAction(s2t("trim"), descriptor, DialogModes.NO);
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function removeCRSmeta() {
                try {
                    if (!documents.length) return;
                    if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                    var xmp = new XMPMeta(app.activeDocument.xmpMetadata.rawData);
                    XMPUtils.removeProperties(xmp, XMPConst.NS_CAMERA_RAW, "", XMPConst.REMOVE_ALL_PROPERTIES);
                    app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function deleteDocumentAncestorsMetadata() {
                try {
                    if (!documents.length) return;
                    if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                    var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
                    xmp.deleteProperty(XMPConst.NS_PHOTOSHOP, "DocumentAncestors");
                    app.activeDocument.xmpMetadata.rawData = xmp.serialize();
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function removeXMP() {
                if (!documents.length) return;
                if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
                var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
                XMPUtils.removeProperties(xmp, "", "", XMPConst.REMOVE_ALL_PROPERTIES);
                app.activeDocument.xmpMetadata.rawData = xmp.serialize();
            }

            function saveAsWebP(saveName) {
                try {
                    var s2t = function (s) { return stringIDToTypeID(s); };
                    var descriptor = new ActionDescriptor();
                    var descriptor2 = new ActionDescriptor();
                    var compressionType = exportSettings.isLossy ? s2t("compressionLossy") : s2t("compressionLossless");
                    descriptor2.putEnumerated(s2t("compression"), s2t("WebPCompression"), compressionType);
                    descriptor2.putInteger(s2t("quality"), exportSettings.quality);
                    descriptor2.putBoolean(s2t("includeXMPData"), false);
                    descriptor2.putBoolean(s2t("includeEXIFData"), false);
                    descriptor2.putBoolean(s2t("includePsExtras"), false);
                    descriptor.putObject(s2t("as"), s2t("WebPFormat"), descriptor2);
                    descriptor.putPath(s2t("in"), new File(exportSettings.outputFolder + '/' + saveName + '.webp'));
                    descriptor.putBoolean(s2t("lowerCase"), true);
                    descriptor.putEnumerated(s2t("saveStage"), s2t("saveStageType"), s2t("saveSucceeded"));
                    executeAction(s2t("save"), descriptor, DialogModes.NO);
                } catch (e) {
                    alert("Error:\n" + e.message + "\nLine: " + e.line);
                }
            }

            function saveAsJPEG(_name) {
                var jpgOptns = new JPEGSaveOptions();
                jpgOptns.formatOptions = FormatOptions.STANDARDBASELINE;
                jpgOptns.embedColorProfile = true;
                jpgOptns.matte = MatteType.NONE;
                jpgOptns.quality = exportSettings.jpegQuality || 9;
                activeDocument.saveAs(new File(exportSettings.outputFolder + '/' + _name + '.jpg'), jpgOptns, true, Extension.LOWERCASE);
            }

            function getTimestamp() {
                var now = new Date();
                return now.getFullYear().toString() +
                    ("0" + (now.getMonth() + 1)).slice(-2) +
                    ("0" + now.getDate()).slice(-2) + "-" +
                    ("0" + now.getHours()).slice(-2) +
                    ("0" + now.getMinutes()).slice(-2) +
                    ("0" + now.getSeconds()).slice(-2);
            }

        } catch (e) {
            alert("Error:\n" + e.message + "\nLine: " + e.line);
        }

    })();

 

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 Beginner ,
Jul 28, 2025 Jul 28, 2025

🙌 Thank you @Stephen Marsh!

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 Beginner ,
Jul 28, 2025 Jul 28, 2025

@Stephen Marsh  Yeah, that worked flawlessly and that dialog box is 🤌. I wish I could upvote that even more. Do you have venmo or something? ^_^

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 ,
Jul 28, 2025 Jul 28, 2025
LATEST
quote

@Stephen Marsh  Yeah, that worked flawlessly and that dialog box is 🤌. I wish I could upvote that even more. Do you have venmo or something? ^_^


By @raven250


You're welcome and thank you for the feedback! You can mark the post as a correct answer so that it's more visible.

 

Others have offered to make a contribution in the past, I'm thinking of setting up a Buy Me a Coffee account.

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 Beginner ,
Jun 12, 2022 Jun 12, 2022

@Stephen Marsh Solved! Your script works perfectly. The problem was that I had the "Open As Layer" event running in the Script Events Manager. Turning that off solved the errors I was getting, plus a whole heap of other stuff relating to exporting artboards. I rely hugely on Open As Layer to help document my compositing workflow, but hadn't connected the dots to its impact on other scripts. But it's easy to toggle the event on and off as needed. Thank you so much for all your help on this, and for indirectly solving my other dramas too 🙂

Judi

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 12, 2022 Jun 12, 2022

@Art by JLM – Glad you worked it out! Which of the 4 script versions works?

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 Beginner ,
Jun 12, 2022 Jun 12, 2022

I tested only v1.4 with the 'fix' in place. Likely the others work too.

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