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

How to batch aligning text and scaling the shape in photoshop

Community Beginner ,
Mar 17, 2025 Mar 17, 2025

Hello everyone! I'm having trouble with many text layers and shape layers that need to be aligned and scaled. Doing this manually would take a lot of time, so I want to write a script to help automate the process. I previously tried using AI for this, but it didn't work well.

All text and shape layers are grouped together, and sometimes their order isn't aligned properly. Usually, I select the text layer and the shape below it manually, center them, and then scale the shape. I do this by selecting the text, expanding it by a certain number (e.g., 100px, 45px), and scaling the shape to cover it while maintaining its proportions.

Not all text layers have a shape below them, so I will skip those. I've attached a PSD sample for reference.

Does anyone have any suggestions? If you can help, I would greatly appreciate it. Thank you for your interest in this topic!

 

 

 

 

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

correct answers 1 Correct answer

Community Expert , Mar 19, 2025 Mar 19, 2025

Screenshot 2025-03-19 at 15.20.03.pngScreenshot 2025-03-19 at 15.20.29.png

// scale shape layers beneath type layers to their width plus two times theAdd;
// 2025, use it at your own risk;
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// horizontal offset;
var theAdd = 100;
var theVertAdd = 171;
// collect type layers;
var theLayers = collectTypeLayers ();
var theCounter = 0;
// check for shape layers;
for (var m = 0; m < theLayers.length; m++) {
    
...
Translate
Adobe
Community Beginner ,
Mar 17, 2025 Mar 17, 2025

Alice392_0-1742232022136.png

Alice392_1-1742232030422.png

here is an example

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 ,
Mar 17, 2025 Mar 17, 2025
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 ,
Mar 17, 2025 Mar 17, 2025

Thank you so much for your reply. I have seen the post and tried to apply it to my workflow, but it only works with rasterized layers. I need to preserve the shape path and cannot use a smart object, as my client specifically requested to keep the shape intact.
I attempted to use AI for customization, but it didn’t turn out well. Additionally, the code you provided is meant for text layers that have a stroke applied. However, I have many layer styles that I need to use, so applying a stroke is not an option for me. Instead, I am using selection tools to deselect layers more quickly. Could you please help me with this? I would greatly appreciate your assistance!

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 ,
Mar 19, 2025 Mar 19, 2025

Screenshot 2025-03-19 at 15.20.03.pngScreenshot 2025-03-19 at 15.20.29.png

// scale shape layers beneath type layers to their width plus two times theAdd;
// 2025, use it at your own risk;
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// horizontal offset;
var theAdd = 100;
var theVertAdd = 171;
// collect type layers;
var theLayers = collectTypeLayers ();
var theCounter = 0;
// check for shape layers;
for (var m = 0; m < theLayers.length; m++) {
    var thisOne = theLayers[m];
    var ref = new ActionReference();
    ref.putIndex( charIDToTypeID("Lyr "), theLayers[m][1]-1/*+theCounter*/ ); 
    var layerDesc = executeActionGet(ref);
    var layerKind = layerDesc.getInteger(stringIDToTypeID("layerKind"));
    if (layerKind == 4) {
        var thisID = layerDesc.getInteger(stringIDToTypeID("layerID"));
        var theBoundsNoFx = layerDesc.getObjectValue(stringIDToTypeID("boundsNoEffects"));
        var X1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("left"));
        var X2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("right"));
        var Y1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("top"));
        var Y2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("bottom"));
        var theW = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("width"));
        var theH = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("height"));
        var xOffset = (thisOne[3][0]+thisOne[4]/2) - (X1+theW/2);
        var yOffset = (thisOne[3][1]+thisOne[5]/2) - (Y1+theH/2);
//        var theScale = ((thisOne[4]+2*theAdd)/theW*100);// Math((thisOne[5]+2*theAdd)/theH*100)
        var theScale = Math.max(((thisOne[4]+2*theAdd)/theW*100), ((thisOne[5]+2*theVertAdd)/theH*100));
        layerDuplicateScaleRotate (thisID, false, xOffset, yOffset, theScale, theScale, 0);
        theCounter++
    }
};
// reset;
app.preferences.rulerUnits = originalRulerUnits;
};
////////////////////////////////////
function collectTypeLayers () {
// the file;
var myDocument = app.activeDocument;
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if not layer group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true ) {

if (layerDesc.hasKey(stringIDToTypeID('smartObject')) == true || layerDesc.hasKey(stringIDToTypeID("textKey")) == true) {

var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));

var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theBoundsNoFx = layerDesc.getObjectValue(stringIDToTypeID("boundsNoEffects"));
var X1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("left"));
var X2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("right"));
var Y1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("top"));
var Y2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("bottom"));
var theW = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("width"));
var theH = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("height"));

theLayers.push([theName, theIndex, theID, [X1, Y1, X2, Y2], theW, theH])
}
};
}
catch (e) {};
};
return theLayers
};
// based on code by mike hale, via paul riggott;
function selectLayerByID(id,add){ 
add = undefined ? add = false:add 
var ref = new ActionReference();
    ref.putIdentifier(charIDToTypeID("Lyr "), id);
    var desc = new ActionDescriptor();
    desc.putReference(charIDToTypeID("null"), ref );
       if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
      desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
   try{
    executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message); 
}
};
////// duplicate layer (id, xOffset, yOffset, theXScale, theYScale, theAngle) //////
function layerDuplicateScaleRotate (theID, theDuplicate, xOffset, yOffset, theXScale, theYScale, theAngle) {
selectLayerByID(theID, false);
// =======================================================
var desc23 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref2 = new ActionReference();
ref2.putIdentifier ( charIDToTypeID( "Lyr " ), theID );
//        ref2.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc23.putReference( idnull, ref2 );
desc23.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsa" ) );
var idOfst = charIDToTypeID( "Ofst" );
var desc24 = new ActionDescriptor();
var idPxl = charIDToTypeID( "#Pxl" );
desc24.putUnitDouble( charIDToTypeID( "Hrzn" ), idPxl, xOffset );
desc24.putUnitDouble( charIDToTypeID( "Vrtc" ), idPxl, yOffset );
var idOfst = charIDToTypeID( "Ofst" );
desc23.putObject( idOfst, idOfst, desc24 );
var idPrc = charIDToTypeID( "#Prc" );
desc23.putUnitDouble( charIDToTypeID( "Wdth" ), idPrc, theXScale );
desc23.putUnitDouble( charIDToTypeID( "Hght" ), idPrc, theYScale );
desc23.putUnitDouble( charIDToTypeID( "Angl" ), charIDToTypeID( "#Ang" ), theAngle );
desc23.putEnumerated( charIDToTypeID( "Intr" ), charIDToTypeID( "Intp" ), stringIDToTypeID( "bicubicAutomatic" ) );
desc23.putBoolean( charIDToTypeID( "Cpy " ), theDuplicate );
executeAction( charIDToTypeID( "Trnf" ), desc23, DialogModes.NO );
};

edited 2025-03-20

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 ,
Mar 19, 2025 Mar 19, 2025

I truly appreciate all your support—thank you! Your help means a lot to me!  😄 😄 😄

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 ,
Mar 20, 2025 Mar 20, 2025

I am afraid I overlooked a point – I only conditioned the scaling on the width of the type layer. 

You actually mentioned a vertial distance, too, but I suppose in the sample file all the type layers were fairly wide anyway so it didn’t make a difference. 

I hope I’ll get around to amending the code in the coming days. 

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 ,
Mar 20, 2025 Mar 20, 2025

Absolutely! I would be so grateful if you could lend a hand with fixing the code sometime in the coming days. Thank you so much for your concern.

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 ,
Mar 20, 2025 Mar 20, 2025

I updated the code, I hope this meets the original intention (see screenshots). 

Screenshot 2025-03-20 at 16.42.18.pngScreenshot 2025-03-20 at 16.42.23.png

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 ,
Mar 20, 2025 Mar 20, 2025

Thank you for your help, it works wonderfully. If possible, could you assist me in adding a condition so that if the horizontal and vertical additions are equal, the shape will scale disproportionately? It looks like this picture, it will help me to work more flexiable. I really appreciate it!

Alice392_0-1742487359973.png

 

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 ,
Mar 21, 2025 Mar 21, 2025
// scale shape layers beneath type layers to their width plus two times theAdd;
// 2025, use it at your own risk;
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// horizontal offset;
var theAdd = 101;
var theVertAdd = 101;
// collect type layers;
var theLayers = collectTypeLayers ();
var theCounter = 0;
// check for shape layers;
for (var m = 0; m < theLayers.length; m++) {
    var thisOne = theLayers[m];
    var ref = new ActionReference();
    ref.putIndex( charIDToTypeID("Lyr "), theLayers[m][1]-1/*+theCounter*/ ); 
    var layerDesc = executeActionGet(ref);
    var layerKind = layerDesc.getInteger(stringIDToTypeID("layerKind"));
    if (layerKind == 4) {
        var thisID = layerDesc.getInteger(stringIDToTypeID("layerID"));
        var theBoundsNoFx = layerDesc.getObjectValue(stringIDToTypeID("boundsNoEffects"));
        var X1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("left"));
        var X2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("right"));
        var Y1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("top"));
        var Y2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("bottom"));
        var theW = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("width"));
        var theH = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("height"));
        var xOffset = (thisOne[3][0]+thisOne[4]/2) - (X1+theW/2);
        var yOffset = (thisOne[3][1]+thisOne[5]/2) - (Y1+theH/2);
        if (theAdd != theVertAdd) {
            var theXScale = Math.max(((thisOne[4]+2*theAdd)/theW*100), ((thisOne[5]+2*theVertAdd)/theH*100));
            var theYScale = theXScale
        }
        else {
            var theXScale = ((thisOne[4]+2*theAdd)/theW*100)
            var theYScale = ((thisOne[5]+2*theVertAdd)/theH*100);

        };
        layerDuplicateScaleRotate (thisID, false, xOffset, yOffset, theXScale, theYScale, 0);
        theCounter++
    }
};
// reset;
app.preferences.rulerUnits = originalRulerUnits;
};
////////////////////////////////////
function collectTypeLayers () {
// the file;
var myDocument = app.activeDocument;
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if not layer group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true ) {

if (layerDesc.hasKey(stringIDToTypeID('smartObject')) == true || layerDesc.hasKey(stringIDToTypeID("textKey")) == true) {

var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));

var theBounds = layerDesc.getObjectValue(stringIDToTypeID("bounds"));
var theBoundsNoFx = layerDesc.getObjectValue(stringIDToTypeID("boundsNoEffects"));
var X1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("left"));
var X2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("right"));
var Y1 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("top"));
var Y2 = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("bottom"));
var theW = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("width"));
var theH = theBoundsNoFx.getUnitDoubleValue(stringIDToTypeID("height"));

theLayers.push([theName, theIndex, theID, [X1, Y1, X2, Y2], theW, theH])
}
};
}
catch (e) {};
};
return theLayers
};
// based on code by mike hale, via paul riggott;
function selectLayerByID(id,add){ 
add = undefined ? add = false:add 
var ref = new ActionReference();
    ref.putIdentifier(charIDToTypeID("Lyr "), id);
    var desc = new ActionDescriptor();
    desc.putReference(charIDToTypeID("null"), ref );
       if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
      desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
   try{
    executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message); 
}
};
////// duplicate layer (id, xOffset, yOffset, theXScale, theYScale, theAngle) //////
function layerDuplicateScaleRotate (theID, theDuplicate, xOffset, yOffset, theXScale, theYScale, theAngle) {
selectLayerByID(theID, false);
// =======================================================
var desc23 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref2 = new ActionReference();
ref2.putIdentifier ( charIDToTypeID( "Lyr " ), theID );
//        ref2.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc23.putReference( idnull, ref2 );
desc23.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsa" ) );
var idOfst = charIDToTypeID( "Ofst" );
var desc24 = new ActionDescriptor();
var idPxl = charIDToTypeID( "#Pxl" );
desc24.putUnitDouble( charIDToTypeID( "Hrzn" ), idPxl, xOffset );
desc24.putUnitDouble( charIDToTypeID( "Vrtc" ), idPxl, yOffset );
var idOfst = charIDToTypeID( "Ofst" );
desc23.putObject( idOfst, idOfst, desc24 );
var idPrc = charIDToTypeID( "#Prc" );
desc23.putUnitDouble( charIDToTypeID( "Wdth" ), idPrc, theXScale );
desc23.putUnitDouble( charIDToTypeID( "Hght" ), idPrc, theYScale );
desc23.putUnitDouble( charIDToTypeID( "Angl" ), charIDToTypeID( "#Ang" ), theAngle );
desc23.putEnumerated( charIDToTypeID( "Intr" ), charIDToTypeID( "Intp" ), stringIDToTypeID( "bicubicAutomatic" ) );
desc23.putBoolean( charIDToTypeID( "Cpy " ), theDuplicate );
executeAction( charIDToTypeID( "Trnf" ), desc23, DialogModes.NO );
};
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 ,
Mar 21, 2025 Mar 21, 2025
LATEST

I sincerely appreciate your help! These tools fit so well into my workflow and have made a huge difference in my productivity. Thank you once again for your support!

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