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

Mass export of artboards from several open psd files at once

New Here ,
Aug 22, 2025 Aug 22, 2025

Hi, I am searching for a way or perhaps a script to enable me to export all artboards from several open PSD files at once (and not individually for each single PSD). Does anyone know if such a script exits and where I can find it? 

TOPICS
Actions and scripting , macOS
310
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
Adobe
Community Expert ,
Aug 22, 2025 Aug 22, 2025

Some scripts can be recorded into an action and the script parameters are also recorded for uninterrupted batch playback on all open files. Perhaps the Artboards to files script can be recorded into such a fashion, I've never tried.

 

I'll need to have a dig around my archive and see if I have such a script or if one can be easily modified without requiring a total rewrite.

 

It's generally more efficient to batch a folder of files one at a time than to batch all open files which chew up memory.

 

What is the save format?

 

What about naming? Filename +  Artboard name? Are all unique or is there a possibility of the same names being used?

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 ,
Aug 22, 2025 Aug 22, 2025

Thanks in advance for your efforts.

It's generally more efficient to batch a folder of files one at a time than to batch all open files which chew up memory.
That is right and would also work. My point is to be able to do the export for dozens of generated photoshop files in one step at a time to automate production of ad variants of a campaign.

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 ,
Aug 22, 2025 Aug 22, 2025

@Norbert252184170tz6 

 

Thanks for clarifying.

 

What is the save format?

 

What about naming? Filename +  Artboard name? Are all artboard names unique, or is there a possibility of the same names being used?

 

EDIT: As a proof of concept, I have tested my "Artboards-to-WEBP-PS2025-v2.jsx" script, removing all interactive features (prompts, alerts etc.) so that it is suitable for "headless" operation when recorded into an Action and run via File > Automate > Batch... and it works great! But if you don't want WebP, then I need to know the format

 

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
New Here ,
Aug 25, 2025 Aug 25, 2025

Hi Stephen, thank you for the reply. Output-Formt should be JPG and ideally we can export the artboards with their name (and perhaps the artboards of each PSD in a single Assets-folder)

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 ,
Aug 25, 2025 Aug 25, 2025
quote

Hi Stephen, thank you for the reply. Output-Formt should be JPG and ideally we can export the artboards with their name (and perhaps the artboards of each PSD in a single Assets-folder)


By @Norbert252184170tz6

 

Try this v1.1 script, it is intended to be recorded into a 2-step action:

 

1) Run script

2) Close (without saving)

 

Then the File > Automate > Batch command should reference the action (no need to set a destination, only the source as open docs, or a folder etc).

 

I'm happy to make modifications based on your feedback.

 

/*
Artboards-to-JPEG-Headless-v1-1.jsx
Stephen Marsh
v1.0 - 25th August 2025: Initial release
v1.1 - 27th August 2025: Changed the save to create and use an "Assets" folder

* Intended for recording into an Action, then run via Automate > Batch
* Generates a log.txt file listing all successfully exported filenames
* Automatically exports all artboards from the active Photoshop document as JPEG files
* Saves exported files to the source document's folder (if saved) or Desktop as fallback location
* Creates an "Assets" folder to hold the files and log
* Creates filenames using document name prefix plus artboard name with special characters sanitized
* Implements automatic version numbering (_v001, _v002, etc.) to prevent filename conflicts
* Converts documents to RGB color mode and 8-bit depth for consistent JPEG output
* Applies sRGB color profile conversion using multiple fallback methods
* Strips all metadata (XMP, Camera Raw, Document Ancestors) from exported files

Headless batch-friendly version (no prompts, alerts or UI)
https://community.adobe.com/t5/photoshop-ecosystem-discussions/mass-export-of-artboards-from-several-open-psd-files-at-once/td-p/15471119

Based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/exporting-artboards-to-webp-format/m-p/15431202/page/2#U15425799
*/

#target photoshop

(function () {
    try {
        // Exit if no document is open or no artboards are present
        if (app.documents.length === 0 || !hasArtboards()) return;

        // Document variable
        var doc = app.activeDocument;

        // Set output folder to document folder if saved, otherwise Desktop
        var baseFolder = (doc.saved) ? doc.fullName.parent : Folder("~/Desktop");
        
        // Create Assets folder
        var outputFolder = new Folder(baseFolder + "/Assets");
        if (!outputFolder.exists) {
            outputFolder.create();
        }

        // Create filename prefix from document name
        var preFix = doc.name.replace(/\.[^\.]+$/, '').replace(/ /g, '-') + "_";

        // Duplicate the document for safe processing
        doc.duplicate(doc.name.replace(/\.[^\.]+$/, '').replace(/ /g, '-'), false);

        // If the doc isn't in RGB mode, convert it
        if (activeDocument.mode !== DocumentMode.RGB) {
            activeDocument.changeMode(ChangeMode.RGB);
        }
        // Ensure 8-bit depth
        activeDocument.bitsPerChannel = BitsPerChannelType.EIGHT;
        // More robust sRGB conversion
        try {
            activeDocument.convertProfile("sRGB IEC61966-2.1", Intent.RELATIVECOLORIMETRIC, true, false);
        } catch (e1) {
            try {
                activeDocument.convertProfile("sRGB", Intent.RELATIVECOLORIMETRIC, true, false);
            } catch (e2) {
                try {
                    var idAssignProfile = stringIDToTypeID("assignProfile");
                    var desc1 = new ActionDescriptor();
                    desc1.putString(stringIDToTypeID("profile"), "sRGB IEC61966-2.1");
                    executeAction(idAssignProfile, desc1, DialogModes.NO);
                } catch (e3) {
                    try {
                        var idConvertToProfile = stringIDToTypeID("convertToProfile");
                        var desc2 = new ActionDescriptor();
                        desc2.putString(stringIDToTypeID("profile"), "sRGB IEC61966-2.1");
                        desc2.putEnumerated(stringIDToTypeID("intent"), stringIDToTypeID("intent"), stringIDToTypeID("relativeColorimetric"));
                        desc2.putBoolean(stringIDToTypeID("blackPointCompensation"), true);
                        desc2.putBoolean(stringIDToTypeID("dither"), false);
                        executeAction(idConvertToProfile, desc2, DialogModes.NO);
                    } catch (e4) {
                        // If all methods fail, continue without conversion
                    }
                }
            }
        }

        // Remove metadata
        deleteDocumentAncestorsMetadata();
        removeCRSmeta();
        removeXMP();

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

        // Loop through artboards and export each one
        for (var i = dupedDoclayerSets.length - 1; i >= 0; i--) {
            var currentSet = dupedDoclayerSets[i];
            dupedDoc.activeLayer = currentSet;

            if (isArtboard()) {
                dupeActiveLayer(currentSet.name, currentSet.name);
                app.activeDocument.trim(TrimType.TRANSPARENT);

                var baseName = preFix + app.activeDocument.activeLayer.name.replace(/[:\/\\*\?\"\<\>\|\\\r\\\n. ]/g, "-");
                var artboardName = getUniqueFilename(baseName, outputFolder);

                saveAsJPEG(artboardName);
                logExportedFile(artboardName);

                app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
            }
        }

        dupedDoc.close(SaveOptions.DONOTSAVECHANGES);

        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() {
            var r = new ActionReference();
            r.putEnumerated(stringIDToTypeID('layer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
            var options = executeActionGet(r);
            return options.hasKey(stringIDToTypeID('artboard'));
        }

        function dupeActiveLayer(docName, layerName) {
            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);
            reference2.putEnumerated(s2t("layer"), s2t("ordinal"), s2t("targetEnum"));
            descriptor.putReference(s2t("using"), reference2);
            descriptor.putString(s2t("layerName"), layerName);
            executeAction(s2t("make"), descriptor, DialogModes.NO);
        }

        function getUniqueFilename(baseName, folderPath) {
            var version = 1;
            var fileName = baseName;
            var file = new File(folderPath + '/' + fileName + '.jpg');
            while (file.exists) {
                var paddedVersion = ("000" + version).slice(-3);
                fileName = baseName + "_v" + paddedVersion;
                file = new File(folderPath + '/' + fileName + '.jpg');
                version++;
            }
            return fileName;
        }

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

        function logExportedFile(fileName) {
            var logFile = new File(outputFolder + "/log.txt");
            logFile.open("a");
            logFile.writeln(fileName + ".jpg");
            logFile.close();
        }

        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 removeCRSmeta() {
            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() {
            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) {
        // Fail silently in headless mode
    }
})();

 

  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 as a plain text format file – .txt
  5. Rename the saved 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

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 ,
Aug 28, 2025 Aug 28, 2025

Hi, I will try it as soon as I can. But it may last a while as we are currently focussing on different projects and campaigns. So at the moment there are other more important jobs to do. But I will do further tests, when I have the time to do so. Thank you for your feedback and best regards. 

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

@Norbert252184170tz6 - OK, let me know how it goes once the priorities shift.

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