1 Reply Latest reply on Nov 18, 2015 2:57 PM by JJMack

    Not getting multiple subpaths from selected shape layer

    GiMars86

      I'm trying to get multiple subpaths from a single shape layer with jsx, via PathItem.subPathItems. Shape layers can sometimes contain multiple subpaths, depending on the Shape. For instance, the letter "O" contains two subpaths, the outer ring and the inner ring.

       

      This works if the shape is manually created with the pen tool. But it doesn't work when this character is converted to a path from a font. In this case, Photoshop only returns the outer path and I see no way to get the details of the inner path.

       

      I have a very concise example psd + jsx file that can be downloaded here (link will be active for the next couple of days, but will update it if needed): WeTransfer

       

      I hope my problem is clear. Has anyone else encountered it and, even better, does anyone know a solution?

        • 1. Re: Not getting multiple subpaths from selected shape layer
          JJMack Most Valuable Participant

          I found a script poster here the handle subpath of the selecte path.  The path must be one with a name other then "Work Path"

          Here is my before and after paths.  The script was poster by pfaffenbichler Re: Script - Convert Point Tool to all anchor points in a shape

          Capture.jpg

          // create a new path based on the selected path without curve points;

          // if selected path is vector mask  it will be removed and the resulting path applied as vector mask; feathering and density will be ignored, though;

          // 2015, use it at your own risk;

          #target photoshop

          if (app.documents.length > 0) {

            var myDocument = app.activeDocument;

            if (myDocument.pathItems.length > 0) {

            var thePath = selectedPath ();

            if (thePath != undefined) {

            var thePathKind = thePath.kind;

            // check if selected path is vector mask;

            if (thePathKind == PathKind.VECTORMASK && thePath == myDocument.pathItems[myDocument.pathItems.length - 1]) {var replace = true}

            else {var replace = false};

            var theArray = collectPathInfoFromDesc2012 (myDocument, selectedPath ());

            var theNewArray = new Array;

            // creae new array;

            for (var m = 0; m < theArray.length; m++) {

            var thisSub = theArray[m];

            theNewArray.push(new Array);

            for (var n = 0; n < thisSub.length - 2; n++) {

            var thisPoint = thisSub[n];

            theNewArray[m].push([thisPoint[0], thisPoint[0], thisPoint[0], false]);

            };

            theNewArray[m].push(thisSub[thisSub.length-2]);

            theNewArray[m].push(thisSub[thisSub.length-1]);

            };

            // create path;

            var theNewPath = createPath2015(theNewArray, thePath.name+"x")

            };

            // remove vector mask and apply path as vector mask, feathering and density will be ignored, though;

            if (replace == true) {

            // =======================================================

            var idDlt = charIDToTypeID( "Dlt " );

            var desc4 = new ActionDescriptor();

            var idnull = charIDToTypeID( "null" );

            var ref1 = new ActionReference();

            var idPath = charIDToTypeID( "Path" );

            var idPath = charIDToTypeID( "Path" );

            var idvectorMask = stringIDToTypeID( "vectorMask" );

            ref1.putEnumerated( idPath, idPath, idvectorMask );

            var idLyr = charIDToTypeID( "Lyr " );

            var idOrdn = charIDToTypeID( "Ordn" );

            var idTrgt = charIDToTypeID( "Trgt" );

            ref1.putEnumerated( idLyr, idOrdn, idTrgt );

            desc4.putReference( idnull, ref1 );

            executeAction( idDlt, desc4, DialogModes.NO );

            // =======================================================

            var idMk = charIDToTypeID( "Mk  " );

            var desc5 = new ActionDescriptor();

            var idnull = charIDToTypeID( "null" );

            var ref2 = new ActionReference();

            var idPath = charIDToTypeID( "Path" );

            ref2.putClass( idPath );

            desc5.putReference( idnull, ref2 );

            var idAt = charIDToTypeID( "At  " );

            var ref3 = new ActionReference();

            var idPath = charIDToTypeID( "Path" );

            var idPath = charIDToTypeID( "Path" );

            var idvectorMask = stringIDToTypeID( "vectorMask" );

            ref3.putEnumerated( idPath, idPath, idvectorMask );

            desc5.putReference( idAt, ref3 );

            var idUsng = charIDToTypeID( "Usng" );

            var ref4 = new ActionReference();

            var idPath = charIDToTypeID( "Path" );

            var idOrdn = charIDToTypeID( "Ordn" );

            var idTrgt = charIDToTypeID( "Trgt" );

            ref4.putEnumerated( idPath, idOrdn, idTrgt );

            desc5.putReference( idUsng, ref4 );

            executeAction( idMk, desc5, DialogModes.NO );

            };

            }

            };

          // from »Flatten All Masks.jsx« by jeffrey tranberry;

          ///////////////////////////////////////////////////////////////////////////////

          // Function: hasVectorMask

          // Usage: see if there is a vector layer mask

          // Input: <none> Must have an open document

          // Return: true if there is a vector mask

          ///////////////////////////////////////////////////////////////////////////////

          function hasVectorMask() {

            var hasVectorMask = false;

            try {

            var ref = new ActionReference();

            var keyVectorMaskEnabled = app.stringIDToTypeID( 'vectorMask' );

            var keyKind = app.charIDToTypeID( 'Knd ' );

            ref.putEnumerated( app.charIDToTypeID( 'Path' ), app.charIDToTypeID( 'Ordn' ), keyVectorMaskEnabled );

            var desc = executeActionGet( ref );

            if ( desc.hasKey( keyKind ) ) {

            var kindValue = desc.getEnumerationValue( keyKind );

            if (kindValue == keyVectorMaskEnabled) {

            hasVectorMask = true;

            }

            }

            }

            catch(e) {

            hasVectorMask = false;

            }

            return hasVectorMask;

            };

          ////// collect path info from actiondescriptor, smooth added //////

          function collectPathInfoFromDesc2012 (myDocument, thePath) {

            var originalRulerUnits = app.preferences.rulerUnits;

            app.preferences.rulerUnits = Units.POINTS;

            // based of functions from xbytor’s stdlib;

            var ref = new ActionReference();

            for (var l = 0; l < myDocument.pathItems.length; l++) {

            var thisPath = myDocument.pathItems[l];

            if (thisPath == thePath && thisPath.kind == PathKind.WORKPATH) {

            ref.putProperty(cTID("Path"), cTID("WrPt"));

            };

            if (thisPath == thePath && thisPath.kind != PathKind.WORKPATH && thisPath.kind != PathKind.VECTORMASK) {

            ref.putIndex(cTID("Path"), l + 1);

            };

            if (thisPath == thePath && thisPath.kind == PathKind.VECTORMASK) {

            var idPath = charIDToTypeID( "Path" );

            var idPath = charIDToTypeID( "Path" );

            var idvectorMask = stringIDToTypeID( "vectorMask" );

            ref.putEnumerated( idPath, idPath, idvectorMask );

            };

            };

            var desc = app.executeActionGet(ref);

            var pname = desc.getString(cTID('PthN'));

            // create new array;

            var theArray = new Array;

            var pathComponents = desc.getObjectValue(cTID("PthC")).getList(sTID('pathComponents'));

            // for subpathitems;

            for (var m = 0; m < pathComponents.count; m++) {

            var listKey = pathComponents.getObjectValue(m).getList(sTID("subpathListKey"));

            var operation1 = pathComponents.getObjectValue(m).getEnumerationValue(sTID("shapeOperation"));

            switch (operation1) {

            case 1097098272:

            var operation = 1097098272 //cTID('Add ');

            break;

            case 1398961266:

            var operation = 1398961266 //cTID('Sbtr');

            break;

            case 1231975538:

            var operation = 1231975538 //cTID('Intr');

            break;

            default:

            // case 1102:

            var operation = sTID('xor') //ShapeOperation.SHAPEXOR;

            break;

            };

            // for subpathitem’s count;

            for (var n = 0; n < listKey.count; n++) {

            theArray.push(new Array);

            var points = listKey.getObjectValue(n).getList(sTID('points'));

            try {var closed = listKey.getObjectValue(n).getBoolean(sTID("closedSubpath"))}

            catch (e) {var closed = false};

            // for subpathitem’s segment’s number of points;

            for (var o = 0; o < points.count; o++) {

            var anchorObj = points.getObjectValue(o).getObjectValue(sTID("anchor"));

            var anchor = [anchorObj.getUnitDoubleValue(sTID('horizontal')), anchorObj.getUnitDoubleValue(sTID('vertical'))];

            var thisPoint = [anchor];

            try {

            var left = points.getObjectValue(o).getObjectValue(cTID("Fwd "));

            var leftDirection = [left.getUnitDoubleValue(sTID('horizontal')), left.getUnitDoubleValue(sTID('vertical'))];

            thisPoint.push(leftDirection)

            }

            catch (e) {

            thisPoint.push(anchor)

            };

            try {

            var right = points.getObjectValue(o).getObjectValue(cTID("Bwd "));

            var rightDirection = [right.getUnitDoubleValue(sTID('horizontal')), right.getUnitDoubleValue(sTID('vertical'))];

            thisPoint.push(rightDirection)

            }

            catch (e) {

            thisPoint.push(anchor)

            };

            try {

            var smoothOr = points.getObjectValue(o).getBoolean(cTID("Smoo"));

            thisPoint.push(smoothOr)

            }

            catch (e) {thisPoint.push(false)};

            theArray[theArray.length - 1].push(thisPoint);

            };

            theArray[theArray.length - 1].push(closed);

            theArray[theArray.length - 1].push(operation);

            };

            };

            // by xbytor, thanks to him;

            function cTID (s) { return cTID[s] || cTID[s] = app.charIDToTypeID(s); };

            function sTID (s) { return sTID[s] || sTID[s] = app.stringIDToTypeID(s); };

            // reset;

            app.preferences.rulerUnits = originalRulerUnits;

            return theArray;

            };

          ////// create a path from collectPathInfoFromDesc2012-array //////

          function createPath2015(theArray, thePathsName) {

            var originalRulerUnits = app.preferences.rulerUnits;

            app.preferences.rulerUnits = Units.POINTS;

            // 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'), 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);

           

           

            /*if (hasVectorMask == false) {

            if (thePathsName != undefined) {app.activeDocument.pathItems[app.activeDocument.pathItems.length - 1].name = thePathsName};

            var myPathItem = app.activeDocument.pathItems[app.activeDocument.pathItems.length - 1];alert ("x")

            }

            else {

            if (thePathsName != undefined) {app.activeDocument.pathItems[app.activeDocument.pathItems.length - 2].name = thePathsName};

            var myPathItem = app.activeDocument.pathItems[app.activeDocument.pathItems.length - 2];alert ("y")

            };*/

            for (var x = 0; x < activeDocument.pathItems.length; x++) {

            if (activeDocument.pathItems[x].kind == PathKind.WORKPATH) {

            app.activeDocument.pathItems[x].name = thePathsName;

            var myPathItem = app.activeDocument.pathItems[x]

            }

            };

            app.preferences.rulerUnits = originalRulerUnits;

            return myPathItem

            };

          ////// determine selected path, updated 08.2011 //////

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

            // save work path;

            if (app.activeDocument.pathItems[app.activeDocument.pathItems.length - 1].kind == PathKind.WORKPATH) {

            // =======================================================

            var idslct = charIDToTypeID( "slct" );

            var desc3 = new ActionDescriptor();

            var idnull = charIDToTypeID( "null" );

            var ref2 = new ActionReference();

            var idPath = charIDToTypeID( "Path" );

            var idWrPt = charIDToTypeID( "WrPt" );

            ref2.putProperty( idPath, idWrPt );

            desc3.putReference( idnull, ref2 );

            executeAction( idslct, desc3, DialogModes.NO );

            // =======================================================

            var idMk = charIDToTypeID( "Mk  " );

            var desc4 = new ActionDescriptor();

            var idnull = charIDToTypeID( "null" );

            var ref3 = new ActionReference();

            var idPath = charIDToTypeID( "Path" );

            ref3.putClass( idPath );

            desc4.putReference( idnull, ref3 );

            var idFrom = charIDToTypeID( "From" );

            var ref4 = new ActionReference();

            var idPath = charIDToTypeID( "Path" );

            var idWrPt = charIDToTypeID( "WrPt" );

            ref4.putProperty( idPath, idWrPt );

            desc4.putReference( idFrom, ref4 );

            var idNm = charIDToTypeID( "Nm  " );

            desc4.putString( idNm, dateString() );

            executeAction( idMk, desc4, DialogModes.NO );

            };

            //

            if (theName == "Work Path") {

            return app.activeDocument.pathItems[app.activeDocument.pathItems.length - 1]

            }

            else {

            return app.activeDocument.pathItems.getByName(theName)

            }

            }

            catch (e) {

            return undefined

            }

            };