Copy link to clipboard
Copied
Question: There are thousands of text layers in my PS document, and now I need to rotate all the text 180 degrees in place. Please tell me how to operate? I don’t want to rotate them one by one. Thank you so much.
Please try this version:
// rotate all type layers;
// 2023, use it at your own risk;
if (app.documents.length > 0) {
var theLayers = collectTypeLayers();
for (var m = 0; m < theLayers.length; m++) {
if (theLayers[m][2] == false) {
showHideLayer (theLayers[m][1], "show");
};
selectLayerByID(theLayers[m][1], false);
scaleRotateLayer (100, 180, 0, 0);
if (theLayers[m][2] == false) {
showHideLayer (theLayers[m][1], "hide")
};
}
};
////////////////////////////////////
function collectTypeLayers ()
...
Copy link to clipboard
Copied
We need to know whether text layers are one above another or scattered in the Layers panel. If you have text layers one above another in the Layers panel simple action can do the trick. You will need to select text layer then record step to rotate it. Record step to select next layer above. Duplicate those two steps as many times as you want then play action. If you have thousands layers then duplicate two steps hundred times and play action several times for example. It can be little tricky to not play action twice to the same layer so watch what is going on in the Layers panel.
There are some tricks you can use to avoid playing rotate on the same layer twice but that will require Conditional actions which are more advanced.
Here is example that provides a straightforward approach to automating tasks in Photoshop using a two-step action that can be duplicated as needed. For more complex actions, the use of Conditional actions or scripts may be necessary. I recommend reaching out to experienced scripters who can offer further assistance @Stephen_A_Marsh @c.pfaffenbichler
Copy link to clipboard
Copied
@Bojan Živković Thank you very much for your patient help. My problem @c.pfaffenbichler has been solved for me. Thank you again. I wish you a happy life and happiness every day!
Copy link to clipboard
Copied
Please try this (updated):
// rotate all type layers;
// 2023, use it at your own risk;
if (app.documents.length > 0) {
var theLayers = collectTypeLayers();
for (var m = 0; m < theLayers.length; m++) {
selectLayerByID(theLayers[m][1], false);
scaleRotateLayer (100, 180, 0, 0)
}
};
////////////////////////////////////
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 && layerDesc.hasKey(stringIDToTypeID("textKey")) == true) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
theLayers.push([theName, theID])
};
}
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);
}
};
////// scale active layer to canvas dimensions //////
function scaleRotateLayer (theScale, theAngle, offsetX, offsetY) {
try {
// scale layer:
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// transform;
var desc23 = new ActionDescriptor();
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc23.putReference( charIDToTypeID( "null" ), ref2 );
var idOfst = charIDToTypeID( "Ofst" );
var desc24 = new ActionDescriptor();
var idPxl = charIDToTypeID( "#Pxl" );
desc24.putUnitDouble( charIDToTypeID( "Hrzn" ), idPxl, offsetX );
desc24.putUnitDouble( charIDToTypeID( "Vrtc" ), idPxl, offsetY );
desc23.putObject( idOfst, idOfst, desc24 );
var idPrc = charIDToTypeID( "#Prc" );
desc23.putUnitDouble( charIDToTypeID( "Wdth" ), idPrc, theScale );
desc23.putUnitDouble( charIDToTypeID( "Hght" ), idPrc, theScale );
desc23.putUnitDouble( charIDToTypeID( "Angl" ), charIDToTypeID( "#Ang" ), theAngle );
desc23.putEnumerated( charIDToTypeID( "Intr" ), charIDToTypeID( "Intp" ), stringIDToTypeID( "bicubicAutomatic" ) );
desc23.putEnumerated( stringIDToTypeID( "freeTransformCenterState" ), stringIDToTypeID( "quadCenterState" ), stringIDToTypeID( "QCSAverage" ) );
// desc23.putBoolean( charIDToTypeID( "Cpy " ), true );
executeAction( charIDToTypeID( "Trnf" ), desc23, DialogModes.NO );
app.preferences.rulerUnits = originalRulerUnits;
} catch (e) {}
};
Copy link to clipboard
Copied
Nice one, you beat me to it! As I have already started my coding, I may as well post it anyway once I've completed it...
Copy link to clipboard
Copied
This script only rotates text layers 180° if they are a top-level layer (i.e. not in a layer set or nested set in set).
/*
Rotate All Top Level Text Layers 180 degrees.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-batch-rotate-text-layers-in-place/td-p/14112213
v1.0, 26th September 2023, Stephen Marsh
*/
#target photoshop
function main() {
// Hack to ensure that a layer is selected
activeDocument.artLayers.add();
activeDocument.activeLayer.remove();
var counter = 0;
// Start Timer
var timeDiff = {
setStartTime: function () {
d = new Date();
time = d.getTime();
},
getDiff: function () {
d = new Date();
t = d.getTime() - time;
time = d.getTime();
return t;
}
};
timeDiff.setStartTime();
// Loop over the text layers and rotate them
for (var i = 0; i < activeDocument.layers.length; i++) {
try {
activeDocument.activeLayer = activeDocument.layers[i];
if (app.activeDocument.activeLayer.kind == LayerKind.TEXT) {
transformRotate(180);
counter++;
}
} catch (e) {}
}
alert(counter + " text layers rotated!" + "\r" + "Run Time: " + timeDiff.getDiff() / 1000 + " seconds");
}
activeDocument.suspendHistory("Rotate All Top Level Text Layers 180 degrees...", "main()");
function transformRotate(angle) {
function s2t(s) {
return app.stringIDToTypeID(s);
}
var descriptor = new ActionDescriptor();
descriptor.putUnitDouble(s2t("angle"), s2t("angleUnit"), angle);
executeAction(s2t("rotateEventEnum"), descriptor, DialogModes.NO);
}
I'll post updated code to work with groups/sets later.
Copy link to clipboard
Copied
This one will process text layers within layer groups and nested layer groups:
/*
Rotate All Text Layers 180 degrees.jsx
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-batch-rotate-text-layers-in-place/td-p/14112213
v1.0, 26th September 2023, Stephen Marsh
*/
#target photoshop
activeDocument.suspendHistory('Rotate All Text Layers 180 degrees.jsx', 'main()');
function main() {
if (!documents.length) {
alert('There are no documents open!');
} else {
var counter = 0;
// Start Timer
var timeDiff = {
setStartTime: function () {
d = new Date();
time = d.getTime();
},
getDiff: function () {
d = new Date();
t = d.getTime() - time;
time = d.getTime();
return t;
}
};
timeDiff.setStartTime();
processAllLayersAndSets(app.activeDocument);
alert(counter + " text layers rotated!" + "\r" + "Run Time: " + timeDiff.getDiff() / 1000 + " seconds");
}
function processAllLayersAndSets(obj) {
// Process Layers
for (var i = obj.artLayers.length - 1; 0 <= i; i--) {
app.activeDocument.activeLayer = obj.artLayers[i];
if (app.activeDocument.activeLayer.kind == LayerKind.TEXT) {
transformRotate(180);
counter++;
}
}
// Process Layer Set Layers
for (var j = obj.layerSets.length - 1; 0 <= j; j--) {
processAllLayersAndSets(obj.layerSets[j]);
}
}
function transformRotate(angle) {
function s2t(s) {
return app.stringIDToTypeID(s);
}
var descriptor = new ActionDescriptor();
descriptor.putUnitDouble(s2t("angle"), s2t("angleUnit"), angle);
executeAction(s2t("rotateEventEnum"), descriptor, DialogModes.NO);
}
}
Copy link to clipboard
Copied
Thank you very much. I tried it just now, but an error occurred and the rotation was unsuccessful. Figure 2 is my document.
Copy link to clipboard
Copied
@LiuFei刘飞 – What version of Photoshop are you using?
You can try replacing the function with slightly different code, but this is based off v2021 as the previous, so may still have issues in your version:
function transformRotate(angle) {
var desc1 = new ActionDescriptor();
desc1.putUnitDouble(cTID('Angl'), cTID('#Ang'), angle);
executeAction(cTID('Rtte'), desc1, DialogModes.NO);
}
This function was created in v2022:
function transformRotate(angle) {
var s2t = function (s) {
return app.stringIDToTypeID(s);
};
var descriptor = new ActionDescriptor();
var reference = new ActionReference();
reference.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));
descriptor.putReference( s2t( "null" ), reference );
descriptor.putUnitDouble( s2t( "angle" ), s2t( "angleUnit" ), angle );
executeAction( s2t( "rotateEventEnum" ), descriptor, DialogModes.NO );
}
Or another one from v2022:
function transformRotate(angle) {
var idrotateEventEnum = stringIDToTypeID( "rotateEventEnum" );
var desc278 = new ActionDescriptor();
var idangle = stringIDToTypeID( "angle" );
var idangleUnit = stringIDToTypeID( "angleUnit" );
desc278.putUnitDouble( idangle, idangleUnit, angle );
executeAction( idrotateEventEnum, desc278, DialogModes.NO );
}
Copy link to clipboard
Copied
@Stephen_A_Marsh 24.7.0
Copy link to clipboard
Copied
@Stephen_A_Marsh Thank you for your patience and help. I don’t know English and I used a translation software to translate it. The expression may not be very accurate.
Copy link to clipboard
Copied
The following function was recorded and tested in the latest v2024:
function transformRotate(angle) {
var idrotateEventEnum = stringIDToTypeID( "rotateEventEnum" );
var desc226 = new ActionDescriptor();
var idnull = stringIDToTypeID( "null" );
var ref1 = new ActionReference();
var idlayer = stringIDToTypeID( "layer" );
var idordinal = stringIDToTypeID( "ordinal" );
var idtargetEnum = stringIDToTypeID( "targetEnum" );
ref1.putEnumerated( idlayer, idordinal, idtargetEnum );
desc226.putReference( idnull, ref1 );
var idangle = stringIDToTypeID( "angle" );
var idangleUnit = stringIDToTypeID( "angleUnit" );
desc226.putUnitDouble( idangle, idangleUnit, angle );
executeAction( idrotateEventEnum, desc226, DialogModes.NO );
}
Copy link to clipboard
Copied
@Stephen_A_Marsh I can’t write scripts and I can’t read scripts. I copied the last piece of code you sent me into notepad and saved it as .jsx, then browsed the file in PS. I noticed nothing happened. Is this just a piece of code? I can't understand the code. You can send me all the code together. Sorry for the trouble, thank you very much.
Copy link to clipboard
Copied
You can also try the one I posted.
Save the code as a txt-file, change the extension to .jsx and copy it into Photoshop’s Presets/Scripts-Folder; after restarting Photoshop it should be available under File > Scripts and can be assigned a Shortcut or used in an Action.
Copy link to clipboard
Copied
@c.pfaffenbichler OK, I'll try it, thank you very much
Copy link to clipboard
Copied
@c.pfaffenbichler Still not working, am I too stupid and using the wrong method? Take a look at the attached screenshot I sent
Copy link to clipboard
Copied
You had not mentioned that there are hidden Type Layers.
I updated the code with a try-clause that will not rotate them but at least will not stop because of them.
Copy link to clipboard
Copied
Please try this version:
// rotate all type layers;
// 2023, use it at your own risk;
if (app.documents.length > 0) {
var theLayers = collectTypeLayers();
for (var m = 0; m < theLayers.length; m++) {
if (theLayers[m][2] == false) {
showHideLayer (theLayers[m][1], "show");
};
selectLayerByID(theLayers[m][1], false);
scaleRotateLayer (100, 180, 0, 0);
if (theLayers[m][2] == false) {
showHideLayer (theLayers[m][1], "hide")
};
}
};
////////////////////////////////////
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 && layerDesc.hasKey(stringIDToTypeID("textKey")) == true) {
var visible = layerDesc.getBoolean(stringIDToTypeID("visible"));
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
theLayers.push([theName, theID, visible])
};
}
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);
}
};
////// scale active layer to canvas dimensions //////
function scaleRotateLayer (theScale, theAngle, offsetX, offsetY) {
try {
// scale layer:
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// transform;
var desc23 = new ActionDescriptor();
var ref2 = new ActionReference();
ref2.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc23.putReference( charIDToTypeID( "null" ), ref2 );
var idOfst = charIDToTypeID( "Ofst" );
var desc24 = new ActionDescriptor();
var idPxl = charIDToTypeID( "#Pxl" );
desc24.putUnitDouble( charIDToTypeID( "Hrzn" ), idPxl, offsetX );
desc24.putUnitDouble( charIDToTypeID( "Vrtc" ), idPxl, offsetY );
desc23.putObject( idOfst, idOfst, desc24 );
var idPrc = charIDToTypeID( "#Prc" );
desc23.putUnitDouble( charIDToTypeID( "Wdth" ), idPrc, theScale );
desc23.putUnitDouble( charIDToTypeID( "Hght" ), idPrc, theScale );
desc23.putUnitDouble( charIDToTypeID( "Angl" ), charIDToTypeID( "#Ang" ), theAngle );
desc23.putEnumerated( charIDToTypeID( "Intr" ), charIDToTypeID( "Intp" ), stringIDToTypeID( "bicubicAutomatic" ) );
desc23.putEnumerated( stringIDToTypeID( "freeTransformCenterState" ), stringIDToTypeID( "quadCenterState" ), stringIDToTypeID( "QCSAverage" ) );
// desc23.putBoolean( charIDToTypeID( "Cpy " ), true );
executeAction( charIDToTypeID( "Trnf" ), desc23, DialogModes.NO );
app.preferences.rulerUnits = originalRulerUnits;
} catch (e) {}
};
////// show or hide layer //////
function showHideLayer (theId, theOp) {
var idhide = stringIDToTypeID( theOp );
var desc22 = new ActionDescriptor();
var list2 = new ActionList();
var ref8 = new ActionReference();
ref8.putIdentifier( stringIDToTypeID( "layer" ), theId );
list2.putReference( ref8 );
desc22.putList( stringIDToTypeID( "null" ), list2 );
executeAction( idhide, desc22, DialogModes.NO );
};
Copy link to clipboard
Copied
This version works, you’re awesome. Except for the text in the variable pen shape layer, which is rotated incorrectly, all other text is OK. I just manually change the text in the variable pen shape layer. The text in the normal layer is very good. 90% of the workload has been solved. Thank you very much.
Copy link to clipboard
Copied
I was hoping that you could replace the function block in the original script with the different functions of the same name.
I'll have to do that for you tomorrow.
Copy link to clipboard
Copied
@Stephen_A_Marsh I still didn't get it right, maybe I'm a little stupid and don't know if I'm doing it right.
Thank you very much for your patient guidance. I'm from China, it's night now, I wonder which country are you friends from?
Copy link to clipboard
Copied
My document is very large, with nearly 10,000 text layers. I need to convert the image 180 degrees from north to south, but the text is upside down. It is too tiring to do it one by one manually, so I want to use a simple method to batch rotate 180 degrees.
Copy link to clipboard
Copied
@Stephen_A_Marsh Thank you very much for your patient help. My problem @c.pfaffenbichler has been solved for me. Thank you again. I wish you a happy life and happiness every day!
Copy link to clipboard
Copied
@Stephen_A_Marsh Thank you very much for your patient help. My problem @c.pfaffenbichler has been solved for me. Thank you again. I wish you a happy life and happiness every day!
By @LiuFei刘飞
You're welcome, I didn't expect you to have hidden text layers, my code makes them visible.
Please mark the answer from @c.pfaffenbichler as the correct answer.