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

SCALE ARTBOARD AND CONTENT

Advocate ,
Sep 14, 2023 Sep 14, 2023

Please get this into the next update.... or is there a script out there available??

Idea No status
TOPICS
Actions and scripting , Windows
2.7K
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
24 Comments
Community Expert ,
Sep 16, 2023 Sep 16, 2023

There are multiple ways to script this, however, this is what first came to me. I have not performed exhaustive testing, use at your own risk.

 

Refer to the notes and changelog at the head of the script for more info.

 

/*
Resize Artboard and Content.jsx
v1.1 - 17th September 2023, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-ideas/scale-artboard-and-content/idi-p/14084466

Notes: 
* The artboard and content will both be resized
* The script doesn't account for layer content extending outside of the artboard bounds
* Visible layer styles such as strokes will be hidden before resizing in order to avoid unexpected sizing results!
* Layer styles are not transformed with the layer content
* The free transform control handles may not be visible when initially resizing the layer content, you can zoom in/out to correct this display glitch
      
Changelog:
v1.0 - 16th September 2023 - Inital release: Artboard was resized to fit content, ignoring transparent artboard pixels
v1.1 - 17th September 2023 - Update: Artboard and content resized honouring transparent artboard pixels
*/

#target photoshop

function main() {
    // Check if the active layer is an artboard (not layer group/set or frame)
    if (isArtboard() === true) {
        // Set the original artboard variable
        var origArtboard = activeDocument.activeLayer;
        // Get the original artboard name
        var origArtboardName = activeDocument.activeLayer.name;
        // Add a temp layer for the original artboard bounds
        artboardBoundsTempLayer();
        // Reselect the artboard
        if (activeDocument.activeLayer.parent !== activeDocument) activeDocument.activeLayer = activeDocument.activeLayer.parent;
        // Select the artboard contents
        selectActiveSetContents();
        // Hide the layer styles
        layerStyleVisibility(false);
        // Resize the artboard content
        alert("Free transform to set the new content and artboard size...");
        app.runMenuItem(stringIDToTypeID("freeTransform"));
        // Add a new artboard using the original artboard content
        app.runMenuItem(stringIDToTypeID("artboardFromLayersEvent"));
        // Delete the artbord bounds temp layer
        removeArtboardBoundsTempLayer();
        // Delete the original (now empty) artboard
        origArtboard.remove();
        // Reselect the artboard
        if (activeDocument.activeLayer.parent !== activeDocument) activeDocument.activeLayer = activeDocument.activeLayer.parent;
        // Rename the new artboard to the original artboard name
        activeDocument.activeLayer.name = origArtboardName;
        // Select the artboard contents
        selectActiveSetContents();
        // Show the layer styles
        layerStyleVisibility(true);
        // Reselect the artboard
        if (activeDocument.activeLayer.parent !== activeDocument) activeDocument.activeLayer = activeDocument.activeLayer.parent;
    } else {
        alert("Select an artboard to resize the content and artboard...");
    }
}

activeDocument.suspendHistory("Resize Artboard and Content.jsx", "main()");


///// FUNCTIONS /////

function isArtboard() {
    // modified from a script by greless with hints from jazz-y!
    // returns true or false
    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')); // test for the required key
    } catch (e) {
        //alert(e);
    }
}

function selectActiveSetContents() {
    /* https://gist.github.com/joonaspaakko/1add5c6a905216740c9c922a657636e1 */
    var doc = app.activeDocument;
    var sourceGroup = app.activeDocument.activeLayer;

    // Make a temp group with a temp layer inside it:
    // [Parent group]
    // - [TEMP GROUP]
    // - - [TEMP LAYER]

    var tempGroup = sourceGroup.layerSets.add();
    tempGroup.name = 'TEMP GROUP';
    var tempLayer = tempGroup.artLayers.add();
    tempLayer.name = 'TEMP LAYER';
    // Loop through all direct child element and move the last layer below 'TEMP LAYER'
    var children_length = sourceGroup.layers.length - 1;
    for (var i = 0; i < children_length; i++) {
        var lastLayer = sourceGroup.layers[sourceGroup.layers.length - 1];
        lastLayer.move(tempGroup.layers[0], ElementPlacement.PLACEAFTER);
    }
    // Get rid of TEMP LAYER
    tempLayer.remove();
    // Get rid of TEMP GROUP by ungrouping it, which also happens to select its children.
    doc.activeLayer = tempGroup;
    // Ungroup tempGroup
    var idungroupLayersEvent = stringIDToTypeID("ungroupLayersEvent");
    var desc702 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref427 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref427.putEnumerated(idLyr, idOrdn, idTrgt);
    desc702.putReference(idnull, ref427);
    executeAction(idungroupLayersEvent, desc702, DialogModes.NO);
}

function layerStyleVisibility(layerFXVisible) {
	function s2t(s) {
        return app.stringIDToTypeID(s);
    }
	var descriptor = new ActionDescriptor();
	var descriptor2 = new ActionDescriptor();
	var reference = new ActionReference();
	reference.putProperty( s2t( "property" ), s2t( "layerFXVisible" ));
	reference.putEnumerated( s2t( "document" ), s2t( "ordinal" ), s2t( "targetEnum" ));
	descriptor.putReference( s2t( "null" ), reference );
	descriptor2.putBoolean( s2t( "layerFXVisible" ), layerFXVisible );
	descriptor.putObject( s2t( "to" ), s2t( "layerFXVisible" ), descriptor2 );
	executeAction( s2t( "set" ), descriptor, DialogModes.NO );
}

function artboardBoundsTempLayer() {
    addTempLayer("_Temp_AB-Bounds", 0);
    function addTempLayer(theName, opacity, layerID) {
        function s2t(s) {
            return app.stringIDToTypeID(s);
        }
        var descriptor = new ActionDescriptor();
        var descriptor2 = new ActionDescriptor();
        var reference = new ActionReference();
        reference.putClass(s2t("layer"));
        descriptor.putReference(s2t("null"), reference);
        descriptor2.putString(s2t("name"), theName);
        descriptor2.putUnitDouble(s2t("opacity"), s2t("percentUnit"), opacity);
        descriptor.putObject(s2t("using"), s2t("layer"), descriptor2);
        executeAction(s2t("make"), descriptor, DialogModes.NO);
    }
    fillArtLayer(100);
    function fillArtLayer(opacity) {
        function s2t(s) {
            return app.stringIDToTypeID(s);
        }
        var descriptor = new ActionDescriptor();
        descriptor.putEnumerated(s2t("using"), s2t("fillContents"), s2t("foregroundColor"));
        descriptor.putUnitDouble(s2t("opacity"), s2t("percentUnit"), opacity);
        descriptor.putEnumerated(s2t("mode"), s2t("blendMode"), s2t("normal"));
        executeAction(s2t("fill"), descriptor, DialogModes.NO);
    }
}

function removeArtboardBoundsTempLayer() {
	function s2t(s) {
        return app.stringIDToTypeID(s);
    }
	var descriptor = new ActionDescriptor();
	var list = new ActionList();
	var reference = new ActionReference();
	reference.putName( s2t( "layer" ), "_Temp_AB-Bounds" );
	descriptor.putReference( s2t( "null" ), reference );
	descriptor.putBoolean( s2t( "makeVisible" ), false );
	executeAction(s2t( "select" ), descriptor, DialogModes.NO);
	activeDocument.activeLayer.remove();
}

 

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

Translate
Report
Community Expert ,
Sep 19, 2023 Sep 19, 2023

@Todd_Morgan 

 

Do you have any feedback on the script?

Translate
Report
Advocate ,
Sep 20, 2023 Sep 20, 2023

Thanks... will have a look.

Translate
Report
Community Beginner ,
Oct 03, 2023 Oct 03, 2023

thanks for that, i tried using it and set the free transform to scle 30% and it did scale all the layers but it didnt scale the artboard, it actully made it larger than before, since the backgroung layer it much larger than the artboard.

Translate
Report
Community Expert ,
Oct 03, 2023 Oct 03, 2023
quote

thanks for that, i tried using it and set the free transform to scle 30% and it did scale all the layers but it didnt scale the artboard, it actully made it larger than before, since the backgroung layer it much larger than the artboard.


By @Lital5E82 

 

 

Thank you for the feedback!

 

In my tests, having a true Background layer shouldn't matter, as the artboard size and content is what is being resized.

 

So do you mean that you have content in the artboard that extends beyond the visible bounds of the artboard? That would be problematic for resizing with the current coding, as that wasn't expected/taken into account.

 

I have updated the notes to include this limitation. At the moment I can't think of an easy work-around without a major rewrite of the code.

Translate
Report
Community Beginner ,
Oct 03, 2023 Oct 03, 2023

yes you understood me completly, unfortently i usually have extended content in my artboards

but i love that someone trying to do this kind of script and i hope adobe will notice and know that creating auto adjustment for artboards is a must since i think alot of people need to create banners in a lot of different sizes and auto layout/sizing is importnat for this kind of work.

so again thank u

Translate
Report
Advocate ,
Oct 22, 2024 Oct 22, 2024

Todd_Morgan_0-1729607381362.png

 i get this when running script

 

Translate
Report
Community Expert ,
Oct 22, 2024 Oct 22, 2024

@Todd_Morgan 

 

I just tested in Photoshop 2021 and 2024 and the script works as expected without error.

 

Looking at line 88, I'm not sure why you would get that error.

 

What version are you using?

 

You could try changing line 88 from:

 

var tempGroup = sourceGroup.layerSets.add();

 

To this:

 

var tempGroup = app.activeDocument.activeLayer.layerSets.add();

 

Translate
Report
Advocate ,
Oct 23, 2024 Oct 23, 2024

still getting error - I am using the latest version of PSD

Translate
Report
Advocate ,
Oct 23, 2024 Oct 23, 2024

OK so the script works if I have one artboard open and all layers selected... but if I have several artboards selected (layers are twirled closed) then I get that error...

Translate
Report
Community Expert ,
Oct 23, 2024 Oct 23, 2024

@Todd_Morgan 

 

I'll test for that, the script was only ever intended for use on a single artboard at one time.


I'm working on a new version that handles content outside of the artboard, again this is only intended for one artboard at a time.

Translate
Report
Advocate ,
Oct 23, 2024 Oct 23, 2024

OK. I wish this was already part of PSD as I have several PSB files with each 30 artboards that need resizing from 3000x to 2000x scaled content... lot's of work and I don't have any coding skills

Translate
Report
Community Expert ,
Oct 23, 2024 Oct 23, 2024

@Todd_Morgan 

 

Baby steps, once It is working for one artboard, the script can then be modified to cycle over all artboards.

 

P.S. Why not keep each artboard at 3000 px and resize the output to 2000 px when using Export As?

Translate
Report
Community Expert ,
Oct 24, 2024 Oct 24, 2024

As mentioned, here is a first draft of a new script for resizing artboards. It uses a different method than my previous script, using a script interface rather than an interactive free transform:

 

Resize Artboard & Content.png

Currently, it is only for use with a single artboard selected at a time.

 

It has not had exhaustive testing on complex artboards. Work on duplicates of any important files for safety. As resizing artboards requires canvas resizing, the script uses the Trim command to force trim to transparency, and may also benefit with saving before or after resizing an artboard to force the "shrinkwrap on save" to kick in, as the next artboard resize may not work correctly. Your insights from testing may be invaluable for getting this to work. I don't use artboards very often and I hate scripting them.

 

Use with caution!

 

/*
Resize Artboard and Content scriptUI GUI.jsx
v1.0 - 24th October, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-ideas/scale-artboard-and-content/idi-p/14084466
//////////
Notes:
* The artboard and content will both be resized
* Layer content extending outside of the artboard bounds will also be resized
* Layer styles are transformed when the proportional resize is selected
//////////
*/

// Check the active layer
if (!isLayerSet()) {
    alert("Please select an artboard before running this script.");
}

// Artboard bounds - by Rune L-H
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var artBoardRect = executeActionGet(ref).getObjectValue(stringIDToTypeID("artboard")).getObjectValue(stringIDToTypeID("artboardRect"));
var artBoardRectWidth = new UnitValue(artBoardRect.getDouble(stringIDToTypeID("right")) - artBoardRect.getDouble(stringIDToTypeID("left")), "px");
var artBoardRectHeight = new UnitValue(artBoardRect.getDouble(stringIDToTypeID("bottom")) - artBoardRect.getDouble(stringIDToTypeID("top")), "px");
artBoardRectWidth = parseInt(artBoardRectWidth);
artBoardRectHeight = parseInt(artBoardRectHeight);

// Create the main dialog window
var dlg = new Window("dialog", "Resize Artboard & Content (v1.0)");
dlg.orientation = "column";
dlg.alignChildren = "fill";

// Create resize options panel
var resizePanel = dlg.add("panel", undefined, "Resize Options");
resizePanel.orientation = "column";
resizePanel.alignChildren = "left";
resizePanel.margins = 20;

resizePanel.add("statictext", undefined, "Original Artboard Dimensions: " + artBoardRectWidth + " x " + artBoardRectHeight + " px");

// Add radio buttons
var constrained = resizePanel.add("radiobutton", undefined, "Proportional Resize");
var unconstrained = resizePanel.add("radiobutton", undefined, "Unconstrained Resize");
constrained.value = true; // Set proportional as default

// Create groups for input fields
var constrainedGroup = resizePanel.add("group");
constrainedGroup.orientation = "row";
constrainedGroup.add("statictext", undefined, "New Width (px):");
var constrainedWidth = constrainedGroup.add("editnumber", undefined, artBoardRectWidth);
constrainedWidth.characters = 6;

var unconstrainedGroup = resizePanel.add("group");
unconstrainedGroup.orientation = "row";
unconstrainedGroup.add("statictext", undefined, "New Width (px):");
var unconstrainedWidth = unconstrainedGroup.add("editnumber", undefined, artBoardRectWidth);
unconstrainedWidth.characters = 6;
unconstrainedGroup.add("statictext", undefined, "New Height (px):");
var unconstrainedHeight = unconstrainedGroup.add("editnumber", undefined, artBoardRectHeight);
unconstrainedHeight.characters = 6;

// Add dropdown for interpolation type
resizePanel.add("statictext", undefined, "Interpolation Method:");
var interTypeDropdown = resizePanel.add("dropdownlist", undefined, ["Bilinear", "Bicubic", "Bicubic Smoother", "Bicubic Sharper", "Preserve Details", "Nearest Neighbor"]);
interTypeDropdown.selection = 1; // Default to "Bicubic"

// Create button group
var buttonGroup = dlg.add("group");
buttonGroup.orientation = "row";
buttonGroup.alignment = "right";
var cancelButton = buttonGroup.add("button", undefined, "Cancel");
var okButton = buttonGroup.add("button", undefined, "OK");

// Initial state of input fields
unconstrainedGroup.enabled = false;

// Add event listeners for radio buttons
constrained.onClick = function () {
    constrainedGroup.enabled = true;
    unconstrainedGroup.enabled = false;
}

unconstrained.onClick = function () {
    constrainedGroup.enabled = false;
    unconstrainedGroup.enabled = true;
}

// Handle button clicks
cancelButton.onClick = function () {
    dlg.close();
}

okButton.onClick = function () {

    try {

        function main() {

            var savedRuler = app.preferences.rulerUnits;
            app.preferences.rulerUnits = Units.PIXELS;

            // Convert the selected layer to an embedded smart object
            executeAction(stringIDToTypeID("newPlacedLayer"), undefined, DialogModes.NO);

            // Edit the selected smart object layer
            executeAction(stringIDToTypeID("placedLayerEditContents"), new ActionDescriptor(), DialogModes.NO);

            // Trim to transparency
            app.activeDocument.trim(TrimType.TRANSPARENT);

            // Get the interpolation type
            var interType = getInterpolationType(interTypeDropdown.selection.index);
            if (constrained.value) {
                constrainedResize(parseInt(constrainedWidth.text), interType);
            } else {
                unconstrainedResize(parseInt(unconstrainedWidth.text), parseInt(unconstrainedHeight.text), interType);
            }

            // Close and save
            app.activeDocument.close(SaveOptions.SAVECHANGES);

            // Convert the smart object back to layers
            executeAction(stringIDToTypeID("placedLayerConvertToLayers"), undefined, DialogModes.NO);

            // Unlock the artboard nesting
            try {
                unlockLayer();
            } catch (e) {
                alert(e);
            }

            // Trim to transparency
            app.activeDocument.trim(TrimType.TRANSPARENT);

            // Save the document for the artboard "shrinkwrap on save" canvas resizing
            //app.activeDocument.save();
            executeAction(stringIDToTypeID("save"), undefined, DialogModes.NO);

            app.preferences.rulerUnits = savedRuler;

            dlg.close();
        }

        app.activeDocument.suspendHistory("Resize Artboard & Content", "main()");

    } catch (e) {
        alert("Error: " + e);
    }
}

/*
// Check if the document has unsaved changes and prompt to save
if (!app.activeDocument.saved) {
    var saveConfirm = confirm("The doc needs to be saved to ensure correct artboard resizing... Would you like to save it now?");
    if (saveConfirm) {
        // Save the document for the artboard "shrinkwrap on save" canvas resizing
        activeDocument.save();
    }
}
*/

// Trim to transparency
app.activeDocument.trim(TrimType.TRANSPARENT);

dlg.show();


///// Functions /////

function isLayerSet() {
    try {
        // Create a reference to the active layer
        var ref = new ActionReference();
        ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
        // Get the layer info
        var desc = executeActionGet(ref);
        // Check if the layer is a layer set (group)
        var layerKind = desc.getInteger(stringIDToTypeID("layerKind"));
        // LayerKind.LAYERSET = 7
        return layerKind === 7;
    } catch (e) {
        alert("Error checking layer type: " + e);
        return false;
    }
}

// Constrained proportions resize function
function constrainedResize(constrainedWidth, interType) {
    var idimageSize = stringIDToTypeID("imageSize");
    var desc384 = new ActionDescriptor();
    var idwidth = stringIDToTypeID("width");
    var idpixelsUnit = stringIDToTypeID("pixelsUnit");
    desc384.putUnitDouble(idwidth, idpixelsUnit, constrainedWidth);
    var idscaleStyles = stringIDToTypeID("scaleStyles");
    desc384.putBoolean(idscaleStyles, true);
    var idconstrainProportions = stringIDToTypeID("constrainProportions");
    desc384.putBoolean(idconstrainProportions, true);
    var idinterpolationType = stringIDToTypeID("interpolationType");
    desc384.putEnumerated(idinterpolationType, idinterpolationType, interType);
    executeAction(idimageSize, desc384, DialogModes.NO);
}

// Unconstrained proportions resize function
function unconstrainedResize(unconstrainedWidth, unconstrainedHeight, interType) {
    var idimageSize = stringIDToTypeID("imageSize");
    var desc398 = new ActionDescriptor();
    var idwidth = stringIDToTypeID("width");
    var idpixelsUnit = stringIDToTypeID("pixelsUnit");
    desc398.putUnitDouble(idwidth, idpixelsUnit, unconstrainedWidth);
    var idheight = stringIDToTypeID("height");
    desc398.putUnitDouble(idheight, idpixelsUnit, unconstrainedHeight);
    var idinterpolationType = stringIDToTypeID("interpolationType");
    desc398.putEnumerated(idinterpolationType, idinterpolationType, interType);
    executeAction(idimageSize, desc398, DialogModes.NO);
}

function unlockLayer() {
    var desc = new ActionDescriptor();
    var ref = new ActionReference();
    ref.putEnumerated(
        stringIDToTypeID("layer"),
        stringIDToTypeID("ordinal"),
        stringIDToTypeID("targetEnum")
    );
    desc.putReference(stringIDToTypeID("null"), ref);
    var lockingDesc = new ActionDescriptor();
    lockingDesc.putBoolean(stringIDToTypeID("protectNone"), true);
    desc.putObject(
        stringIDToTypeID("layerLocking"),
        stringIDToTypeID("layerLocking"),
        lockingDesc
    );
    executeAction(stringIDToTypeID("applyLocking"), desc, DialogModes.NO);
}

// Function to map dropdown selection to stringIDToTypeID for interpolation
function getInterpolationType(index) {
    switch (index) {
        case 0: return stringIDToTypeID("bilinear");
        case 1: return stringIDToTypeID("bicubic");
        case 2: return stringIDToTypeID("bicubicSmoother");
        case 3: return stringIDToTypeID("bicubicSharper");
        case 4: return stringIDToTypeID("preserveDetailsUpscale");
        case 5: return stringIDToTypeID("nearestNeighbor");
        default: return stringIDToTypeID("bicubic");
    }
}

 

 

Translate
Report
Advocate ,
Oct 24, 2024 Oct 24, 2024

Will most lkkely do that - but for future use by client don't want blowback when they have the files and forget to output scaled down to 2000x...

Translate
Report
Community Expert ,
Oct 24, 2024 Oct 24, 2024

@Todd_Morgan 

 

Fair enough, let me know how things go with the new script. If it is working for you I'll look into extending it to process multiple artboards.

Translate
Report
New Here ,
Jan 21, 2025 Jan 21, 2025

Thank you so much, been copying, pasting and manualy tweaking till now, this works perfectly for me!

Translate
Report
Community Expert ,
Jan 21, 2025 Jan 21, 2025
quote

Thank you so much, been copying, pasting and manualy tweaking till now, this works perfectly for me!


By @Luc Quevauvilliers 

 

Thank you for taking the time to provide feedback!

Translate
Report
Advocate ,
Feb 10, 2025 Feb 10, 2025

Hi @Stephen Marsh ... any word on the multiple artboards script?

Translate
Report
Community Expert ,
Feb 10, 2025 Feb 10, 2025

@Todd_Morgan - As I didn't receive any feedback from you, I didn't look at extending this beyond the active artboard. 

 

EDIT:

 

* Thinking this through, for a script to automate the resizing of all artboards, if resizing in pixels, then all artboards would need to have the same px values, or at least the same edge being resized (width or height).


* If proportionally resizing by %, then all artboards could be processed, whether or not they had the same px values. But again, one would need to pick a consistent width or height value.

 

Do you agree? Am I missing anything? Any other comments?

 

I think you need to explain the resizing requirements and rules required.

Translate
Report
Contributor ,
Aug 23, 2025 Aug 23, 2025

Thank you for the very useful script. Would it be possible to modify it so that it does not create new instances of smart objects in the transformed artboard? Example: a document with many artboards of different sizes, but containing the same (linked) smart object - after editing which it is updated in all artboards. In the script-transformed artboard, new instances of smart objects are created that are not linked to the original smart object. This somewhat limits the usability of the script.

Translate
Report
Community Expert ,
Aug 23, 2025 Aug 23, 2025

@rudo123 

 

Thank you for the feedback.

 

I'm guessing that it's the process of making the artboard a smart object that messes up existing smart objects.

 

I'll look into an alternative method to isolate and resize.

 

EDIT: I also tried artboard duplication to/from a temporary new document, which also broke the embedded smart object. As these script variations using new documents do not retain the natural "links/references" to embedded smart objects, you might need to take a look at the first script that I posted, using the interactive transform to resize. The drawback is that content extending outside the artboard bounds is not correctly handled by the transform, nor is layer style scaling.

 

Perhaps someone has a creative workaround...

Translate
Report
Contributor ,
Aug 24, 2025 Aug 24, 2025

OK, thanks for the effort. Maybe Adobe will implement this functionality directly, without the need for a script...

Translate
Report
Community Expert ,
Aug 24, 2025 Aug 24, 2025
LATEST

I wouldn't hold my breath, but there's hope.

Translate
Report