This script, developed by Tom from Inventsable (contact: tom@inventsable.cc) and based on the Outliner project hosted on GitHub, enables you to convert all paths in the active Illustrator document into permanent outlines. In this context “outlines” mean that every path is re-rendered with its individual anchor points and handles drawn explicitly. The modification is non-destructive in that it can be reversed with a single Undo command from Illustrator’s Edit menu.
Purpose & Functionality

- Primary Goal:
The script converts existing path items (including all their anchor points and handles) into a structured, visual representation. This creates a permanent “outline” of the object with visible nodes: - It replaces the appearance of each path with a standardized stroke.
- It draws anchors, handles, and connecting “stick” lines using customizable geometric shapes (rectangles for anchors and ellipses for handles).
- Customization Options:
At the top of the script, several configuration settings allow you to adjust the final appearance: - Anchor Parameters:
anchorWidth
(stroke width for anchors)anchorSize
(dimensions of the anchor rectangle)anchorColor
(RGB color for anchors, default set to a blue value)anchorIsFilled
(determines whether anchors are filled or only outlined)
- Handle Parameters:
handleSize
(dimensions of the handle’s ellipse)
- Outline Appearance:
outlineWidth
(stroke width for the converted path outlines)outlineColor
(stroke color for the outlines, set by default as a dark “rich black”)
- Additional Options:
useLayerLabelColor
: If enabled, the script overrides the default anchor color with the parent layer’s label color.forceOpacity
: Forces the converted paths to have full opacity.overrideComplex
: When true, the script clones all objects to reconstruct them, which is useful for handling complex appearances (such as multiple strokes per item).mergeClippingMasks
: Uses a Pathfinder–Intersect action to merge clipping masks and their contents.renameGenericPaths
: Renames unnamed paths based on their parent layer.generateIds
: When enabled, generated names include unique 3-character identifiers.groupRelated
: Groups newly created anchor, handle, and stick items together as children of a parent group.
How the Script Works
- Scanning and Collection:
The script scans all page items in the active document. Depending on theoverrideComplex
setting, it either works directly on the existing path items or clones them in order to rebuild complex appearances. - Converting to Outlines:
For each applicable path:
- The appearance is replaced with a uniform stroke based on the
outlineWidth
andoutlineColor
. - Each anchor point on the path is processed:
- A rectangular “anchor” is drawn at the anchor point.
- Two “handle” objects (one for the left and one for the right direction) are drawn if the coordinate data indicates a handle is present.
- If grouping is enabled, related items (anchor, handles, and connecting sticks) are nested within a dedicated group for that path.
- Layer Sorting:
After conversion, the script rearranges the stacking order within each layer so that the newly created anchor groups are positioned directly above their corresponding original path items. This makes it easier to manage or edit the outlines further if necessary. - Additional Processing:
Functions such as merging clipping masks (using a dynamically created Pathfinder action) and cloning path items (for overriding complex appearances) enhance the versatility and robustness of the script.
Usage
- Prepare Your Document:
Open an Adobe Illustrator document that contains one or more path items you wish to convert to outlines. - Edit Configuration (Optional):
Before running the script, you can adjust the settings at the top of the file (e.g., sizes, colors, grouping, etc.) to tailor the output to your needs. - Run the Script:
Execute the script via Illustrator’s File > Scripts menu. The script will process every path in the current document:
- It will convert the path appearances.
- It will draw anchors and handles for each point.
- It will apply any selected grouping and sorting options.
- Undo if Needed:
The transformation is performed with standard Illustrator commands, so you can revert all changes with a single Edit > Undo command.
This script is ideal for designers or developers who need to create a visible representation of path data with detailed control over anchors and handles. Its extensibility makes it a good starting point for further customization or integration into larger workflows.
/*
https://github.com/Inventsable/Outliner
contact: tom@inventsable.cc
Barebones script to convert all paths in current document to permanent Outlines, including handles and anchors.
This action can be undone with a single Edit > Undo command.
You can edit the below settings:
*/
var anchorWidth = 4; // number in pixels, width of stroke
var anchorSize = 20; // number in pixels, height/width of rectangle
var handleSize = 25; // number in pixels, size of ellipse/orb where handle is grabbed
var anchorColor = newRGB(50, 50, 200); // RGB value, defaults to blue
var anchorIsFilled = false; // Boolean, if true anchors are filled, otherwise have only stroke
//
var parentGroupLabel = "_nodes";
var anchorLabel = "_anchor";
var handleLabel = "_handle";
var stickLabel = "_stick";
//
var outlineWidth = 5; // number in pixels, width of stroke
var outlineColor = newRGB(35, 31, 32); // The RGB value of color (default rich black)
//
var useLayerLabelColor = true; // Boolean, if true override above anchorColor and use the Layer's label instead
var forceOpacity = true; // Boolean, if true force all paths to have full opacity
var overrideComplex = false; // Boolean, if true clone all objects and attempt to reconstruct them
// This only needs to be true if you have complex Appearances like multiple strokes per object
var mergeClippingMasks = true; // Boolean, if true will use Pathfinder > Intersect on all Clipping Masks and contents
// If merging is true, requires an additional Undo command per item merged to get back to original
var renameGenericPaths = true; // Boolean, if true will rename unnamed paths as their parent layer
var generateIds = false; // Boolean, if true with generate names with 3 character unique identifiers
var groupRelated = true; // Boolean, if true create child groups for each handle within a parent group for anchor and both handles
/*
Do not edit below unless you know what you're doing!
*/
convertAllToOutlines();
var doc = app.activeDocument;
function convertAllToOutlines() {
convertListToOutlines(scanCurrentPageItems());
sortLayerContents();
}
// Return a list of current pathItems in activeDoc or their clones when overriding complex appearance
function scanCurrentPageItems() {
var list = [];
if (!overrideComplex) {
if (mergeClippingMasks) mergeClippingPaths();
for (var i = app.activeDocument.pathItems.length - 1; i >= 0; i--)
list.push(app.activeDocument.pathItems[i]);
return list;
} else {
return cloneAllPathItems();
}
}
function convertListToOutlines(list) {
for (var i = list.length - 1; i >= 0; i--) {
var item = list[i];
item.name = renameGenericPaths
? rollName(
item.name || item.parent.name || item.layer.name,
item,
item.layer
)
: item.name || item.parent.name || item.layer.name;
if (item.stroked || item.filled) {
replaceAppearance(item);
var parentgroup = groupRelated
? app.activeDocument.groupItems.add()
: null;
if (groupRelated) {
parentgroup.name = item.name + parentGroupLabel;
parentgroup.move(item.layer, ElementPlacement.PLACEATBEGINNING);
}
if (item.pathPoints && item.pathPoints.length)
for (var p = 0; p < item.pathPoints.length; p++) {
var point = item.pathPoints[p];
var pointName = item.name + "[" + p + "]";
var group = groupRelated ? parentgroup.groupItems.add() : null;
if (groupRelated) group.name = pointName;
drawAnchor(point, item.layer, pointName, group);
drawHandle(point, "left", item.layer, pointName, group);
drawHandle(point, "right", item.layer, pointName, group);
item.opacity = forceOpacity ? 100.0 : item.opacity;
}
}
}
}
function drawAnchor(point, layer, name, group) {
var anchor = groupRelated
? group.pathItems.rectangle(
point.anchor[1] + anchorSize / 2,
point.anchor[0] - anchorSize / 2,
anchorSize,
anchorSize
)
: app.activeDocument.pathItems.rectangle(
point.anchor[1] + anchorSize / 2,
point.anchor[0] - anchorSize / 2,
anchorSize,
anchorSize
);
anchor.name = name + anchorLabel;
if (!groupRelated) anchor.move(layer, ElementPlacement.PLACEATBEGINNING);
setAnchorAppearance(anchor, false, layer);
return [anchor];
}
function drawHandle(point, direction, layer, name, group) {
if (
Number(point.anchor[0]) !== Number(point[direction + "Direction"][0]) ||
Number(point.anchor[1]) !== Number(point[direction + "Direction"][1])
) {
var stick = groupRelated
? group.pathItems.add()
: app.activeDocument.pathItems.add();
stick.setEntirePath([point.anchor, point[direction + "Direction"]]);
if (!groupRelated) stick.move(layer, ElementPlacement.PLACEATBEGINNING);
stick.name = name + "_" + direction.charAt(0).toUpperCase() + stickLabel;
setAnchorAppearance(stick, true, layer);
var handle = groupRelated
? group.pathItems.ellipse(
point[direction + "Direction"][1] + handleSize / 2,
point[direction + "Direction"][0] - handleSize / 2,
handleSize,
handleSize
)
: app.activeDocument.pathItems.ellipse(
point[direction + "Direction"][1] + handleSize / 2,
point[direction + "Direction"][0] - handleSize / 2,
handleSize,
handleSize
);
if (!groupRelated) handle.move(layer, ElementPlacement.PLACEATBEGINNING);
handle.stroked = false;
handle.filled = true;
handle.name = name + "_" + direction.charAt(0).toUpperCase() + handleLabel;
handle.fillColor = useLayerLabelColor ? layer.color : anchorColor;
return [stick, handle];
}
}
function setAnchorAppearance(item, isHandle, layer) {
var realColor = useLayerLabelColor ? layer.color : anchorColor;
if (!isHandle) {
item.filled = anchorIsFilled;
item.stroked = !anchorIsFilled;
if (!anchorIsFilled) {
item.strokeWidth = anchorWidth;
item.strokeColor = realColor;
} else {
item.fillColor = realColor;
}
} else {
item.filled = false;
item.stroked = true;
item.strokeWidth = anchorWidth;
item.strokeColor = realColor;
}
}
function replaceAppearance(item) {
item.filled = false;
item.stroked = true;
item.strokeWidth = outlineWidth;
item.strokeColor = outlineColor;
}
function newRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
// Rearrange results per layer so anchor Groups are directly above their target path
function sortLayerContents() {
for (var i = 0; i < app.activeDocument.layers.length; i++) {
var layer = app.activeDocument.layers[i];
for (var c = 0; c < layer.pathItems.length; c++)
layer.pathItems[c].zOrder(ZOrderMethod.BRINGTOFRONT);
var offset = layer.pathItems.length + 1;
for (var c = 0; c < layer.groupItems.length; c++) {
var group = layer.groupItems[c];
offset = Number(offset) - Number(1);
for (var z = 0; z < offset; z++) group.zOrder(ZOrderMethod.BRINGFORWARD);
}
}
}
// Generates a unique identifier for layer to use in children nodes
function rollName(name, item, layer) {
var siblingCount = 0;
var nameRX = new RegExp(name + "\\[\\d\\].*");
if (!generateIds)
for (var i = 0; i < layer.pathItems.length; i++)
if (
nameRX.test(layer.pathItems[i].name) &&
layer.pathItems[i] !== item &&
!/group/i.test(layer.pathItems[i].typename)
)
siblingCount++;
return generateIds
? name + "_" + shortId() + "_"
: name + "[" + siblingCount + "]";
}
// Reconstruct all PathItems with basic data to override any complex appearances
function cloneAllPathItems() {
var list = [];
var cloneProps = ["position", "left", "top", "name", "closed"];
var pathProps = ["anchor", "leftDirection", "rightDirection", "pointType"];
for (var i = app.activeDocument.pathItems.length - 1; i >= 0; i--) {
var item = app.activeDocument.pathItems[i];
var clone = {
pathPoints: [],
};
for (var v = 0; v < cloneProps.length; v++) {
var prop = cloneProps[v];
clone[prop] = item[prop];
}
for (var v = 0; v < item.pathPoints.length; v++)
clone.pathPoints.push(item.pathPoints[v]);
list.push(clone);
item.remove();
}
var dupes = [];
for (var i = 0; i < list.length; i++) {
var schema = list[i];
var item = app.activeDocument.pathItems.add();
for (var v = 0; v < cloneProps.length; v++) {
var prop = cloneProps[v];
item[prop] = schema[prop];
}
for (var v = 0; v < schema.pathPoints.length; v++) {
var point = schema.pathPoints[v];
var newpoint = item.pathPoints.add();
for (var c = 0; c < pathProps.length; c++) {
var prop = pathProps[c];
newpoint[prop] = point[prop];
}
}
dupes.push(item);
}
return dupes;
}
function mergeClippingPaths() {
app.selection = null;
app.executeMenuCommand("Clipping Masks menu item");
var masks = app.selection;
if (app.selection.length < 1) return null;
for (var i = 0; i < masks.length; i++) {
var mask = masks[i];
var parent = mask.parent;
var siblings = [];
for (var v = 0; v < parent.pathItems.length; v++) {
var child = parent.pathItems[v];
if (!child.clipping) {
// var tag = child.tags.add();
// tag.name = "marked";
siblings.push(child);
}
}
if (siblings.length > 1)
for (var v = 1; v < siblings.length; v++) {
app.selection = null;
var dupe = mask.duplicate();
var sibling = siblings[v];
var lastname = sibling.name;
dupe.selected = true;
sibling.selected = true;
intersectAction();
//
// TODO
// If path has name, doing intersect creates a new path and this reference is lost.
//
}
app.selection = null;
mask.selected = true;
siblings[0].selected = true;
var lastname = siblings[0].name;
intersectAction();
app.selection = null;
//
// Fix name transfer
//
parent.selected = true;
app.executeMenuCommand("ungroup");
app.selection = null;
}
}
// Thanks Qwertyfly
// https://community.adobe.com/t5/illustrator/js-cs6-executemenucommand/m-p/5904772#M19673
function intersectAction() {
if ((app.documents.length = 0)) {
return;
}
var ActionString = [
"/version 3",
"/name [ 10",
" 4578706f727454657374",
"]",
"/isOpen 1",
"/actionCount 1",
"/action-1 {",
" /name [ 9",
" 496e74657273656374",
" ]",
" /keyIndex 0",
" /colorIndex 0",
" /isOpen 1",
" /eventCount 1",
" /event-1 {",
" /useRulersIn1stQuadrant 0",
" /internalName (ai_plugin_pathfinder)",
" /localizedName [ 10",
" 5061746866696e646572",
" ]",
" /isOpen 0",
" /isOn 1",
" /hasDialog 0",
" /parameterCount 1",
" /parameter-1 {",
" /key 1851878757",
" /showInPalette -1",
" /type (enumerated)",
" /name [ 9",
" 496e74657273656374",
" ]",
" /value 1",
" }",
" }",
"}",
].join("\n");
createAction(ActionString);
var ActionString = null;
app.doScript("Intersect", "ExportTest", false);
app.unloadAction("ExportTest", "");
function createAction(str) {
var f = new File("~/ScriptAction.aia");
f.open("w");
f.write(str);
f.close();
app.loadAction(f);
f.remove();
}
}
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function shortId() {
var str = "";
var codex = "0123456789abcdefghijklmnopqrstuvwxyz";
for (var i = 0; i <= 2; i++)
str += codex.charAt(randomInt(0, codex.length - 1));
return str.toUpperCase();
}
Update : Outliner with UI

/**
* Outliner Script with UI
*
* Based on the Outliner script – converts all paths in the current document to permanent outlines including handles and anchors.
* You can modify the parameters below via the UI before execution.
*
* Contact: tom@inventsable.cc
* https://github.com/Inventsable/Outliner
*
*/
// Default settings
var anchorWidth = 4; // number in pixels, width of stroke
var anchorSize = 20; // number in pixels, height/width of rectangle
var handleSize = 25; // number in pixels, size of ellipse/orb where handle is grabbed
var anchorColor = newRGB(50, 50, 200); // RGB value, defaults to blue
var anchorIsFilled = false; // Boolean, if true anchors are filled, otherwise only stroked
var parentGroupLabel = "_nodes";
var anchorLabel = "_anchor";
var handleLabel = "_handle";
var stickLabel = "_stick";
var outlineWidth = 5; // number in pixels, width of stroke
var outlineColor = newRGB(35, 31, 32); // The RGB value of color (default rich black)
var useLayerLabelColor = true; // Boolean, if true override above anchorColor and use the Layer's label instead
var forceOpacity = true; // Boolean, if true force all paths to have full opacity
var overrideComplex = false; // Boolean, if true clone all objects and attempt to reconstruct them
var mergeClippingMasks = true; // Boolean, if true will use Pathfinder > Intersect on all Clipping Masks and contents
var renameGenericPaths = true; // Boolean, if true will rename unnamed paths as their parent layer
var generateIds = false; // Boolean, if true will generate names with 3-character unique identifiers
var groupRelated = true; // Boolean, if true create child groups for each handle within a parent group
// Show parameter UI first
showSettingsDialog();
// After dialog, run conversion using the (possibly modified) global settings.
convertAllToOutlines();
var doc = app.activeDocument;
///////////////////////////
// UI Section
///////////////////////////
function showSettingsDialog() {
var dlg = new Window("dialog", "Outliner Settings", undefined, {maximizeButton:true});
dlg.orientation = "column";
dlg.alignChildren = ["fill", "top"];
// Anchor Settings Group
var anchorGroup = dlg.add("panel", undefined, "Anchor Settings");
anchorGroup.orientation = "column";
anchorGroup.alignChildren = ["fill", "top"];
var grpAnchorWidth = anchorGroup.add("group");
grpAnchorWidth.add("statictext", undefined, "Anchor Stroke Width (px):");
var inpAnchorWidth = grpAnchorWidth.add("edittext", undefined, anchorWidth);
inpAnchorWidth.characters = 5;
var grpAnchorSize = anchorGroup.add("group");
grpAnchorSize.add("statictext", undefined, "Anchor Size (px):");
var inpAnchorSize = grpAnchorSize.add("edittext", undefined, anchorSize);
inpAnchorSize.characters = 5;
var grpAnchorColor = anchorGroup.add("group");
grpAnchorColor.add("statictext", undefined, "Anchor Color (R,G,B):");
var inpAnchorColorR = grpAnchorColor.add("edittext", undefined, anchorColor.red);
inpAnchorColorR.characters = 3;
var inpAnchorColorG = grpAnchorColor.add("edittext", undefined, anchorColor.green);
inpAnchorColorG.characters = 3;
var inpAnchorColorB = grpAnchorColor.add("edittext", undefined, anchorColor.blue);
inpAnchorColorB.characters = 3;
var grpAnchorFill = anchorGroup.add("group");
var chkAnchorFilled = grpAnchorFill.add("checkbox", undefined, "Fill Anchors");
chkAnchorFilled.value = anchorIsFilled;
// Handle Settings Group
var handleGroup = dlg.add("panel", undefined, "Handle Settings");
handleGroup.orientation = "column";
handleGroup.alignChildren = ["fill", "top"];
var grpHandleSize = handleGroup.add("group");
grpHandleSize.add("statictext", undefined, "Handle Size (px):");
var inpHandleSize = grpHandleSize.add("edittext", undefined, handleSize);
inpHandleSize.characters = 5;
// Outline Settings Group
var outlineGroup = dlg.add("panel", undefined, "Outline Settings");
outlineGroup.orientation = "column";
outlineGroup.alignChildren = ["fill", "top"];
var grpOutlineWidth = outlineGroup.add("group");
grpOutlineWidth.add("statictext", undefined, "Outline Stroke Width (px):");
var inpOutlineWidth = grpOutlineWidth.add("edittext", undefined, outlineWidth);
inpOutlineWidth.characters = 5;
var grpOutlineColor = outlineGroup.add("group");
grpOutlineColor.add("statictext", undefined, "Outline Color (R,G,B):");
var inpOutlineColorR = grpOutlineColor.add("edittext", undefined, outlineColor.red);
inpOutlineColorR.characters = 3;
var inpOutlineColorG = grpOutlineColor.add("edittext", undefined, outlineColor.green);
inpOutlineColorG.characters = 3;
var inpOutlineColorB = grpOutlineColor.add("edittext", undefined, outlineColor.blue);
inpOutlineColorB.characters = 3;
// Additional Options Group
var optionsGroup = dlg.add("panel", undefined, "Additional Options");
optionsGroup.orientation = "column";
optionsGroup.alignChildren = ["left", "top"];
var chkUseLayerLabelColor = optionsGroup.add("checkbox", undefined, "Use Layer Label Color for Anchors");
chkUseLayerLabelColor.value = useLayerLabelColor;
var chkForceOpacity = optionsGroup.add("checkbox", undefined, "Force Full Opacity on Paths");
chkForceOpacity.value = forceOpacity;
var chkOverrideComplex = optionsGroup.add("checkbox", undefined, "Override Complex Appearance (clone all paths)");
chkOverrideComplex.value = overrideComplex;
var chkMergeClippingMasks = optionsGroup.add("checkbox", undefined, "Merge Clipping Masks");
chkMergeClippingMasks.value = mergeClippingMasks;
var chkRenameGenericPaths = optionsGroup.add("checkbox", undefined, "Rename Unnamed Paths");
chkRenameGenericPaths.value = renameGenericPaths;
var chkGenerateIds = optionsGroup.add("checkbox", undefined, "Generate Unique IDs for Names");
chkGenerateIds.value = generateIds;
var chkGroupRelated = optionsGroup.add("checkbox", undefined, "Group Anchors/Handles with Parent Object");
chkGroupRelated.value = groupRelated;
// OK/Cancel Buttons
var btnGroup = dlg.add("group");
btnGroup.alignment = "center";
var btnCancel = btnGroup.add("button", undefined, "Cancel", {name:"cancel"});
var btnOK = btnGroup.add("button", undefined, "OK", {name:"ok"});
btnOK.onClick = function() {
// Update globals from UI
anchorWidth = parseFloat(inpAnchorWidth.text);
anchorSize = parseFloat(inpAnchorSize.text);
handleSize = parseFloat(inpHandleSize.text);
anchorColor = newRGB(parseFloat(inpAnchorColorR.text), parseFloat(inpAnchorColorG.text), parseFloat(inpAnchorColorB.text));
anchorIsFilled = chkAnchorFilled.value;
outlineWidth = parseFloat(inpOutlineWidth.text);
outlineColor = newRGB(parseFloat(inpOutlineColorR.text), parseFloat(inpOutlineColorG.text), parseFloat(inpOutlineColorB.text));
useLayerLabelColor = chkUseLayerLabelColor.value;
forceOpacity = chkForceOpacity.value;
overrideComplex = chkOverrideComplex.value;
mergeClippingMasks = chkMergeClippingMasks.value;
renameGenericPaths = chkRenameGenericPaths.value;
generateIds = chkGenerateIds.value;
groupRelated = chkGroupRelated.value;
dlg.close();
}
btnCancel.onClick = function() {
dlg.close();
}
dlg.center();
dlg.show();
}
///////////////////////////
// Main Conversion Functions
///////////////////////////
function convertAllToOutlines() {
convertListToOutlines(scanCurrentPageItems());
sortLayerContents();
}
function scanCurrentPageItems() {
var list = [];
if (!overrideComplex) {
if (mergeClippingMasks) mergeClippingPaths();
for (var i = app.activeDocument.pathItems.length - 1; i >= 0; i--)
list.push(app.activeDocument.pathItems[i]);
return list;
} else {
return cloneAllPathItems();
}
}
function convertListToOutlines(list) {
for (var i = list.length - 1; i >= 0; i--) {
var item = list[i];
item.name = renameGenericPaths
? rollName(
item.name || item.parent.name || item.layer.name,
item,
item.layer
)
: item.name || item.parent.name || item.layer.name;
if (item.stroked || item.filled) {
replaceAppearance(item);
var parentgroup = groupRelated
? app.activeDocument.groupItems.add()
: null;
if (groupRelated) {
parentgroup.name = item.name + parentGroupLabel;
parentgroup.move(item.layer, ElementPlacement.PLACEATBEGINNING);
}
if (item.pathPoints && item.pathPoints.length)
for (var p = 0; p < item.pathPoints.length; p++) {
var point = item.pathPoints[p];
var pointName = item.name + "[" + p + "]";
var group = groupRelated ? parentgroup.groupItems.add() : null;
if (groupRelated) group.name = pointName;
drawAnchor(point, item.layer, pointName, group);
drawHandle(point, "left", item.layer, pointName, group);
drawHandle(point, "right", item.layer, pointName, group);
item.opacity = forceOpacity ? 100.0 : item.opacity;
}
}
}
}
function drawAnchor(point, layer, name, group) {
var anchor = groupRelated
? group.pathItems.rectangle(
point.anchor[1] + anchorSize / 2,
point.anchor[0] - anchorSize / 2,
anchorSize,
anchorSize
)
: app.activeDocument.pathItems.rectangle(
point.anchor[1] + anchorSize / 2,
point.anchor[0] - anchorSize / 2,
anchorSize,
anchorSize
);
anchor.name = name + anchorLabel;
if (!groupRelated) anchor.move(layer, ElementPlacement.PLACEATBEGINNING);
setAnchorAppearance(anchor, false, layer);
return [anchor];
}
function drawHandle(point, direction, layer, name, group) {
if (
Number(point.anchor[0]) !== Number(point[direction + "Direction"][0]) ||
Number(point.anchor[1]) !== Number(point[direction + "Direction"][1])
) {
var stick = groupRelated
? group.pathItems.add()
: app.activeDocument.pathItems.add();
stick.setEntirePath([point.anchor, point[direction + "Direction"]]);
if (!groupRelated) stick.move(layer, ElementPlacement.PLACEATBEGINNING);
stick.name = name + "_" + direction.charAt(0).toUpperCase() + stickLabel;
setAnchorAppearance(stick, true, layer);
var handle = groupRelated
? group.pathItems.ellipse(
point[direction + "Direction"][1] + handleSize / 2,
point[direction + "Direction"][0] - handleSize / 2,
handleSize,
handleSize
)
: app.activeDocument.pathItems.ellipse(
point[direction + "Direction"][1] + handleSize / 2,
point[direction + "Direction"][0] - handleSize / 2,
handleSize,
handleSize
);
if (!groupRelated) handle.move(layer, ElementPlacement.PLACEATBEGINNING);
handle.stroked = false;
handle.filled = true;
handle.name = name + "_" + direction.charAt(0).toUpperCase() + handleLabel;
handle.fillColor = useLayerLabelColor ? layer.color : anchorColor;
return [stick, handle];
}
}
function setAnchorAppearance(item, isHandle, layer) {
var realColor = useLayerLabelColor ? layer.color : anchorColor;
if (!isHandle) {
item.filled = anchorIsFilled;
item.stroked = !anchorIsFilled;
if (!anchorIsFilled) {
item.strokeWidth = anchorWidth;
item.strokeColor = realColor;
} else {
item.fillColor = realColor;
}
} else {
item.filled = false;
item.stroked = true;
item.strokeWidth = anchorWidth;
item.strokeColor = realColor;
}
}
function replaceAppearance(item) {
item.filled = false;
item.stroked = true;
item.strokeWidth = outlineWidth;
item.strokeColor = outlineColor;
}
function newRGB(r, g, b) {
var color = new RGBColor();
color.red = r;
color.green = g;
color.blue = b;
return color;
}
function sortLayerContents() {
for (var i = 0; i < app.activeDocument.layers.length; i++) {
var layer = app.activeDocument.layers[i];
for (var c = 0; c < layer.pathItems.length; c++)
layer.pathItems[c].zOrder(ZOrderMethod.BRINGTOFRONT);
var offset = layer.pathItems.length + 1;
for (var c = 0; c < layer.groupItems.length; c++) {
var group = layer.groupItems[c];
offset = Number(offset) - Number(1);
for (var z = 0; z < offset; z++) group.zOrder(ZOrderMethod.BRINGFORWARD);
}
}
}
function rollName(name, item, layer) {
var siblingCount = 0;
var nameRX = new RegExp(name + "\\[\\d\\].*");
if (!generateIds)
for (var i = 0; i < layer.pathItems.length; i++)
if (
nameRX.test(layer.pathItems[i].name) &&
layer.pathItems[i] !== item &&
!/group/i.test(layer.pathItems[i].typename)
)
siblingCount++;
return generateIds
? name + "_" + shortId() + "_"
: name + "[" + siblingCount + "]";
}
function cloneAllPathItems() {
var list = [];
var cloneProps = ["position", "left", "top", "name", "closed"];
var pathProps = ["anchor", "leftDirection", "rightDirection", "pointType"];
for (var i = app.activeDocument.pathItems.length - 1; i >= 0; i--) {
var item = app.activeDocument.pathItems[i];
var clone = {
pathPoints: [],
};
for (var v = 0; v < cloneProps.length; v++) {
var prop = cloneProps[v];
clone[prop] = item[prop];
}
for (var v = 0; v < item.pathPoints.length; v++)
clone.pathPoints.push(item.pathPoints[v]);
list.push(clone);
item.remove();
}
var dupes = [];
for (var i = 0; i < list.length; i++) {
var schema = list[i];
var item = app.activeDocument.pathItems.add();
for (var v = 0; v < cloneProps.length; v++) {
var prop = cloneProps[v];
item[prop] = schema[prop];
}
for (var v = 0; v < schema.pathPoints.length; v++) {
var point = schema.pathPoints[v];
var newpoint = item.pathPoints.add();
for (var c = 0; c < pathProps.length; c++) {
var prop = pathProps[c];
newpoint[prop] = point[prop];
}
}
dupes.push(item);
}
return dupes;
}
function mergeClippingPaths() {
app.selection = null;
app.executeMenuCommand("Clipping Masks menu item");
var masks = app.selection;
if (app.selection.length < 1) return null;
for (var i = 0; i < masks.length; i++) {
var mask = masks[i];
var parent = mask.parent;
var siblings = [];
for (var v = 0; v < parent.pathItems.length; v++) {
var child = parent.pathItems[v];
if (!child.clipping) {
siblings.push(child);
}
}
if (siblings.length > 1)
for (var v = 1; v < siblings.length; v++) {
app.selection = null;
var dupe = mask.duplicate();
var sibling = siblings[v];
var lastname = sibling.name;
dupe.selected = true;
sibling.selected = true;
intersectAction();
}
app.selection = null;
mask.selected = true;
siblings[0].selected = true;
var lastname = siblings[0].name;
intersectAction();
app.selection = null;
parent.selected = true;
app.executeMenuCommand("ungroup");
app.selection = null;
}
}
function intersectAction() {
if ((app.documents.length = 0)) {
return;
}
var ActionString = [
"/version 3",
"/name [ 10",
" 4578706f727454657374",
"]",
"/isOpen 1",
"/actionCount 1",
"/action-1 {",
" /name [ 9",
" 496e74657273656374",
" ]",
" /keyIndex 0",
" /colorIndex 0",
" /isOpen 1",
" /eventCount 1",
" /event-1 {",
" /useRulersIn1stQuadrant 0",
" /internalName (ai_plugin_pathfinder)",
" /localizedName [ 10",
" 5061746866696e646572",
" ]",
" /isOpen 0",
" /isOn 1",
" /hasDialog 0",
" /parameterCount 1",
" /parameter-1 {",
" /key 1851878757",
" /showInPalette -1",
" /type (enumerated)",
" /name [ 9",
" 496e74657273656374",
" ]",
" /value 1",
" }",
" }",
"}",
].join("\n");
createAction(ActionString);
var ActionString = null;
app.doScript("Intersect", "ExportTest", false);
app.unloadAction("ExportTest", "");
function createAction(str) {
var f = new File("~/ScriptAction.aia");
f.open("w");
f.write(str);
f.close();
app.loadAction(f);
f.remove();
}
}
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function shortId() {
var str = "";
var codex = "0123456789abcdefghijklmnopqrstuvwxyz";
for (var i = 0; i <= 2; i++)
str += codex.charAt(randomInt(0, codex.length - 1));
return str.toUpperCase();
}x