Copy link to clipboard
Copied
I have a function that I used to draw lines and then stroke the path.
export const getSolidColor = (hex) => { const color = new SolidColor() color.rgb.hexValue = hex return color } export const drawLines = (doc, coordinates, title) => { const lines = [] for (i = 0; i < coordinates.length; i++) { const { anchor, kind, ldr, rdr } = coordinates[i] const point = [anchor.x, anchor.y] const line = new PathPointInfo() line.kind = kind line.anchor = point line.leftDirection = ldr ? [ldr.x, ldr.y] : point line.rightDirection = rdr ? [rdr.x, rdr.y] : point lines.push(line) } const subPath = new SubPathInfo() subPath.closed = true subPath.entireSubPath = lines subPath.operation = ShapeOperation.SHAPEXOR const item = doc.pathItems.add(title, [subPath]) item.deselect() return item }
When I call this function to strokePath it works fine.
// Create a new document const width = 1920 const height = 1080 const ppi = 72 const title = "Character 1" const mode = NewDocumentMode.RGB const newDoc = app.documents.add(width, height, ppi, title, mode) const brush = ToolType.BRUSH drawLines(newDoc, coords, "Line 1").strokePath(brush)
But, when I try to fill the path using the fillPath method, the layer just appears empty.
export const convertPoints = (points) => { const newPoints = [] for (i = 0; i < points.length; i++) { newPoints.push({ kind: PointKind.CORNERPOINT, anchor: { x: points[i][0], y: points[i][1] }, ldr: null, rdr: null }) } return newPoints } const newPoints = convertPoints([ [width * 0.33, height * 0], [width * 0.33, height * 1], [width * 0.5, height * 1], [width * 0.5, height * 0] ]) const fillColor = getSolidColor("0080ff") const opacity = 90 const fillMode = ColorBlendMode.NORMAL const preserveTransparency = true const feather = 0 const wholePath = true const antiAlias = true drawLines(newDoc, newPoints, "Line 2").fillPath( fillColor, fillMode, opacity, preserveTransparency, feather, wholePath, antiAlias )
The shape appears along with the anchor points on the Photoshop document but its not colored or filled inside. Does anyone know how to do with with ExtendScript?
Thank you!
Your code is definitely not for ExtendScript. Perhaps this is for UXP, which is not available to me.
Try replacing
const preserveTransparency = true
with
const preserveTransparency = false
Copy link to clipboard
Copied
Your code is definitely not for ExtendScript. Perhaps this is for UXP, which is not available to me.
Try replacing
const preserveTransparency = true
with
const preserveTransparency = false
Copy link to clipboard
Copied
It's standard JavaScript. Once it gets compiled it makes more sense.
Copy link to clipboard
Copied
It's standard JavaScript. Once it gets compiled it makes more sense.
By @Lance31522690av1y
JavaScript and ExtendScript are not the same thing.
Your code does not work, for example, in PS2020 due to the fact that it is not ExtendScript.
P.S. Have you tried my advice?
Copy link to clipboard
Copied
My apologies. It is JavaScript - not ExtendScript.
And yes, changing the "presererve transparency" method worked!
Thank you!
Copy link to clipboard
Copied
My apologies. It is JavaScript - not ExtendScript.
And yes, changing the "presererve transparency" method worked!
Thank you!
By @Lance31522690av1y
It's either ExtendScript (.js or .jsx) or UXP JavaScript (.psjs).
Copy link to clipboard
Copied
Could you please post screenshots with the pertinent Panels (Toolbar, Layers, Paths, Options Bar, …) visible?
How did you create the code?
Why would you fill a Path instead of creating a Shape Layer?
Copy link to clipboard
Copied
I've never been able to make a shape layer using extendscript. I've always had to create the path first, then convert it to a shape layer. Do you know a way to directly make a shape layer?Why would you fill a Path instead of creating a Shape Layer?
By @c.pfaffenbichler
Copy link to clipboard
Copied
I've always had to create the path first, then convert it to a shape layer. Do you know a way to directly make a shape layer?
Do you mean with the Pen Tool (or other Path-releated Tools) or via Script?
Sorry, I had read sloppily.
With a Script that would need a selected Path or one could create a Work Path before creating the Shape Layer, maybe other options exist.
This Script would create a Shape Layer of two circles.
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
var theArray = [[[[123.946875,67.756875],[153.647014898625,67.756875],[94.246735101375,67.756875],true],[[177.72375,121.53375],[177.72375,151.233889898625],[177.72375,91.833610101375],true],
[[123.946875,175.310625],[94.246735101375,175.310625],[153.647014898625,175.310625],true],[[70.17,121.53375],[70.17,91.833610101375],[70.17,151.233889898625],true],true,1097098272],
[[[173.3953125,133.648125],[194.627376180187,133.648125],[152.163248819812,133.648125],true],[[211.839375,172.0921875],[211.839375,193.324251180188],[211.839375,150.860123819812],true],
[[173.3953125,210.53625],[152.163248819812,210.53625],[194.627376180187,210.53625],true],[[134.95125,172.0921875],[134.95125,150.860123819812],[134.95125,193.324251180188],true],true,1737]];
var theX = createShapeLayer(theArray, [0,125,255], 30, [0,0,0]);
};
////////////////////////////////////
////// create a solid color layer //////
function createShapeLayer(theArray, fillColor, strokeWidth, strokeColor) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// thanks to xbytor;
cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty(cTID('Path'), cTID('WrPt'));
desc1.putReference(sTID('null'), ref1);
var list1 = new ActionList();
for (var m = 0; m < theArray.length; m++) {
var thisSubPath = theArray[m];
var desc2 = new ActionDescriptor();
desc2.putEnumerated(sTID('shapeOperation'), sTID('shapeOperation'), 1908);
// desc2.putEnumerated(sTID('shapeOperation'), sTID('shapeOperation'), thisSubPath[thisSubPath.length - 1]);
var list2 = new ActionList();
var desc3 = new ActionDescriptor();
desc3.putBoolean(cTID('Clsp'), thisSubPath[thisSubPath.length - 2]);
var list3 = new ActionList();
for (var n = 0; n < thisSubPath.length - 2; n++) {
var thisPoint = thisSubPath[n];
var desc4 = new ActionDescriptor();
var desc5 = new ActionDescriptor();
desc5.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[0][0]);
desc5.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[0][1]);
desc4.putObject(cTID('Anch'), cTID('Pnt '), desc5);
var desc6 = new ActionDescriptor();
desc6.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[1][0]);
desc6.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[1][1]);
desc4.putObject(cTID('Fwd '), cTID('Pnt '), desc6);
var desc7 = new ActionDescriptor();
desc7.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[2][0]);
desc7.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[2][1]);
desc4.putObject(cTID('Bwd '), cTID('Pnt '), desc7);
desc4.putBoolean(cTID('Smoo'), thisPoint[3]);
list3.putObject(cTID('Pthp'), desc4);
};
desc3.putList(cTID('Pts '), list3);
list2.putObject(cTID('Sbpl'), desc3);
desc2.putList(cTID('SbpL'), list2);
list1.putObject(cTID('PaCm'), desc2);
};
desc1.putList(cTID('T '), list1);
executeAction(cTID('setd'), desc1, DialogModes.NO);
// solid color layer;
var desc16 = new ActionDescriptor();
var ref4 = new ActionReference();
ref4.putClass( stringIDToTypeID( "contentLayer" ) );
desc16.putReference( charIDToTypeID( "null" ), ref4 );
var desc17 = new ActionDescriptor();
var desc18 = new ActionDescriptor();
if (fillColor != false) {
var desc19 = new ActionDescriptor();
desc19.putDouble( charIDToTypeID( "Rd " ), fillColor[0] );
desc19.putDouble( charIDToTypeID( "Grn " ), fillColor[1] );
desc19.putDouble( charIDToTypeID( "Bl " ), fillColor[2] );
desc18.putObject( charIDToTypeID( "Clr " ), charIDToTypeID( "RGBC" ), desc19 );
};
desc17.putObject( charIDToTypeID( "Type" ), stringIDToTypeID( "solidColorLayer" ), desc18 );
////////////////////////////////////
var desc38 = new ActionDescriptor();
desc38.putInteger( stringIDToTypeID( "strokeStyleVersion" ), 2 );
if (strokeColor != false) {desc38.putBoolean( stringIDToTypeID( "strokeEnabled" ), true )}
else {desc38.putBoolean( stringIDToTypeID( "strokeEnabled" ), false )};
if (fillColor == false) {desc38.putBoolean( stringIDToTypeID( "fillEnabled" ), false )};
desc38.putUnitDouble( stringIDToTypeID( "strokeStyleLineWidth" ), stringIDToTypeID( "pixelsUnit" ), strokeWidth );
desc38.putUnitDouble( stringIDToTypeID( "strokeStyleLineDashOffset" ), stringIDToTypeID( "pointsUnit" ), 0.000000 );
desc38.putDouble( stringIDToTypeID( "strokeStyleMiterLimit" ), 100.000000 );
desc38.putEnumerated( stringIDToTypeID( "strokeStyleLineCapType" ), stringIDToTypeID( "strokeStyleLineCapType" ), stringIDToTypeID( "strokeStyleButtCap" ) );
desc38.putEnumerated( stringIDToTypeID( "strokeStyleLineJoinType" ), stringIDToTypeID( "strokeStyleLineJoinType" ), stringIDToTypeID( "strokeStyleMiterJoin" ) );
desc38.putEnumerated( stringIDToTypeID( "strokeStyleLineAlignment" ), stringIDToTypeID( "strokeStyleLineAlignment" ), stringIDToTypeID( "strokeStyleAlignCenter" ) );
var idstrokeStyleScaleLock = stringIDToTypeID( "strokeStyleScaleLock" );
desc38.putBoolean( idstrokeStyleScaleLock, false );
desc38.putBoolean( stringIDToTypeID( "strokeStyleStrokeAdjust" ), false );
var list5 = new ActionList();
desc38.putList( stringIDToTypeID( "strokeStyleLineDashSet" ), list5 );
desc38.putEnumerated( stringIDToTypeID( "strokeStyleBlendMode" ), stringIDToTypeID( "blendMode" ), stringIDToTypeID( "normal" ) );
desc38.putUnitDouble( stringIDToTypeID( "strokeStyleOpacity" ), stringIDToTypeID( "percentUnit" ), 100.000000 );
var desc39 = new ActionDescriptor();
if (strokeColor != false) {
var desc40 = new ActionDescriptor();
desc40.putDouble( charIDToTypeID( "Rd " ), strokeColor[0] );
desc40.putDouble( charIDToTypeID( "Grn " ), strokeColor[1] );
desc40.putDouble( charIDToTypeID( "Bl " ), strokeColor[2] );
desc39.putObject( charIDToTypeID( "Clr " ), charIDToTypeID( "RGBC" ), desc40 );
};
desc38.putObject( stringIDToTypeID( "strokeStyleContent" ), stringIDToTypeID( "solidColorLayer"), desc39 );
desc38.putDouble( stringIDToTypeID( "strokeStyleResolution" ), 300.000000 );
desc17.putObject( stringIDToTypeID( "strokeStyle" ), stringIDToTypeID( "strokeStyle" ), desc38 );
////////////////////////////////////
desc16.putObject( charIDToTypeID( "Usng" ), stringIDToTypeID( "contentLayer" ), desc17 );
executeAction( charIDToTypeID( "Mk " ), desc16, DialogModes.NO );
app.preferences.rulerUnits = originalRulerUnits;
// get identifier;
var ref = new ActionReference();
ref.putProperty (stringIDToTypeID ("property"), stringIDToTypeID ("layerID"));
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
return executeActionGet(ref).getInteger(stringIDToTypeID("layerID"));
};
Copy link to clipboard
Copied
Yea, that's what I thought: with a script, you need a work path first. That's what I've been doing when I create these images, by morphing shape layers. I have to have the script redraw the path, then convert it to a shape layer.
Copy link to clipboard
Copied
Sorry, the previous post was due to my misunderstanding.
This would create a Ellipse Shape Layer for example:
// 2024, use it at your own risk;
ellipseToolShapeLayer ([100,100,550,550], [128,128,128], 100, [128,255,255]);
////// make ellipse tool shape layer //////
function ellipseToolShapeLayer (theBounds, theFillColor, strokeWidth, theStrokeColor) {
var desc126 = new ActionDescriptor();
var ref16 = new ActionReference();
ref16.putClass( stringIDToTypeID( "contentLayer" ) );
desc126.putReference( stringIDToTypeID( "null" ), ref16 );
var desc127 = new ActionDescriptor();
var desc128 = new ActionDescriptor();
var desc129 = new ActionDescriptor();
desc129.putDouble( stringIDToTypeID( "red" ), theStrokeColor[0] );
desc129.putDouble( stringIDToTypeID( "grain" ), theStrokeColor[1] );
desc129.putDouble( stringIDToTypeID( "blue" ), theStrokeColor[2] );
var idRGBColor = stringIDToTypeID( "RGBColor" );
desc128.putObject( stringIDToTypeID( "color" ), idRGBColor, desc129 );
var idsolidColorLayer = stringIDToTypeID( "solidColorLayer" );
desc127.putObject( stringIDToTypeID( "type" ), idsolidColorLayer, desc128 );
var desc130 = new ActionDescriptor();
var idunitValueQuadVersion = stringIDToTypeID( "unitValueQuadVersion" );
desc130.putInteger( idunitValueQuadVersion, 1 );
desc130.putUnitDouble( stringIDToTypeID( "top" ), stringIDToTypeID( "pixelsUnit" ), theBounds[1] );
desc130.putUnitDouble( stringIDToTypeID( "left" ), stringIDToTypeID( "pixelsUnit" ), theBounds[0] );
desc130.putUnitDouble( stringIDToTypeID( "bottom" ), stringIDToTypeID( "pixelsUnit" ), theBounds[3] );
desc130.putUnitDouble( stringIDToTypeID( "right" ), stringIDToTypeID( "pixelsUnit" ), theBounds[2] );
desc127.putObject( stringIDToTypeID( "shape" ), stringIDToTypeID( "ellipse" ), desc130 );
var desc131 = new ActionDescriptor();
desc131.putInteger( stringIDToTypeID( "strokeStyleVersion" ), 2 );
desc131.putBoolean( stringIDToTypeID( "strokeEnabled" ), true );
desc131.putBoolean( stringIDToTypeID( "fillEnabled" ), true );
desc131.putUnitDouble( stringIDToTypeID( "strokeStyleLineWidth" ), stringIDToTypeID( "pixelsUnit" ), strokeWidth );
desc131.putUnitDouble( stringIDToTypeID( "strokeStyleLineDashOffset" ), stringIDToTypeID( "pointsUnit" ), 0.000000 );
desc131.putDouble( stringIDToTypeID( "strokeStyleMiterLimit" ), 100.000000 );
desc131.putEnumerated( stringIDToTypeID( "strokeStyleLineCapType" ), stringIDToTypeID( "strokeStyleLineCapType" ), stringIDToTypeID( "strokeStyleButtCap" ) );
desc131.putEnumerated( stringIDToTypeID( "strokeStyleLineJoinType" ), stringIDToTypeID( "strokeStyleLineJoinType" ), stringIDToTypeID( "strokeStyleMiterJoin" ) );
desc131.putEnumerated( stringIDToTypeID( "strokeStyleLineAlignment" ), stringIDToTypeID( "strokeStyleLineAlignment" ), stringIDToTypeID( "strokeStyleAlignCenter" ) );
desc131.putBoolean( stringIDToTypeID( "strokeStyleScaleLock" ), false );
desc131.putBoolean( stringIDToTypeID( "strokeStyleStrokeAdjust" ), false );
var list13 = new ActionList();
desc131.putList( stringIDToTypeID( "strokeStyleLineDashSet" ), list13 );
desc131.putEnumerated( stringIDToTypeID( "strokeStyleBlendMode" ), stringIDToTypeID( "blendMode" ), stringIDToTypeID( "normal" ) );
desc131.putUnitDouble( stringIDToTypeID( "strokeStyleOpacity" ),stringIDToTypeID( "percentUnit" ), 100.000000 );
var desc132 = new ActionDescriptor();
var desc133 = new ActionDescriptor();
desc133.putDouble( stringIDToTypeID( "red" ), theFillColor[0] );
desc133.putDouble( stringIDToTypeID( "grain" ), theFillColor[1] );
desc133.putDouble( stringIDToTypeID( "blue" ), theFillColor[2] );
var idRGBColor = stringIDToTypeID( "RGBColor" );
desc132.putObject( stringIDToTypeID( "color" ), idRGBColor, desc133 );
desc131.putObject( stringIDToTypeID( "strokeStyleContent" ), stringIDToTypeID( "solidColorLayer" ), desc132 );
desc131.putDouble( stringIDToTypeID( "strokeStyleResolution") , 300.000000 );
desc127.putObject( stringIDToTypeID( "strokeStyle" ), stringIDToTypeID( "strokeStyle" ), desc131 );
desc126.putObject( stringIDToTypeID( "using" ), stringIDToTypeID( "contentLayer" ), desc127 );
executeAction( stringIDToTypeID( "make" ), desc126, DialogModes.NO );
};