Skip to main content
Stephen Marsh
Community Expert
Community Expert
August 28, 2025
Question

Artboards to AVIF script

  • August 28, 2025
  • 1 reply
  • 164 views

I have created an "Artboards to AVIF" script, based on my "Artboards to WebP" script.

 

Key Features:
* Only for Photoshop 2025 (v26.x.x) or later
* Export artboards as AVIF with lossy or lossless compression
* Adjustable quality slider for lossy AVIF
* Optional JPEG save with quality level dropdown
* Resize artboards by % with filename suffix (e.g. "_200")
* Filenames cleaned: spaces converted to web-friendly hyphens
* Artboard content trimmed to artboard bounds
* Metadata toggle (XMP, CRS, ancestors)
* ICC profile embedded, with automatic conversion to sRGB 8-bit RGB if required
* Option to overwrite existing files or add a timestamp suffix
* Output folder selection with option to open folder after export
 
 
/*
Artboards-to-AVIF-PS2025-scriptUI-GUI-v1-0.jsx
Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-discussions/artboards-to-avif-script/m-p/15480083
v1.0 - 30th July 2025: Initial release

* Only for Photoshop 2025 (v26.x.x) or later!
* Saves artboards as AVIF 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)

Based on:
Artboards-to-WEBP-PS2025-scriptUI-GUI-v2-1.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/exporting-artboards-to-webp-format/td-p/12937135#U15431202
*/

#target photoshop

    (function () {

        try {

            app.bringToFront();

            var versionNumber = app.version.split(".");
            var versionCheck = parseInt(versionNumber);
            if (versionCheck < 26) {
                alert("You must use Photoshop 2025 or later to save using native AVIF 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 = app.activeDocument.path;
            } catch (e) {
                docPath = Folder("~/Desktop");
            }

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

            var exportSettings = {
                outputFolder: docPath,
                prefix: doc.name.replace(/\.[^\.]+$/, '').replace(/ /g, '-') + "_",
                quality: 50,
                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 AVIF (v1.0)");
            dlg.orientation = "column";
            dlg.alignChildren = ["fill", "top"];
            dlg.spacing = 10;
            dlg.margins = 16;

            var settingsGroup = dlg.add("panel", undefined, "");
            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;
            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;
            var overwriteCheck = checkGroup.add("checkbox", undefined, "Overwrite existing files");
            overwriteCheck.value = true;
            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.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;
            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;
                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;
            }

            app.togglePalettes();

            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();

            var dupedDoc = null;
            var avifCounter = 0;
            var jpegCounter = 0;

            try {
                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;

                deleteDocumentAncestorsMetadata();
                removeCRSmeta();
                removeXMP();

                var dupedDoclayerSets = app.activeDocument.layerSets;

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

                    progressText.text = "Processing: " + currentSet.name + " (" + (avifCounter + 1) + " of " + layerSets.length + ")";
                    progressBar.value = avifCounter + 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);
                        }

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

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

                        var finalFileName = exportSettings.overwrite ? artboardName : artboardName + "_" + getTimestamp();

                        saveAsAVIF(finalFileName);
                        if (exportSettings.saveJPEG) {
                            saveAsJPEG(finalFileName);
                            jpegCounter++;
                        }
                        app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                        avifCounter++;
                    }
                }
                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();
            }

            app.beep();
            alert((avifCounter + jpegCounter) + ' files saved to: ' + '\r' + exportSettings.outputFolder.fsName);

            if (exportSettings.openFolder) {
                exportSettings.outputFolder.execute();
            }


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

            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);
                executeAction(s2t("imageSize"), descriptor, DialogModes.NO);
            }

            function hasArtboards() {
                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;
            }

            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 saveAsAVIF(saveName) {
                try {
                    var s2t = function (s) { return stringIDToTypeID(s); };
                    var descSave = new ActionDescriptor();
                    var descAVIFOptions = new ActionDescriptor();
                    var idAVIFCompression = s2t("AVIFCompression");
                    if (exportSettings.isLossy) {
                        descAVIFOptions.putEnumerated(s2t("colorCompression"), idAVIFCompression, s2t("compressionLossy"));
                        descAVIFOptions.putInteger(s2t("colorQuality"), exportSettings.quality);
                    } else {
                        descAVIFOptions.putEnumerated(s2t("colorCompression"), idAVIFCompression, s2t("compressionLossless"));
                    }
                    descAVIFOptions.putEnumerated(s2t("alphaCompression"), idAVIFCompression, s2t("compressionLossless"));
                    descAVIFOptions.putEnumerated(s2t("colorFormat"), s2t("AVIFColorFormat"), s2t("AVIFFormat422")); // Options: AVIFFormat444, AVIFFormat422, AVIFFormat420
                    descAVIFOptions.putEnumerated(s2t("sampleDepth"), s2t("AVIFSampleDepth"), s2t("AVIFDepth12bit"));
                    descAVIFOptions.putInteger(s2t("encoderSpeed"), 6); // Options: 2 (slowest/smallest), 4, 6, 8, 10 (fastest/largest)
                    descAVIFOptions.putBoolean(s2t("includeXMPData"), false);
                    descAVIFOptions.putBoolean(s2t("includeEXIFData"), false);
                    descAVIFOptions.putBoolean(s2t("includePsExtras"), false);
                    descSave.putObject(s2t("as"), s2t("AVIFFormat"), descAVIFOptions);
                    descSave.putPath(s2t("in"), new File(exportSettings.outputFolder + '/' + saveName + '.avif'));
                    descSave.putBoolean(s2t("lowerCase"), true);
                    descSave.putEnumerated(s2t("saveStage"), s2t("saveStageType"), s2t("saveSucceeded"));
                    executeAction(s2t("save"), descSave, DialogModes.NO);
                } catch (e) {
                    alert("Error saving AVIF:\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);
        }

    })();

 

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

 

1 reply

creative explorer
Community Expert
Community Expert
September 2, 2025

@Stephen Marsh nice job! 

m
Stephen Marsh
Community Expert
Community Expert
September 2, 2025

@creative explorer - thank you!