Copy link to clipboard
Copied
I cannot for the life of me work this out but I'm sure it must be possible with paths.
I want to bend equally spaced text onto a curve (as per pic below)
How can I do this?
Copy link to clipboard
Copied
Please elaborate.
If there is the slightest chance that the curve may need to be edited later on I would recommend considering using Indesign for this task.
Copy link to clipboard
Copied
Imagine having a bulleted list you need to curve round an arc. I could do it by hand but I'm sure there must be a way to do this in Photoshop. The text or curve won't need to be edited later. I don't have access to InDesign. Thanks 🙂
Copy link to clipboard
Copied
What is the Curve exactly? Is is a segment of a circle or not?
Copy link to clipboard
Copied
See this next pic. The text that reads "EXAMPLE TEXT" needs to fit to the line of the arc (instead of being straight)
Copy link to clipboard
Copied
And also see this old graphic. The letters NW are sticking out from the centre circle. This is what I'm trying to achieve.
Copy link to clipboard
Copied
Is it a circle or not?
Copy link to clipboard
Copied
I once created a Script for circular arrangements.
// 2010, pfaffenbichler;
// use it at your own risk;
#target photoshop
////// filter for checking if entry is numeric and positive, thanks to xbytor //////
posNumberKeystrokeFilter = function() {
this.text = this.text.replace(",", ".");
this.text = this.text.replace("-", "");
if (this.text.match(/[^\-\.\d]/)) {
this.text = this.text.replace(/[^\-\.\d]/g, '');
}
};
////////////////////////////////////
var theCheck = photoshopCheck();
if (theCheck == true) {
// do the operations;
var myDocument = app.activeDocument;
var myResolution = myDocument.resolution;
var originalUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
////////////////////////////////////
var dlg = new Window('dialog', "set circle-radius for arrangement", [500,300,840,450]);
// field for radius;
dlg.radius = dlg.add('panel', [15,17,162,67], 'radius');
dlg.radius.number = dlg.radius.add('edittext', [12,12,60,32], "60", {multiline:false});
dlg.radius.numberText = dlg.radius.add('statictext', [65,14,320,32], "mm radius ", {multiline:false});
dlg.radius.number.onChange = posNumberKeystrokeFilter;
dlg.radius.number.active = true;
// field for selecting;
dlg.centerWidth = dlg.add('panel', [172,17,325,67], 'arrange by');
dlg.centerWidth.center = dlg.centerWidth.add('radiobutton', [12,12,70,32], "center");
dlg.centerWidth.width = dlg.centerWidth.add('radiobutton', [80,12,150,32], "width");
dlg.centerWidth.center.value = true;
// buttons for ok, and cancel;
dlg.buttons = dlg.add('panel', [15,80,325,130], '');
dlg.buttons.buildBtn = dlg.buttons.add('button', [13,13,145,35], 'OK', {name:'ok'});
dlg.buttons.cancelBtn = dlg.buttons.add('button', [155,13,290,35], 'Cancel', {name:'cancel'});
// show the dialog;
dlg.center();
var myReturn = dlg.show ();
////////////////////////////////////
if (myReturn == true) {
app.togglePalettes();
// duplicate layerset;
var theName = myDocument.activeLayer.name;
var theOriginal = myDocument.activeLayer;
var myLayerSet = theOriginal.duplicate(theOriginal, ElementPlacement.PLACEBEFORE);
theOriginal.visible = false;
myLayerSet.name = theName + "_rotation";
var theLayers = collectLayers(myLayerSet);
var theNumber = theLayers.length;
// calculate the radius in pixels;
var theRadius = Number(dlg.radius.number.text) / 10 * myResolution / 2.54;
myDocument.selection.deselect();
// get the angles;
var theAngles = new Array;
// if to be aligned by centers;
if (dlg.centerWidth.center.value == true) {
var theAngle = 360 / theNumber;
for (var a = 0; a < theNumber; a++) {
theAngles[a] = theAngle * a;
}
}
// if to be aligned according to widths;
else {
var theWidths = new Array;
var theTotalWidth = 0;
// get the widths;
for (var b = 0; b < theNumber; b++) {
var theLayer = theLayers[b];
var theBounds = theLayer.bounds;
var theWidth = (theBounds[2] - theBounds[0]);
theTotalWidth = theTotalWidth + theWidth;
theWidths = theWidths.concat(theWidth)
};
var theCircumference = Math.PI * 2 * theRadius;
// determine the space between;
var theGutter = (theCircumference - Number(theTotalWidth)) / theNumber;
var theFactor = 360 / (theGutter * theNumber + theTotalWidth);
theAngles[0] = theWidths[0] * theFactor;
for (var c = 1; c < theNumber; c++) {
theAngles[c] = (theGutter + (theWidths[c] / 2) + (theWidths[c - 1] / 2)) * theFactor + theAngles[c - 1];
};
};
// work through the layers;
for (var d = 0; d < theNumber; d++) {
var thisAngle = theAngles[d];
// convert to smart object;
var theLayer = smartify (theLayers[d]);
// get actual and target position;
var theBounds = theLayer.bounds;
var theHorCenter = (theBounds[0] + ((theBounds[2] - theBounds[0])/2));
var theVerCenter = (theBounds[1] + ((theBounds[3] - theBounds[1])/2));
var theHorTarget = Math.cos(radiansOf(thisAngle - 90)) * theRadius;
var theVerTarget = Math.sin(radiansOf(thisAngle - 90)) * theRadius;
// do the transformations;
rotateAndMove(myDocument, theLayer, thisAngle, - theHorCenter + theHorTarget + (myDocument.width / 2), - theVerCenter + theVerTarget + (myDocument.height / 2))
};
// reset;
app.preferences.rulerUnits = originalUnits;
app.togglePalettes()
};
};
////////////////////////////////////
////////////////////////////////////
////////////////////////////////////
////// function collect all artlayers //////
function collectLayers (theParent) {
if (!allLayers) {
var allLayers = new Array}
else {};
for (var m = theParent.layers.length - 1; m >= 0;m--) {
var theLayer = theParent.layers[m];
// apply the function to layersets;
if (theLayer.typename == "ArtLayer") {
allLayers = allLayers.concat(theLayer)
}
else {
// this line includes the layer groups;
// allLayers = allLayers.concat(theLayer);
allLayers = allLayers.concat(collectLayers(theLayer))
}
}
return allLayers
};
////// function to determine if open document is eligible for operations //////
function photoshopCheck () {
var checksOut = true;
if (app.documents.length == 0) {
alert ("no open document");
checksOut = false
}
else {
if (app.activeDocument.activeLayer.typename != "LayerSet") {
alert ("please select a group");
checksOut = false
}
else {
if (app.activeDocument.activeLayer.layers.length < 3) {
alert ("please select a group containing at least three layers");
checksOut = false
}
}
};
return checksOut
};
////// function to smartify if not //////
function smartify (theLayer) {
// make layers smart objects if they are not already;
if (theLayer.kind != LayerKind.SMARTOBJECT) {
myDocument.activeLayer = theLayer;
var id557 = charIDToTypeID( "slct" );
var desc108 = new ActionDescriptor();
var id558 = charIDToTypeID( "null" );
var ref77 = new ActionReference();
var id559 = charIDToTypeID( "Mn " );
var id560 = charIDToTypeID( "MnIt" );
var id561 = stringIDToTypeID( "newPlacedLayer" );
ref77.putEnumerated( id559, id560, id561 );
desc108.putReference( id558, ref77 );
executeAction( id557, desc108, DialogModes.NO );
return myDocument.activeLayer
};
else {return theLayer}
};
////// radians //////
function radiansOf (theAngle) {
return theAngle * Math.PI / 180
};
////// rotate and move //////
function rotateAndMove (myDocument, theLayer, thisAngle, horizontalOffset, verticalOffset) {
// do the transformations;
myDocument.activeLayer = theLayer;
// =======================================================
var idTrnf = charIDToTypeID( "Trnf" );
var desc3 = new ActionDescriptor();
var idFTcs = charIDToTypeID( "FTcs" );
var idQCSt = charIDToTypeID( "QCSt" );
var idQcsa = charIDToTypeID( "Qcsa" );
desc3.putEnumerated( idFTcs, idQCSt, idQcsa );
var idOfst = charIDToTypeID( "Ofst" );
var desc4 = new ActionDescriptor();
var idHrzn = charIDToTypeID( "Hrzn" );
var idPxl = charIDToTypeID( "#Pxl" );
desc4.putUnitDouble( idHrzn, idPxl, horizontalOffset );
var idVrtc = charIDToTypeID( "Vrtc" );
var idPxl = charIDToTypeID( "#Pxl" );
desc4.putUnitDouble( idVrtc, idPxl, verticalOffset );
var idOfst = charIDToTypeID( "Ofst" );
desc3.putObject( idOfst, idOfst, desc4 );
var idAngl = charIDToTypeID( "Angl" );
var idAng = charIDToTypeID( "#Ang" );
desc3.putUnitDouble( idAngl, idAng, Number(thisAngle) );
executeAction( idTrnf, desc3, DialogModes.NO );
};
Copy link to clipboard
Copied
If all the text is the same, and you don't need to edit it later, you can create a pattern of the text and use the scripted fill with pattern along a path.
Copy link to clipboard
Copied
Wow, that's amazing! Thanks. It's an arc, not a circle. Can't believe it needs to be so complicated though 😞
Copy link to clipboard
Copied
Frankly, the only way I can think to do this would be to write a script that calculates equal spaces on the path, then gets the perpendicular angle of those locations and apply them to the text angles.
Copy link to clipboard
Copied
Is this what you are looking for? The scripts came in while I was getting this ready, but I've done it and will post anyway.
Draw an ellipse and a path that starts from the center of the ellipse. Click the Type tool where you want the text to start.
Copy the Type layer. Rotate an appropriate amount for the number of items you have. Move the pivot point to the center of the ellipse. I used -15°.
(360°/x)
Repeat the rotation.
You can edit the text. The layer names will update when you do.
~ Jane
Copy link to clipboard
Copied
Yes, brilliant! Thanks Jane. That's a great workaround 🙂
Copy link to clipboard
Copied
You're welcome, @fizzyfizz. This is much faster in Illustrator because of several features that Illustrator has that PS does not, but it can be done without too much trouble in Photoshop. Let us know if you have questions.
~ Jane