A while back I asked if anyone had messed about with scripting paths in Photoshop. I got little response. Anyway I persevered with the hope of creating a circle. Just for kicks, you understand (I must get out more). Turns out there isn't much info out there on the subject only that it's not possible to create a true circle with bezier curves. I've had a look it into it and I've managed a circular approximation with paths.
// draw circular path
// use at your own risk
// Author: ghoulfool
// Thanks to G. Adam Stanislav for the kappa explanation
// Kappa Kappa Hey!
app.preferences.rulerUnits = Units.PIXELS;
// OPTIONALS
var radius = 150; // radius of the circle to be drawn
var circX = 160; // centre of circle X
var circY = 160; // centre of circle Y
// create a document to work with
var docRef = app.documents.add("320px", "320px", 72, "Circle");
// call the source document
var srcDoc = app.activeDocument;
// create new layer
var layerRef = srcDoc.artLayers.add()
layerRef.name = "circle"
layerRef.blendMode = BlendMode.NORMAL
//draw circle
drawCircle(circX , circY, radius, "circle")
function drawCircle(X,Y,rad, pathName)
{
var K = (4 * (Math.sqrt(2) - 1) / 3)* rad
// define circle points
var C = new Array();
C = [X, Y - rad, X + rad, Y, X, Y + rad, X - rad, Y, X + K, Y - rad, X + rad, Y - K, X + rad, Y + K, X - K, Y + rad, X + K, Y + rad, X - rad, Y + K, X - rad, Y - K, X - K, Y - rad];
// create the array of PathPointInfo objects
var lineArray = new Array();
lineArray.push(new PathPointInfo());
lineArray[0].kind = PointKind.CORNERPOINT;
lineArray[0].anchor = new Array(C[0], C[1]); // A
lineArray[0].leftDirection = [C[8], C[9]];
lineArray[0].rightDirection = lineArray[0].anchor;
lineArray.push(new PathPointInfo());
lineArray[1].kind = PointKind.CORNERPOINT;
lineArray[1].anchor = new Array(C[2], C[3]); // B
lineArray[1].leftDirection = [C[12], C[13]];
lineArray[1].rightDirection = [C[10], C[11]];
lineArray.push(new PathPointInfo());
lineArray[2].kind = PointKind.CORNERPOINT;
lineArray[2].anchor = new Array(C[4], C[5]); // C
lineArray[2].leftDirection = [C[14], C[15]];
lineArray[2].rightDirection = [C[16], C[17]];
lineArray.push(new PathPointInfo());
lineArray[3].kind = PointKind.CORNERPOINT;
lineArray[3].anchor = new Array(C[6], C[7]); // D
lineArray[3].leftDirection = [C[20], C[21]];
lineArray[3].rightDirection = [C[18], C[19]];
lineArray.push(new PathPointInfo());
lineArray[4].kind = PointKind.CORNERPOINT;
lineArray[4].anchor = new Array(C[0], C[1]);
lineArray[4].leftDirection = lineArray[4].anchor;
lineArray[4].rightDirection = [C[22], C[23]];
// create a SubPathInfo object, which holds the line array in its entireSubPath property.
var lineSubPathArray = new Array();
lineSubPathArray.push(new SubPathInfo());
lineSubPathArray[0].operation = ShapeOperation.SHAPEXOR;
lineSubPathArray[0].closed = false;
lineSubPathArray[0].entireSubPath = lineArray;
//create the path item, passing subpath to add method
var myPathItem = docRef.pathItems.add(pathName, lineSubPathArray);
// set foreground colour to green
var fgColor = new SolidColor;
fgColor.rgb.hexValue="00ff80" //green colour
foregroundColor = fgColor
//fill the path
myPathItem.fillPath(fgColor,ColorBlendMode.NORMAL,100,false,0,true,true);
//deselect path
// =======================================================
var id630 = charIDToTypeID( "Dslc" );
var desc154 = new ActionDescriptor();
var id631 = charIDToTypeID( "null" );
var ref127 = new ActionReference();
var id632 = charIDToTypeID( "Path" );
ref127.putClass( id632 );
desc154.putReference( id631, ref127 );
executeAction( id630, desc154, DialogModes.NO );
}
This was my second attempt. The first was on a semi circle basis with two points - but the circles looked very oval. This is much better I feel.
Enjoy!
Turns out there isn't much info out there on the subject only that it's not possible to create a true circle with bezier curves.
Is that so indeed?
The Ellipse Tool (constrained) seems to create a decent crircular Path and if that is pasted above itself and rotated I cannot notice any misalignments.
I was well aware that you can convert the ellipsis tool to a path (make work path) but the resulting path is perfectly circular, but rather messy (in terms of point placement)
The whole point of the exercise was for me to gain a better understanding on how bezier paths work within scripting. So i'm happy. ![]()
This would be very easy to do with scriptlistner code using either the elliptical marquee tool or elliptical tool. The elliptical tool can create a Path directly and the elliptical marquee tool can create selection which in turn can be turned in a path all can be transformed. The elliptical tool would create a better Path a circle would have 4 point. Converting a slection is to a path would not work that well.
I created a plug-in script based on "Fit Image.jsx" that combine the rectangle and elliptical selection tools so you can record making aspect ratio selection for documents in actions. The plugin http://www.mouseprints.net/old/dpr/AspectRatioSelection.jsx
/* ==========================================================
// Christmass 2007 John J. McAssey (JJMack) and the
// Day I descovered Photoshop had what I wanted
// a way to pass Prams to Scripts throught menu File>Automate
// ======================================================= */
/* SetMarqueeSelection function from Scriptlistner plugin
// ===================================================================== ===== */
function setMarqueeSelection(x1, y1, x2, y2, type, shape, feather, antiAlias) {
var SelectionType =null;
if (type ==null) { var SelectionType = "setd" }
if (type ==diminish) { var SelectionType = "SbtF" }
if (type ==extend) { var SelectionType = "AddT" }
if (type ==intersect) { var SelectionType = "IntW" }
if (type ==replace) { var SelectionType = "setd" }
var id3 = charIDToTypeID( SelectionType );
var desc2 = new ActionDescriptor();
var id4 = charIDToTypeID( "null" );
var ref1 = new ActionReference();
var id5 = charIDToTypeID( "Chnl" );
var id6 = charIDToTypeID( "fsel" );
ref1.putProperty( id5, id6 );
desc2.putReference( id4, ref1 );
var id7 = charIDToTypeID( "T " );
var desc3 = new ActionDescriptor();
var id8 = charIDToTypeID( "Top " );
var id9 = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( id8, id9, y1 );
var id10 = charIDToTypeID( "Left" );
var id11 = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( id10, id11, x1 );
var id12 = charIDToTypeID( "Btom" );
var id13 = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( id12, id13, y2 );
var id14 = charIDToTypeID( "Rght" );
var id15 = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( id14, id15, x2 );
var id16 = charIDToTypeID( shape );
desc2.putObject( id7, id16, desc3 );
var id17 = charIDToTypeID( "Fthr" );
var id18 = charIDToTypeID( "#Pxl" );
desc2.putUnitDouble( id17, id18, feather );
var id19 = charIDToTypeID( "AntA" );
desc2.putBoolean( id19, antiAlias );
executeAction( id3, desc2, DialogModes.NO );
}
North America
Europe, Middle East and Africa
Asia Pacific