Skip to main content
Participating Frequently
March 17, 2025
Answered

How to batch aligning text and scaling the shape in photoshop

  • March 17, 2025
  • 3 replies
  • 739 views

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!

 

 

 

 

Correct answer c.pfaffenbichler

// 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

3 replies

c.pfaffenbichler
Community Expert
c.pfaffenbichlerCommunity ExpertCorrect answer
Community Expert
March 19, 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 = 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

Alice392Author
Participating Frequently
March 19, 2025

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

Alice392Author
Participating Frequently
March 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 );
};

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!

Alice392Author
Participating Frequently
March 18, 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!

Alice392Author
Participating Frequently
March 17, 2025

here is an example