• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

How to fill a path in Adobe Photoshop with ExtendScript?

Community Beginner ,
Apr 12, 2024 Apr 12, 2024

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!

TOPICS
Actions and scripting

Views

496

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

People's Champ , Apr 12, 2024 Apr 12, 2024

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

Votes

Translate

Translate
Adobe
People's Champ ,
Apr 12, 2024 Apr 12, 2024

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Apr 12, 2024 Apr 12, 2024

Copy link to clipboard

Copied

It's standard JavaScript. Once it gets compiled it makes more sense. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Apr 12, 2024 Apr 12, 2024

Copy link to clipboard

Copied

quote

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Apr 13, 2024 Apr 13, 2024

Copy link to clipboard

Copied

My apologies. It is JavaScript - not ExtendScript.

 

And yes, changing the "presererve transparency" method worked! 

 

Thank you!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 14, 2024 Apr 14, 2024

Copy link to clipboard

Copied

LATEST
quote

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).

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 13, 2024 Apr 13, 2024

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? 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 13, 2024 Apr 13, 2024

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? 
 
quote

Why would you fill a Path instead of creating a Shape Layer? 


By @c.pfaffenbichler

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 14, 2024 Apr 14, 2024

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. 

Screenshot 2024-04-14 at 11.55.34.png

 

// 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"));
};

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 14, 2024 Apr 14, 2024

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.

FB_IMG_1580530918510.jpg

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 14, 2024 Apr 14, 2024

Copy link to clipboard

Copied

Sorry, the previous post was due to my misunderstanding. 

 

This would create a Ellipse Shape Layer for example: 

Screenshot 2024-04-14 at 12.34.03.png

 

// 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 );
};

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines