I accidentally merged all the shapes into a single vector layer in Photoshop. Luckily, they still retained their individual paths, so I could use the path selection tool to select them. However, my job requires me to separate them into individual vector layers, and there are thousands of such shapes, like this:
Correct answer c.pfaffenbichler
// split layer with vector mask into layers according to subpathitems; // 2026, use it at yout own risk; if (app.documents.length > 0) { if (hasVectorMask() == true) { var myDocument = activeDocument; var theLayer = myDocument.activeLayer; var thePath = collectPathInfoFromDesc2023 (myDocument, myDocument.pathItems[myDocument.pathItems.length-1]); for (var m = 0; m < thePath.length; m++) { var thisLayer = theLayer.duplicate(); myDocument.activeLayer = thisLayer; changeSelectedPath2020([thePath[m]]) myDocument.activeLayer = theLayer; }; theLayer.remove() } }; ////// collect path info from actiondescriptor, indices start at 1, not 0 ////// function collectPathInfoFromDesc2023 (myDocument, thePath) { var originalRulerUnits = app.preferences.rulerUnits; app.preferences.rulerUnits = Units.POINTS; // based of functions from xbytor’s stdlib; var idPath = charIDToTypeID( "Path" ); var ref = new ActionReference(); // check if thePath is an index or a dom-path; if (thePath.constructor == Number) { ref.putIndex(idPath, thePath) } else { thePath.select(); var ref = new ActionReference(); ref.putEnumerated( charIDToTypeID( "Path" ), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); }; // get stuff; 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; }; ////// change a path based on collectPathInfoFromDesc2023-array ////// function changeSelectedPath2020(theArray) { 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.putEnumerated( cTID('Path'), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 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); /// get index; var ref = new ActionReference(); ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("itemIndex")); ref.putEnumerated( charIDToTypeID("Path"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); var pathDesc = executeActionGet(ref); var myPathItem = activeDocument.pathItems[pathDesc.getInteger(stringIDToTypeID("itemIndex")) - 1]; app.preferences.rulerUnits = originalRulerUnits; return myPathItem }; ////// from »Flatten All Masks.jsx« by jeffrey tranberry ////// 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; };
// split layer with vector mask into layers according to subpathitems; // 2026, use it at yout own risk; if (app.documents.length > 0) { if (hasVectorMask() == true) { var myDocument = activeDocument; var theLayer = myDocument.activeLayer; var thePath = collectPathInfoFromDesc2023 (myDocument, myDocument.pathItems[myDocument.pathItems.length-1]); for (var m = 0; m < thePath.length; m++) { var thisLayer = theLayer.duplicate(); myDocument.activeLayer = thisLayer; changeSelectedPath2020([thePath[m]]) myDocument.activeLayer = theLayer; }; theLayer.remove() } }; ////// collect path info from actiondescriptor, indices start at 1, not 0 ////// function collectPathInfoFromDesc2023 (myDocument, thePath) { var originalRulerUnits = app.preferences.rulerUnits; app.preferences.rulerUnits = Units.POINTS; // based of functions from xbytor’s stdlib; var idPath = charIDToTypeID( "Path" ); var ref = new ActionReference(); // check if thePath is an index or a dom-path; if (thePath.constructor == Number) { ref.putIndex(idPath, thePath) } else { thePath.select(); var ref = new ActionReference(); ref.putEnumerated( charIDToTypeID( "Path" ), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); }; // get stuff; 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; }; ////// change a path based on collectPathInfoFromDesc2023-array ////// function changeSelectedPath2020(theArray) { 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.putEnumerated( cTID('Path'), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 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); /// get index; var ref = new ActionReference(); ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("itemIndex")); ref.putEnumerated( charIDToTypeID("Path"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); var pathDesc = executeActionGet(ref); var myPathItem = activeDocument.pathItems[pathDesc.getInteger(stringIDToTypeID("itemIndex")) - 1]; app.preferences.rulerUnits = originalRulerUnits; return myPathItem }; ////// from »Flatten All Masks.jsx« by jeffrey tranberry ////// 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; };
I had the functions that do the "heavy lifting" available from previous projects, so it was not that difficult. And I am sure one could streamline the script further.