Rotate layers incremental script
Copy link to clipboard
Copied
hello!
I have 8 layers (photos) each one rotated 45º.
I want counter rotate all layers automatically but I don’t know how do a script that rotate each layer incrementally
something like:
layer.index * 45
result
layer0 = 0º
layer1 = 45º
layer2 = 90º
layer3 = 135º
...
layer8 = 315º
it would be nice a menu to indicate angle of rotation and a checkbox for clockwise or counterclockwise
Thanks!
Explore related tutorials & articles
Copy link to clipboard
Copied
It is easy to rotate a layer about a point. You need to know what x,y point and the angle. You can use layer bounds to get the anchor points for the layer. The rotation point can be any x,y point you want to use. Make the layer the active layer and use a function like this this rotate the layer. To code your dialog will be much more complex.
function rotateAroundPosition(_angle,x,y) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
desc1.putEnumerated(charIDToTypeID('FTcs'), charIDToTypeID('QCSt'), stringIDToTypeID("QCSIndependent"));
desc2.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x);
desc2.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y);
desc1.putObject(charIDToTypeID('Pstn'), charIDToTypeID('Pnt '), desc2);
desc1.putUnitDouble(charIDToTypeID('Angl'), charIDToTypeID('#Ang'), _angle);
desc1.putEnumerated(charIDToTypeID('Intr'), charIDToTypeID('Intp'), charIDToTypeID('Bcbc'));
executeAction(charIDToTypeID('Trnf'), desc1, DialogModes.NO);
}
Copy link to clipboard
Copied
Wow thanks for your response and time!
I did not thought that was need too much code only for rotate a layer from center point! Amazing
Your code will rotate all layers selected incrementally automatically? I mean if I selected 7 layers of my 8 layers (layer 0 no need be rotated), each layer will rotate 45º incrementally: layer 1 = 45º, Layer 2 = 90º, Layer 3 = 135º .... Layer 7 = 315º ?
I tried to put your code to a .js file, select a layer and launch but seems that nothing happen. Maybe I need to change something in script to work...
Thanks!
Copy link to clipboard
Copied
You need to pass the function three variables +-Angle the X point position and the y point position. anf the layer yow want toe be rotated need to be the document active layer.
The function is used in my rotate layers about script. A script the duplicates a layer and rotate it about poins a number of times to do full 360 rotation.
// 2015 John J. McAssey (JJMack)
// ======================================================= */
// This script is supplied as is. It is provided as freeware.
// The author accepts no liability for any problems arising from its use.
// enable double-clicking from Mac Finder or Windows Explorer
#target photoshop // this command only works in Photoshop CS2 and higher
// bring application forward for double-click events
app.bringToFront();
// ensure at least one document open
if (!documents.length) alert('There are no documents open.', 'No Document');
else {
//Set First Time Defaults here
var dfltCpys = 12; // default number of copies including the original
var dfltPos = 4; // default Middle Center
//End Defaults
var Prefs ={}; //Object to hold preferences.
var prefsFile = File(Folder.temp + "/RotateLayerAboutPreferences.dat");
//If preferences do not exit use Defaults from above
if(!prefsFile.exists){
Prefs.Cpys = dfltCpys;
Prefs.Pos = dfltPos;
prefsFile.open('w');
prefsFile.write(Prefs.toSource());
prefsFile.close();
}
else{//Preferences exist so open them
prefsFile.open('r');
Prefs = eval(prefsFile.read());
prefsFile.close();
}
try {
function createDialog(){
// begin dialog layout
var DupRotateDialog = new Window('dialog');
DupRotateDialog.text = 'Duplicate and Rotate Layer';
DupRotateDialog.frameLocation = [78, 100];
DupRotateDialog.alignChildren = 'center';
DupRotateDialog.NumLayerPnl = DupRotateDialog.add('panel', [2, 2, 300, 56], 'Number of Layers and Rotation Anchor Point');
DupRotateDialog.NumLayerPnl.add('statictext', [10, 16, 50, 48], 'Copies ');
DupRotateDialog.NumLayerPnl.imgCpysEdt = DupRotateDialog.NumLayerPnl.add('edittext', [50, 13, 90, 34], Prefs.Cpys, {name:'imgCpys'});
DupRotateDialog.NumLayerPnl.imgCpysEdt.helpTip = 'Number of copies of selected Layer';
DupRotateDialog.NumLayerPnl.add('statictext',[96, 16, 240, 48],'Location');
var position =['Top Left','Top Center','Top Right','Center Left','Center','Center Right','Bottom Left','Bottom Center','Bottom Right','Doc Center','Samples','Path Points'];
DupRotateDialog.NumLayerPnl.dd1 = DupRotateDialog.NumLayerPnl.add('dropdownlist',[150, 13, 260, 34],position);
DupRotateDialog.NumLayerPnl.dd1.selection=Prefs.Pos;
var buttons = DupRotateDialog.add('group');
buttons.orientation = 'row';
var okBtn = buttons.add('button');
okBtn.text = 'OK';
okBtn.properties = {name: 'ok'};
var cancelBtn = buttons.add('button');
cancelBtn.text = 'Cancel';
cancelBtn.properties = {name: 'cancel'};
return DupRotateDialog;
}
dispdlg(createDialog());
function dispdlg(DupRotateDialog){
// display dialog and only continues on OK button press (OK = 1, Cancel = 2)
DupRotateDialog.onShow = function() {
var ww = DupRotateDialog.bounds.width;
var hh = DupRotateDialog.bounds.height;
DupRotateDialog.bounds.x = 78;
DupRotateDialog.bounds.y = 100;
DupRotateDialog.bounds.width = ww;
DupRotateDialog.bounds.height = hh;
}
if (DupRotateDialog.show() == 1) {
//variables passed from user interface
var copies = String(DupRotateDialog.NumLayerPnl.imgCpys.text); if (copies=="") { copies = Prefs.Cpys;}
if (isNaN(copies)) { alert("Non numeric value entered"); dispdlg(createDialog());}
else {
if (copies<2 || copies>360) { alert("Number of layer allow is 2 to 360"); dispdlg(createDialog());} // Not in range
else {
var AnchorPoint = Number(DupRotateDialog.NumLayerPnl.dd1.selection.index) + 1;
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
// Save the current preferences
Prefs.Cpys = copies;
Prefs.Pos = Number(DupRotateDialog.NumLayerPnl.dd1.selection.index);
prefsFile.open('w');
prefsFile.write(Prefs.toSource());
prefsFile.close();
var startRulerUnits = app.preferences.rulerUnits;
var startTypeUnits = app.preferences.typeUnits;
var startDisplayDialogs = app.displayDialogs;
// Set Photoshop to use pixels and display no dialogs
app.preferences.rulerUnits = Units.PIXELS;
app.preferences.typeUnits = TypeUnits.PIXELS;
app.displayDialogs = DialogModes.NO;
app.togglePalettes();
try { app.activeDocument.suspendHistory('RotateLayerAbout','main(copies, AnchorPoint)' );}
catch(e) {alert(e + ': on line ' + e.line);}
// Return the app preferences
app.togglePalettes();
app.preferences.rulerUnits = startRulerUnits;
app.preferences.typeUnits = startTypeUnits;
app.displayDialogs = startDisplayDialogs;
}
}
}
else {
//alert('Operation Canceled.');
}
}
}
catch(err){
// Lot's of things can go wrong, Give a generic alert and see if they want the details
if ( confirm("Sorry, something major happened and I can't continue! Would you like to see more info?" ) ) { alert(err + ': on line ' + err.line ); }
}
}
function main(stemsAmount, Position) {
if ( Position == 11 && app.activeDocument.colorSamplers.length==0 ) {
alert("No Color Sampler set");
return;
}
if ( Position == 12 ) {
var thePath = selectedPath();
if (thePath == undefined) {
alert("No Path Selected");
return;
}
var myPathInfo = extractSubPathInfo(thePath);
}
// Save selected layer to variable:
var originalStem = app.activeDocument.activeLayer;
// Run the copying process
if(stemsAmount != null){
// Calculate the rotation angle
var angle = 360 / parseInt(stemsAmount);
// Create a group for stems
var stemsGroup = app.activeDocument.layerSets.add();
stemsGroup.name = originalStem.name + " ("+stemsAmount+" stems)";
// Place original layer in group
originalStem.move(stemsGroup, ElementPlacement.INSIDE);
// Duplicate and rotate layers:
for(var i = 1; i < stemsAmount; i++){
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
// Rotate new layer
switch (Position){
case 1 : newStem.rotate(angle * i, AnchorPosition.TOPLEFT); break;
case 2 : newStem.rotate(angle * i, AnchorPosition.TOPCENTER); break;
case 3 : newStem.rotate(angle * i, AnchorPosition.TOPRIGHT); break;
case 4 : newStem.rotate(angle * i, AnchorPosition.MIDDLELEFT); break;
case 5 : newStem.rotate(angle * i, AnchorPosition.MIDDLECENTER); break;
case 6 : newStem.rotate(angle * i, AnchorPosition.MIDDLERIGHT); break;
case 7 : newStem.rotate(angle * i, AnchorPosition.BOTTOMLEFT); break;
case 8 : newStem.rotate(angle * i, AnchorPosition.BOTTOMCENTER); break;
case 9 : newStem.rotate(angle * i, AnchorPosition.BOTTOMRIGHT); break;
case 10 : app.activeDocument.activeLayer = newStem; rotateAroundPosition(angle * i,activeDocument.width/2,activeDocument.height/2); break;
case 11 : for (var s=0,len=app.activeDocument.colorSamplers.length;s<len;s++) {
if (s!=0) {
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
}
newStem.name = originalStem.name + " " + (i+1) + " p" + (s+1) ;
app.activeDocument.activeLayer = newStem;
var colorSamplerRef = app.activeDocument.colorSamplers
;//alert("angle=" + (angle * i) + " ,x=" + colorSamplerRef.position[0].value + " ,y=" + colorSamplerRef.position[1].value);
rotateAroundPosition(angle * i,colorSamplerRef.position[0].value,colorSamplerRef.position[1].value);
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
};
break;
case 12 : for(var k=0;k<myPathInfo.length;k++){
for(var j=0;j<myPathInfo
.entireSubPath.length;j++){ if (k!=0 || j!=0) {
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
}
newStem.name = originalStem.name + " " + (i+1) + " p" + (j+1) ;
app.activeDocument.activeLayer = newStem;
rotateAroundPosition(angle * i,myPathInfo
.entireSubPath .anchor[0],myPathInfo .entireSubPath .anchor[1]); newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
}
}
break;
default : break;
}
// Add index to new layers
if (Position!=11) {
newStem.name = originalStem.name + " " + (i+1);
// Place new layer inside stems group
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
}
};
// Add index to the original layer
if (Position!=11) originalStem.name += " 1";
else originalStem.name += " 1 p1";
};
activeDocument.activeLayer = activeDocument.layers[0]; // Target top
var groupname = app.activeDocument.activeLayer.name // remember name of group
var idungroupLayersEvent = stringIDToTypeID( "ungroupLayersEvent" ); // this part from Script Listene -- ungroup group
var desc14 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref13 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref13.putEnumerated( idLyr, idOrdn, idTrgt );
desc14.putReference( idnull, ref13 );
executeAction( idungroupLayersEvent, desc14, DialogModes.NO );
var idMk = charIDToTypeID( "Mk " ); // this part from Script Listene -- group selected layers
var desc15 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref14 = new ActionReference();
var idlayerSection = stringIDToTypeID( "layerSection" );
ref14.putClass( idlayerSection );
desc15.putReference( idnull, ref14 );
var idFrom = charIDToTypeID( "From" );
var ref15 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref15.putEnumerated( idLyr, idOrdn, idTrgt );
desc15.putReference( idFrom, ref15 );
executeAction( idMk, desc15, DialogModes.NO );
app.activeDocument.activeLayer.name = groupname // recall group name
}
function rotateAroundPosition(_angle,x,y) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
desc1.putEnumerated(charIDToTypeID('FTcs'), charIDToTypeID('QCSt'), stringIDToTypeID("QCSIndependent"));
desc2.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x);
desc2.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y);
desc1.putObject(charIDToTypeID('Pstn'), charIDToTypeID('Pnt '), desc2);
desc1.putUnitDouble(charIDToTypeID('Angl'), charIDToTypeID('#Ang'), _angle);
desc1.putEnumerated(charIDToTypeID('Intr'), charIDToTypeID('Intp'), charIDToTypeID('Bcbc'));
executeAction(charIDToTypeID('Trnf'), desc1, DialogModes.NO);
}
////// determine selected path //////
function selectedPath () {
try {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Path"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
var theName = desc.getString(charIDToTypeID("PthN"));
return app.activeDocument.pathItems.getByName(theName)
}
catch (e) {
return undefined
}
};
////// michael l hale’s code //////
function extractSubPathInfo(pathObj){
var pathArray = new Array();// each element can be used as the second arugment in pathItems.add ie doc.pathItems.add("myPath1", [pathArray[0]]);
var pl = pathObj.subPathItems.length;
for(var s=0;s<pl;s++){
var pArray = new Array();
for(var i=0;i<pathObj.subPathItems
.pathPoints.length;i++){pArray = new PathPointInfo;
pArray.kind = pathObj.subPathItems
.pathPoints.kind;pArray.anchor = pathObj.subPathItems
.pathPoints.anchor;//alert("Anchor " + pathObj.subPathItems
.pathPoints.anchor );pArray.leftDirection = pathObj.subPathItems
.pathPoints.leftDirection;pArray.rightDirection = pathObj.subPathItems
.pathPoints.rightDirection;};
pathArray[pathArray.length] = new Array();
pathArray[pathArray.length - 1] = new SubPathInfo();
pathArray[pathArray.length - 1].operation = pathObj.subPathItems
.operation;pathArray[pathArray.length - 1].closed = pathObj.subPathItems
.closed;pathArray[pathArray.length - 1].entireSubPath = pArray;
};
return pathArray;
};
Higher resolution work better
Copy link to clipboard
Copied
Thanks again,
I try to replace _angle by 45
x (in pixels) by canvas size x /2
y (in pixels) by canvas size y /2
Unfortunately I get an error... (error 17, expected variable name)
And seems that I need a loop with some kind of increment to achieve that all layers selected become rotated +45 degrees incrementally. Maybe If we know layer index value to multiply this number by 45...
In After Effects expresions is with layer.index but no idea with script fo Photoshop.
Logic part is something like:
angleIncrement = 45
angle = 0
centerX = (document size X) / 2
centerY = (document size Y) / 2
For each selected layer do:
rotate layer.index(1) by angle
angle = layer.index(1) * angleIncrement
end for
Thanks!
Copy link to clipboard
Copied
If you get an error messages and can not figure out why. You neet to post the actual script code you are executind and a screen capture the show your document and Photoshop UI like layers palette etc when the error message showing. For you do not seem to know what is going on and therefore can not state what the problems is. The Function I gave you rotate the active layer using the values you pass.
You wrote " I get an error... (error 17, expected variable name)" and you did not show the line number of the script code you use or or the script code.
My car will not start why? Can you give me the correct reason why? ...
Copy link to clipboard
Copied
Sorry, You are right!
function rotateAroundPosition(45,2048,2048) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
desc1.putEnumerated(charIDToTypeID('FTcs'), charIDToTypeID('QCSt'), stringIDToTypeID("QCSIndependent"));
desc2.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x);
desc2.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y);
desc1.putObject(charIDToTypeID('Pstn'), charIDToTypeID('Pnt '), desc2);
desc1.putUnitDouble(charIDToTypeID('Angl'), charIDToTypeID('#Ang'), _angle);
desc1.putEnumerated(charIDToTypeID('Intr'), charIDToTypeID('Intp'), charIDToTypeID('Bcbc'));
executeAction(charIDToTypeID('Trnf'), desc1, DialogModes.NO);
}
Red numbers point angles of rotation of images that I want to counter-rotate to align with Photomerge.
Thanks agains
Copy link to clipboard
Copied
Can't you just use something like this?
app.activeDocument.activeLayer.rotate(45, AnchorPosition.MIDDLECENTER)
Copy link to clipboard
Copied
Thanks Tom!
Sorry but I don't know nothing about PS scripting. I dont know if this works, reading this line seems be correct. But
I don't want rotate only one layer. I want to rotate al selected layers at time, but with every layer I want to increment angle by 45º. I need know how to write a "for" loop and know how increment angle by 45 with next layer in each loop...
Thanks!
Copy link to clipboard
Copied
edene8699004 wrote
Sorry but I don't know nothing about PS scripting.
Then you need to learn about scripting languages supported by Adobe Scriptingsupport plug-in and learn how to code in one I would suggest JavaScript. You also need to learn about Adobe Photoshop Document Object Model. A Photoshop DOM code. All of Photoshop features are not covered by Adobe's Photoshop DOM. So some of the code posted here is Photoshop Action Manager code to do thins not possible with Adobe DOM Code. Action manager code is not very readable.]
The following is DOM code for rotating a layer about one of its 9 anchor points.
"app.activeDocument.activeLayer.rotate(45, AnchorPosition.MIDDLECENTER);"
The following is a function created with action manager cod the can do the same thing but the rotations is not limited to rotating about an anchor point. You can use any point to rotate a layer about. The point does not need to be within the layers bounds even.
function rotateAroundPosition(_angle,x,y) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
desc1.putEnumerated(charIDToTypeID('FTcs'), charIDToTypeID('QCSt'), stringIDToTypeID("QCSIndependent"));
desc2.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x);
desc2.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y);
desc1.putObject(charIDToTypeID('Pstn'), charIDToTypeID('Pnt '), desc2);
desc1.putUnitDouble(charIDToTypeID('Angl'), charIDToTypeID('#Ang'), _angle);
desc1.putEnumerated(charIDToTypeID('Intr'), charIDToTypeID('Intp'), charIDToTypeID('Bcbc'));
executeAction(charIDToTypeID('Trnf'), desc1, DialogModes.NO);
}
You could heir a programmer of perhaps you know a programmer that can help you learn or create the script you want. Rotating a layer is only a small part of what you want the script to do. You want it to have some kind of Script UI. You need to design how that UI will function and code it. That is way more complex then rotating a layer.
There is much you need to learn if you want to Script Photoshop. Even to hack at it like I do. I do not know javascript but can hack at javascript using a reference and web searching. I know quit a bit about how Photoshop works. I been using it foe 20+ years. I was a Programmer before I retired. So I know something about programming and design processes. There is a Adobe Photoshop Plug-in Scriptlisener you can install that is somewhat like an Action Recorder. However it has no controls and the Action steps are recorded into two log file one your desktop. The steps are recorded as VSB code and JavaScript coded steps. The steps are like Action steps everything is hard coded. No logic just step step like actions. However you can modify the recorded code. Program functions that you pass variable to. The functions use these variables instead of the hard coded values recorded in the Scriptlisener recorded code.
That is how the above function was created. _angle, x, y are thee variable name that will be passed that are use in the step to replace what was hard coded by the plug-in. You should be able to see where the substations was done. You should see _angle and x and y being used within the function
Copy link to clipboard
Copied
A friend help my with code and this works:
var doc = app.activeDocument;
var angle = 45;
function rotateEachLayer() {
for ( var i = 0; i < doc.layers.length; i++ ) {
var item = doc.layers;
var incrementalAngle = i * angle;
item.rotate( incrementalAngle );
}
}
rotateEachLayer();
-------
Only one thing. You know how use only selected layers instead all layers in document?
Thanks!
Copy link to clipboard
Copied
The code you show is using DOM code to rotate some layers one at a time about its center anchor point and increase the angle or rotation an additional 45 degrees for each rotation done. 0, 45, 90, 135,
The some layer will be all layers if your document does not contain layer groups. It use using Photoshop layers array. There is a layers array for each layer group. If you document contains layers groups only the layers document top level will rotate.
If you want to rotate particular layer by name or because they are selected you need the create an array that contains the layer objects you want to rotate. Then code that for loop for the length of that array. You would use that array not the documents layers array.
If your document contains layer groups you may need to use recursion to process the layers you want to rotate.
Layers center location can vary.
Copy link to clipboard
Copied
You have been quiet for a couple of days now. How are you doing with your script.
As I wrote I do not know JavaScript but have a programming background. So I can more or less read JavaScript code to some extent and figure out what it is doing and often can hack at code toe bend it to do what I want to do. This forum is a great place to find example code. When you want to do something search the forum for code that does something like you want to do, if you can not find a script that does exactly what you want to do.
For example I pretended I was you. You want to rotate selected layers via a Photoshop script. That means your script need to know what layers are selected and rotate them. If it does that the script would need to target each of the selected layers one at a time to rotate each one. The means selection one layer ay a time. When done rotating the layers the script would need to reselect all the layers that were selected to begin with. So with those thing in mind I started to search this forum for JavaScript code.
I found a function that will return an array of the select layers layers ID. I found a function the can get a layer by its ID and I found a function that can select layers by the laye's ID.
So if all you want to do is rotate a layer about it center anchor point to can adapt the code you have to rotate selected layers. If you want to rotate layers about the document center you would need to use the rotate function I posted where x,y is the canvas center point.
Your RotateSelecedLayers script woul look something like this.
//alert(get_selected_layers_id().toSource())
var selectedLayers = get_selected_layers_id();
var angle = 45;
for ( var i = 0; i < selectedLayers.length; i++ ) {
var incrementalAngle = i * angle;
thisLayer = get_layer_by_id(selectedLayers);
saveVisibility = thisLayer.visible;
thisLayer.visible = true;
alert(thisLayer.name + " rotate " + incrementalAngle + " Degrees");
thisLayer.rotate( incrementalAngle );
thisLayer.visible = saveVisibility;
}
for ( var i = 0; i < selectedLayers.length; i++ ) { selectLayerByID(selectedLayers,true);}
function get_selected_layers_id() {
try {
var r = new ActionReference();
r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"));
r.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
var d = executeActionGet(r);
if (!d.hasKey(stringIDToTypeID("targetLayers"))) {
var r = new ActionReference();
r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("layerID"));
r.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
return [ executeActionGet(r).getInteger(stringIDToTypeID("layerID")) ];
}
var list = d.getList(stringIDToTypeID("targetLayers"));
if (!list) return null;
var n = 0;
try { activeDocument.backgroundLayer } catch (e) { n = 1; }
var len = list.count;
var selected_layers = new Array();
for (var i = 0; i < len; i++) {
try {
var r = new ActionReference();
r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("layerID"));
r.putIndex( charIDToTypeID("Lyr "), list.getReference(i).getIndex() + n);
selected_layers.push(executeActionGet(r).getInteger(stringIDToTypeID("layerID")));
}
catch (e) { _alert(e); return null; }
}
return selected_layers;
}
catch (e) { alert(e); return null; }
}
function get_layer_by_id(id, doc_id) {
try {
var doc;
if (doc_id == undefined) doc = activeDocument;
else {
for (var i = 0; i < documents.length; i++) {
if (documents.id == doc_id) {
doc = documents;
break;
}
}
}
if (doc == undefined) { alert("Bad document " + doc_id); return null; }
var r = new ActionReference();
r.putProperty(charIDToTypeID("Prpr"), stringIDToTypeID("json"));
if (doc_id == undefined) r.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
else r.putIdentifier(charIDToTypeID("Dcmn"), doc_id);
eval("var json = " + executeActionGet(r).getString(stringIDToTypeID("json")));
if (json == undefined) return null;
var set = new Array();
function search_id(layers, id) {
for (var i = 0; i < layers.length; i++) {
if (layers.id == id) { set.push(i); return true; }
}
for (var i = 0; i < layers.length; i++) {
if (layers.layers) {
if (search_id(layers.layers, id)) { set.push(i); return true; }
}
}
}
if (search_id(json.layers, id)) {
var ret = doc.layers;
for (var i = set.length-1; i > 0; i--) { ret = ret[set].layers;}
return ret[set[0]];
}
return null;
}
catch (e) { alert(e); }
}
// 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); }
};
Copy link to clipboard
Copied
Hello again JJMack, thanks for your time and patience.
I have done a search on this forum for "selected layer" function. A friend help me with code and result was:
var doc = app.activeDocument;
var angle = 45;
function SelectedLayers(){
try{
var ActLay = app.activeDocument.activeLayer;
ActLay.allLocked = true; //lock all selected layers
var LayerStack = app.activeDocument.artLayers.length;
var selLayers = new Array();
for (var i=0; i<=LayerStack-1; i++){
ActLay = app.activeDocument.layers
if (ActLay.allLocked == true){selLayers.push(app.activeDocument.layers);} // push all locked layers into an array
}
for (i=0; i<=LayerStack-1; i++){
var LAY = app.activeDocument.layers;
LAY.allLocked = false; // unlock all locked Layers
}
return selLayers;
}
catch(e){/*alert(e);*/}
}
var selectedLayers = SelectedLayers();
function rotateLayers() {
for ( var i = 0; i < selectedLayers.length; i++ ) {
var item = selectedLayers;
var incrementalAngle = angle + (i * angle);
item.rotate( incrementalAngle );
}
}
rotateLayers();
//alert(selectedLayers);
Seems works correctly, I will try your code too.
Thanks!
Copy link to clipboard
Copied
Hi JJMack .I'm looking for something like this wonderful Script however, the last two items on the list don't seem to work correctly:
['Samples', 'Path Points']
Does it still work for you? Could you show them funciana? Thanks.
Copy link to clipboard
Copied
Its your coding is wrong. You would use the function in you code like this:
rotateAroundPosition(45,2048,2048);
The function itself has variables
function rotateAroundPosition(_angle,x,y) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
desc1.putEnumerated(charIDToTypeID('FTcs'), charIDToTypeID('QCSt'), stringIDToTypeID("QCSIndependent"));
desc2.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x);
desc2.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y);
desc1.putObject(charIDToTypeID('Pstn'), charIDToTypeID('Pnt '), desc2);
desc1.putUnitDouble(charIDToTypeID('Angl'), charIDToTypeID('#Ang'), _angle);
desc1.putEnumerated(charIDToTypeID('Intr'), charIDToTypeID('Intp'), charIDToTypeID('Bcbc'));
executeAction(charIDToTypeID('Trnf'), desc1, DialogModes.NO);
}
X and Y can be any point not just anchor points
Copy link to clipboard
Copied
Hi JJMack .I'm looking for something like this wonderful Script however, the last two items on the list don't seem to work correctly:
['Samples', 'Path Points']
Does it still work for you? Could you show them funciana? Thanks.
// 2015 John J. McAssey (JJMack)
// ======================================================= */
// This script is supplied as is. It is provided as freeware.
// The author accepts no liability for any problems arising from its use.
// enable double-clicking from Mac Finder or Windows Explorer
#target photoshop // this command only works in Photoshop CS2 and higher
// bring application forward for double-click events
app.bringToFront();
// ensure at least one document open
if (!documents.length) alert('There are no documents open.', 'No Document');
else {
//Set First Time Defaults here
var dfltCpys = 12; // default number of copies including the original
var dfltPos = 4; // default Middle Center
//End Defaults
var Prefs ={}; //Object to hold preferences.
var prefsFile = File(Folder.temp + "/RotateLayerAboutPreferences.dat");
//If preferences do not exit use Defaults from above
if(!prefsFile.exists){
Prefs.Cpys = dfltCpys;
Prefs.Pos = dfltPos;
prefsFile.open('w');
prefsFile.write(Prefs.toSource());
prefsFile.close();
}
else{//Preferences exist so open them
prefsFile.open('r');
Prefs = eval(prefsFile.read());
prefsFile.close();
}
try {
function createDialog(){
// begin dialog layout
var DupRotateDialog = new Window('dialog');
DupRotateDialog.text = 'Duplicate and Rotate Layer';
DupRotateDialog.frameLocation = [78, 100];
DupRotateDialog.alignChildren = 'center';
DupRotateDialog.NumLayerPnl = DupRotateDialog.add('panel', [2, 2, 300, 56], 'Number of Layers and Rotation Anchor Point');
DupRotateDialog.NumLayerPnl.add('statictext', [10, 16, 50, 48], 'Copies ');
DupRotateDialog.NumLayerPnl.imgCpysEdt = DupRotateDialog.NumLayerPnl.add('edittext', [50, 13, 90, 34], Prefs.Cpys, {name:'imgCpys'});
DupRotateDialog.NumLayerPnl.imgCpysEdt.helpTip = 'Number of copies of selected Layer';
DupRotateDialog.NumLayerPnl.add('statictext',[96, 16, 240, 48],'Location');
var position =['Top Left','Top Center','Top Right','Center Left','Center','Center Right','Bottom Left','Bottom Center','Bottom Right','Doc Center','Samples','Path Points'];
DupRotateDialog.NumLayerPnl.dd1 = DupRotateDialog.NumLayerPnl.add('dropdownlist',[150, 13, 260, 34],position);
DupRotateDialog.NumLayerPnl.dd1.selection=Prefs.Pos;
var buttons = DupRotateDialog.add('group');
buttons.orientation = 'row';
var okBtn = buttons.add('button');
okBtn.text = 'OK';
okBtn.properties = {name: 'ok'};
var cancelBtn = buttons.add('button');
cancelBtn.text = 'Cancel';
cancelBtn.properties = {name: 'cancel'};
return DupRotateDialog;
}
dispdlg(createDialog());
function dispdlg(DupRotateDialog){
// display dialog and only continues on OK button press (OK = 1, Cancel = 2)
DupRotateDialog.onShow = function() {
var ww = DupRotateDialog.bounds.width;
var hh = DupRotateDialog.bounds.height;
DupRotateDialog.bounds.x = 78;
DupRotateDialog.bounds.y = 100;
DupRotateDialog.bounds.width = ww;
DupRotateDialog.bounds.height = hh;
}
if (DupRotateDialog.show() == 1) {
//variables passed from user interface
var copies = String(DupRotateDialog.NumLayerPnl.imgCpys.text); if (copies=="") { copies = Prefs.Cpys;}
if (isNaN(copies)) { alert("Non numeric value entered"); dispdlg(createDialog());}
else {
if (copies<2 || copies>360) { alert("Number of layer allow is 2 to 360"); dispdlg(createDialog());} // Not in range
else {
var AnchorPoint = Number(DupRotateDialog.NumLayerPnl.dd1.selection.index) + 1;
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
// Save the current preferences
Prefs.Cpys = copies;
Prefs.Pos = Number(DupRotateDialog.NumLayerPnl.dd1.selection.index);
prefsFile.open('w');
prefsFile.write(Prefs.toSource());
prefsFile.close();
var startRulerUnits = app.preferences.rulerUnits;
var startTypeUnits = app.preferences.typeUnits;
var startDisplayDialogs = app.displayDialogs;
// Set Photoshop to use pixels and display no dialogs
app.preferences.rulerUnits = Units.PIXELS;
app.preferences.typeUnits = TypeUnits.PIXELS;
app.displayDialogs = DialogModes.NO;
app.togglePalettes();
try { app.activeDocument.suspendHistory('RotateLayerAbout','main(copies, AnchorPoint)' );}
catch(e) {alert(e + ': on line ' + e.line);}
// Return the app preferences
app.togglePalettes();
app.preferences.rulerUnits = startRulerUnits;
app.preferences.typeUnits = startTypeUnits;
app.displayDialogs = startDisplayDialogs;
}
}
}
else {
//alert('Operation Canceled.');
}
}
}
catch(err){
// Lot's of things can go wrong, Give a generic alert and see if they want the details
if ( confirm("Sorry, something major happened and I can't continue! Would you like to see more info?" ) ) { alert(err + ': on line ' + err.line ); }
}
}
function main(stemsAmount, Position) {
if ( Position == 11 && app.activeDocument.colorSamplers.length==0 ) {
alert("No Color Sampler set");
return;
}
if ( Position == 12 ) {
var thePath = selectedPath();
if (thePath == undefined) {
alert("No Path Selected");
return;
}
var myPathInfo = extractSubPathInfo(thePath);
}
// Save selected layer to variable:
var originalStem = app.activeDocument.activeLayer;
// Run the copying process
if(stemsAmount != null){
// Calculate the rotation angle
var angle = 360 / parseInt(stemsAmount);
// Create a group for stems
var stemsGroup = app.activeDocument.layerSets.add();
stemsGroup.name = originalStem.name + " ("+stemsAmount+" stems)";
// Place original layer in group
originalStem.move(stemsGroup, ElementPlacement.INSIDE);
// Duplicate and rotate layers:
for(var i = 1; i < stemsAmount; i++){
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
// Rotate new layer
switch (Position){
case 1 : newStem.rotate(angle * i, AnchorPosition.TOPLEFT); break;
case 2 : newStem.rotate(angle * i, AnchorPosition.TOPCENTER); break;
case 3 : newStem.rotate(angle * i, AnchorPosition.TOPRIGHT); break;
case 4 : newStem.rotate(angle * i, AnchorPosition.MIDDLELEFT); break;
case 5 : newStem.rotate(angle * i, AnchorPosition.MIDDLECENTER); break;
case 6 : newStem.rotate(angle * i, AnchorPosition.MIDDLERIGHT); break;
case 7 : newStem.rotate(angle * i, AnchorPosition.BOTTOMLEFT); break;
case 8 : newStem.rotate(angle * i, AnchorPosition.BOTTOMCENTER); break;
case 9 : newStem.rotate(angle * i, AnchorPosition.BOTTOMRIGHT); break;
case 10 : app.activeDocument.activeLayer = newStem; rotateAroundPosition(angle * i,activeDocument.width/2,activeDocument.height/2); break;
case 11 : for (var s=0,len=app.activeDocument.colorSamplers.length;s<len;s++) {
if (s!=0) {
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
}
newStem.name = originalStem.name + " " + (i+1) + " p" + (s+1) ;
app.activeDocument.activeLayer = newStem;
var colorSamplerRef = app.activeDocument.colorSamplers;
//alert("angle=" + (angle * i) + " ,x=" + colorSamplerRef.position[0].value + " ,y=" + colorSamplerRef.position[1].value);
rotateAroundPosition(angle * i,colorSamplerRef.position[0].value,colorSamplerRef.position[1].value);
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
};
break;
case 12 : for(var k=0;k<myPathInfo.length;k++){
for(var j=0;j<myPathInfo.entireSubPath.length;j++){
if (k!=0 || j!=0) {
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
}
newStem.name = originalStem.name + " " + (i+1) + " p" + (j+1) ;
app.activeDocument.activeLayer = newStem;
rotateAroundPosition(angle * i,myPathInfo.entireSubPath.anchor[0],myPathInfo.entireSubPath.anchor[1]);
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
}
}
break;
default : break;
}
// Add index to new layers
if (Position!=11) {
newStem.name = originalStem.name + " " + (i+1);
// Place new layer inside stems group
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
}
};
// Add index to the original layer
if (Position!=11) originalStem.name += " 1";
else originalStem.name += " 1 p1";
};
activeDocument.activeLayer = activeDocument.layers[0]; // Target top
var groupname = app.activeDocument.activeLayer.name // remember name of group
var idungroupLayersEvent = stringIDToTypeID( "ungroupLayersEvent" ); // this part from Script Listene -- ungroup group
var desc14 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref13 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref13.putEnumerated( idLyr, idOrdn, idTrgt );
desc14.putReference( idnull, ref13 );
executeAction( idungroupLayersEvent, desc14, DialogModes.NO );
var idMk = charIDToTypeID( "Mk " ); // this part from Script Listene -- group selected layers
var desc15 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref14 = new ActionReference();
var idlayerSection = stringIDToTypeID( "layerSection" );
ref14.putClass( idlayerSection );
desc15.putReference( idnull, ref14 );
var idFrom = charIDToTypeID( "From" );
var ref15 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref15.putEnumerated( idLyr, idOrdn, idTrgt );
desc15.putReference( idFrom, ref15 );
executeAction( idMk, desc15, DialogModes.NO );
app.activeDocument.activeLayer.name = groupname // recall group name
}
function rotateAroundPosition(_angle,x,y) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
desc1.putEnumerated(charIDToTypeID('FTcs'), charIDToTypeID('QCSt'), stringIDToTypeID("QCSIndependent"));
desc2.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x);
desc2.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y);
desc1.putObject(charIDToTypeID('Pstn'), charIDToTypeID('Pnt '), desc2);
desc1.putUnitDouble(charIDToTypeID('Angl'), charIDToTypeID('#Ang'), _angle);
desc1.putEnumerated(charIDToTypeID('Intr'), charIDToTypeID('Intp'), charIDToTypeID('Bcbc'));
executeAction(charIDToTypeID('Trnf'), desc1, DialogModes.NO);
}
////// determine selected path //////
function selectedPath () {
try {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Path"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
var theName = desc.getString(charIDToTypeID("PthN"));
return app.activeDocument.pathItems.getByName(theName)
}
catch (e) {
return undefined
}
};
////// michael l hale’s code //////
function extractSubPathInfo(pathObj){
var pathArray = new Array();// each element can be used as the second arugment in pathItems.add ie doc.pathItems.add("myPath1", [pathArray[0]]);
var pl = pathObj.subPathItems.length;
for(var s=0;s<pl;s++){
var pArray = new Array();
for(var i=0;i<pathObj.subPathItems.pathPoints.length;i++){
pArray = new PathPointInfo;
pArray.kind = pathObj.subPathItems.pathPoints.kind;
pArray.anchor = pathObj.subPathItems.pathPoints.anchor;
//alert("Anchor " + pathObj.subPathItems.pathPoints.anchor );
pArray.leftDirection = pathObj.subPathItems.pathPoints.leftDirection;
pArray.rightDirection = pathObj.subPathItems.pathPoints.rightDirection;
};
pathArray[pathArray.length] = new Array();
pathArray[pathArray.length - 1] = new SubPathInfo();
pathArray[pathArray.length - 1].operation = pathObj.subPathItems.operation;
pathArray[pathArray.length - 1].closed = pathObj.subPathItems.closed;
pathArray[pathArray.length - 1].entireSubPath = pArray;
};
return pathArray;
};
Copy link to clipboard
Copied
That looks like my script. However the formatting and spacing has been messed up broke the script. I'll post it again. The old jive site often broke script the were posted. Perhaps the changed site java script posting will work better.
// 2015 John J. McAssey (JJMack)
// ======================================================= */
// This script is supplied as is. It is provided as freeware.
// The author accepts no liability for any problems arising from its use.
// enable double-clicking from Mac Finder or Windows Explorer
#target photoshop // this command only works in Photoshop CS2 and higher
// bring application forward for double-click events
app.bringToFront();
// ensure at least one document open
if (!documents.length) alert('There are no documents open.', 'No Document');
else {
//Set First Time Defaults here
var dfltCpys = 12; // default number of copies including the original
var dfltPos = 4; // default Middle Center
//End Defaults
var Prefs ={}; //Object to hold preferences.
var prefsFile = File(Folder.temp + "/RotateLayerAboutPreferences.dat");
//If preferences do not exit use Defaults from above
if(!prefsFile.exists){
Prefs.Cpys = dfltCpys;
Prefs.Pos = dfltPos;
prefsFile.open('w');
prefsFile.write(Prefs.toSource());
prefsFile.close();
}
else{//Preferences exist so open them
prefsFile.open('r');
Prefs = eval(prefsFile.read());
prefsFile.close();
}
try {
function createDialog(){
// begin dialog layout
var DupRotateDialog = new Window('dialog');
DupRotateDialog.text = 'Duplicate and Rotate Layer';
DupRotateDialog.frameLocation = [78, 100];
DupRotateDialog.alignChildren = 'center';
DupRotateDialog.NumLayerPnl = DupRotateDialog.add('panel', [2, 2, 300, 56], 'Number of Layers and Rotation Anchor Point');
DupRotateDialog.NumLayerPnl.add('statictext', [10, 16, 50, 48], 'Copies ');
DupRotateDialog.NumLayerPnl.imgCpysEdt = DupRotateDialog.NumLayerPnl.add('edittext', [50, 13, 90, 34], Prefs.Cpys, {name:'imgCpys'});
DupRotateDialog.NumLayerPnl.imgCpysEdt.helpTip = 'Number of copies of selected Layer';
DupRotateDialog.NumLayerPnl.add('statictext',[96, 16, 240, 48],'Location');
var position =['Top Left','Top Center','Top Right','Center Left','Center','Center Right','Bottom Left','Bottom Center','Bottom Right','Doc Center','Samples','Path Points'];
DupRotateDialog.NumLayerPnl.dd1 = DupRotateDialog.NumLayerPnl.add('dropdownlist',[150, 13, 260, 34],position);
DupRotateDialog.NumLayerPnl.dd1.selection=Prefs.Pos;
var buttons = DupRotateDialog.add('group');
buttons.orientation = 'row';
var okBtn = buttons.add('button');
okBtn.text = 'OK';
okBtn.properties = {name: 'ok'};
var cancelBtn = buttons.add('button');
cancelBtn.text = 'Cancel';
cancelBtn.properties = {name: 'cancel'};
return DupRotateDialog;
}
dispdlg(createDialog());
function dispdlg(DupRotateDialog){
// display dialog and only continues on OK button press (OK = 1, Cancel = 2)
DupRotateDialog.onShow = function() {
var ww = DupRotateDialog.bounds.width;
var hh = DupRotateDialog.bounds.height;
DupRotateDialog.bounds.x = 78;
DupRotateDialog.bounds.y = 100;
DupRotateDialog.bounds.width = ww;
DupRotateDialog.bounds.height = hh;
}
if (DupRotateDialog.show() == 1) {
//variables passed from user interface
var copies = String(DupRotateDialog.NumLayerPnl.imgCpys.text); if (copies=="") { copies = Prefs.Cpys;}
if (isNaN(copies)) { alert("Non numeric value entered"); dispdlg(createDialog());}
else {
if (copies<2 || copies>360) { alert("Number of layer allow is 2 to 360"); dispdlg(createDialog());} // Not in range
else {
var AnchorPoint = Number(DupRotateDialog.NumLayerPnl.dd1.selection.index) + 1;
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
// Save the current preferences
Prefs.Cpys = copies;
Prefs.Pos = Number(DupRotateDialog.NumLayerPnl.dd1.selection.index);
prefsFile.open('w');
prefsFile.write(Prefs.toSource());
prefsFile.close();
var startRulerUnits = app.preferences.rulerUnits;
var startTypeUnits = app.preferences.typeUnits;
var startDisplayDialogs = app.displayDialogs;
// Set Photoshop to use pixels and display no dialogs
app.preferences.rulerUnits = Units.PIXELS;
app.preferences.typeUnits = TypeUnits.PIXELS;
app.displayDialogs = DialogModes.NO;
app.togglePalettes();
try { app.activeDocument.suspendHistory('RotateLayerAbout','main(copies, AnchorPoint)' );}
catch(e) {alert(e + ': on line ' + e.line);}
// Return the app preferences
app.togglePalettes();
app.preferences.rulerUnits = startRulerUnits;
app.preferences.typeUnits = startTypeUnits;
app.displayDialogs = startDisplayDialogs;
}
}
}
else {
//alert('Operation Canceled.');
}
}
}
catch(err){
// Lot's of things can go wrong, Give a generic alert and see if they want the details
if ( confirm("Sorry, something major happened and I can't continue! Would you like to see more info?" ) ) { alert(err + ': on line ' + err.line ); }
}
}
function main(stemsAmount, Position) {
if ( Position == 11 && app.activeDocument.colorSamplers.length==0 ) {
alert("No Color Sampler set");
return;
}
if ( Position == 12 ) {
var thePath = selectedPath();
if (thePath == undefined) {
alert("No Path Selected");
return;
}
var myPathInfo = extractSubPathInfo(thePath);
}
// Save selected layer to variable:
var originalStem = app.activeDocument.activeLayer;
// Run the copying process
if(stemsAmount != null){
// Calculate the rotation angle
var angle = 360 / parseInt(stemsAmount);
// Create a group for stems
var stemsGroup = app.activeDocument.layerSets.add();
stemsGroup.name = originalStem.name + " ("+stemsAmount+" stems)";
// Place original layer in group
originalStem.move(stemsGroup, ElementPlacement.INSIDE);
// Duplicate and rotate layers:
for(var i = 1; i < stemsAmount; i++){
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
// Rotate new layer
switch (Position){
case 1 : newStem.rotate(angle * i, AnchorPosition.TOPLEFT); break;
case 2 : newStem.rotate(angle * i, AnchorPosition.TOPCENTER); break;
case 3 : newStem.rotate(angle * i, AnchorPosition.TOPRIGHT); break;
case 4 : newStem.rotate(angle * i, AnchorPosition.MIDDLELEFT); break;
case 5 : newStem.rotate(angle * i, AnchorPosition.MIDDLECENTER); break;
case 6 : newStem.rotate(angle * i, AnchorPosition.MIDDLERIGHT); break;
case 7 : newStem.rotate(angle * i, AnchorPosition.BOTTOMLEFT); break;
case 8 : newStem.rotate(angle * i, AnchorPosition.BOTTOMCENTER); break;
case 9 : newStem.rotate(angle * i, AnchorPosition.BOTTOMRIGHT); break;
case 10 : app.activeDocument.activeLayer = newStem; rotateAroundPosition(angle * i,activeDocument.width/2,activeDocument.height/2); break;
case 11 : for (var s=0,len=app.activeDocument.colorSamplers.length;s<len;s++) {
if (s!=0) {
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
}
newStem.name = originalStem.name + " " + (i+1) + " p" + (s+1) ;
app.activeDocument.activeLayer = newStem;
var colorSamplerRef = app.activeDocument.colorSamplers[s];
//alert("angle=" + (angle * i) + " ,x=" + colorSamplerRef.position[0].value + " ,y=" + colorSamplerRef.position[1].value);
rotateAroundPosition(angle * i,colorSamplerRef.position[0].value,colorSamplerRef.position[1].value);
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
};
break;
case 12 : for(var k=0;k<myPathInfo.length;k++){
for(var j=0;j<myPathInfo[k].entireSubPath.length;j++){
if (k!=0 || j!=0) {
// Duplicate original layer and save it to the variable
var newStem = originalStem.duplicate();
}
newStem.name = originalStem.name + " " + (i+1) + " p" + (j+1) ;
app.activeDocument.activeLayer = newStem;
rotateAroundPosition(angle * i,myPathInfo[k].entireSubPath[j].anchor[0],myPathInfo[k].entireSubPath[j].anchor[1]);
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
}
}
break;
default : break;
}
// Add index to new layers
if (Position!=11) {
newStem.name = originalStem.name + " " + (i+1);
// Place new layer inside stems group
newStem.move(stemsGroup, ElementPlacement.PLACEATEND);
}
};
// Add index to the original layer
if (Position!=11) originalStem.name += " 1";
else originalStem.name += " 1 p1";
};
activeDocument.activeLayer = activeDocument.layers[0]; // Target top
var groupname = app.activeDocument.activeLayer.name // remember name of group
var idungroupLayersEvent = stringIDToTypeID( "ungroupLayersEvent" ); // this part from Script Listene -- ungroup group
var desc14 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref13 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref13.putEnumerated( idLyr, idOrdn, idTrgt );
desc14.putReference( idnull, ref13 );
executeAction( idungroupLayersEvent, desc14, DialogModes.NO );
var idMk = charIDToTypeID( "Mk " ); // this part from Script Listene -- group selected layers
var desc15 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref14 = new ActionReference();
var idlayerSection = stringIDToTypeID( "layerSection" );
ref14.putClass( idlayerSection );
desc15.putReference( idnull, ref14 );
var idFrom = charIDToTypeID( "From" );
var ref15 = new ActionReference();
var idLyr = charIDToTypeID( "Lyr " );
var idOrdn = charIDToTypeID( "Ordn" );
var idTrgt = charIDToTypeID( "Trgt" );
ref15.putEnumerated( idLyr, idOrdn, idTrgt );
desc15.putReference( idFrom, ref15 );
executeAction( idMk, desc15, DialogModes.NO );
app.activeDocument.activeLayer.name = groupname // recall group name
}
function rotateAroundPosition(_angle,x,y) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putEnumerated(charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));
desc1.putReference(charIDToTypeID('null'), ref1);
desc1.putEnumerated(charIDToTypeID('FTcs'), charIDToTypeID('QCSt'), stringIDToTypeID("QCSIndependent"));
desc2.putUnitDouble(charIDToTypeID('Hrzn'), charIDToTypeID('#Pxl'), x);
desc2.putUnitDouble(charIDToTypeID('Vrtc'), charIDToTypeID('#Pxl'), y);
desc1.putObject(charIDToTypeID('Pstn'), charIDToTypeID('Pnt '), desc2);
desc1.putUnitDouble(charIDToTypeID('Angl'), charIDToTypeID('#Ang'), _angle);
desc1.putEnumerated(charIDToTypeID('Intr'), charIDToTypeID('Intp'), charIDToTypeID('Bcbc'));
executeAction(charIDToTypeID('Trnf'), desc1, DialogModes.NO);
}
////// determine selected path //////
function selectedPath () {
try {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Path"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
var theName = desc.getString(charIDToTypeID("PthN"));
return app.activeDocument.pathItems.getByName(theName)
}
catch (e) {
return undefined
}
};
////// michael l hale’s code //////
function extractSubPathInfo(pathObj){
var pathArray = new Array();// each element can be used as the second arugment in pathItems.add ie doc.pathItems.add("myPath1", [pathArray[0]]);
var pl = pathObj.subPathItems.length;
for(var s=0;s<pl;s++){
var pArray = new Array();
for(var i=0;i<pathObj.subPathItems[s].pathPoints.length;i++){
pArray[i] = new PathPointInfo;
pArray[i].kind = pathObj.subPathItems[s].pathPoints[i].kind;
pArray[i].anchor = pathObj.subPathItems[s].pathPoints[i].anchor;
//alert("Anchor " + pathObj.subPathItems[s].pathPoints[i].anchor );
pArray[i].leftDirection = pathObj.subPathItems[s].pathPoints[i].leftDirection;
pArray[i].rightDirection = pathObj.subPathItems[s].pathPoints[i].rightDirection;
};
pathArray[pathArray.length] = new Array();
pathArray[pathArray.length - 1] = new SubPathInfo();
pathArray[pathArray.length - 1].operation = pathObj.subPathItems[s].operation;
pathArray[pathArray.length - 1].closed = pathObj.subPathItems[s].closed;
pathArray[pathArray.length - 1].entireSubPath = pArray;
};
return pathArray;
};
Copy link to clipboard
Copied
Thanks for the quick response JJMack ! The script is now 100% functional. Congratulations and thank you again
Copy link to clipboard
Copied
There is a Bug in Photoshop Scripting I did not bother to code around in that script. R-bin and I have reported the bug to Adobe. Adobe has even knowledge the bug. However Adobe support does not seem to want to fix the nasty bug. I have seen Scripts posted here the fail badly when Adobe bug bite. This script will just fail with this message
The document should still be in pretty good shape all you need do is back up one history state deselect and rerun the script. It will run correctly then.
My bug report was made and acknowledge 5 years ago I updated it 3 month ago stating it still not fixed
R-bin reported the bug 6 years ago Adobe's Tom Ruark official replay was "Interesting"...
Tom was also assign the job of fixing a bug I report was introduced in CS4. He never did the bugs are still in all versions of Photoshop cs4 and newer. Adobe withdraw my bug report.
Adobe Photoshop support is not what it should be IMO.
Copy link to clipboard
Copied
Hi, I'll hijack this thread a bit. I'm looking for a script that can copy, move and rotate in a spiraling/fractal manner .
Made a very crude illustration of what I mean. Is this existing somewhere? Don't really know how to script myself .
Would really appreciate it if someone could help me. ❤️
Copy link to clipboard
Copied
Users have posted Scripts to rotate layers and distribute layers along a path. Why not look at these script code and code the script you seem to want. There are the deco scripts use in fill pattern scripts including a sprial. If the script you want does not exists. Code the script you want the posted scripts should help get you going.
These forums are for helping users with using Adobe Products you may need to code the scipt you want if the one you have found and the one we have pointed you to do not work the way you want.

