Compound Path to Path. Scripting
- May 4, 2024
- 1 reply
- 3068 views
Hello,
I am attempting to solve a specific task required for my Adobe Illustrator + After Effects Masks workflow. I am familiar with various manual and automated techniques for working with shapes and masks, but in this particular case, I want to address this task in its specific form.
Essentially, my goal is to develop a tool (script/plugin) that manipulates a Compound Path in a project similar to how I might use the Knife tool to transform a Compound Path into a continuous solid Path. Ultimately, I want to produce a single, solid mask in an After Effects project from this. I have attached a screenshot for clarity.
(I've also attached the image as a file to the post so it can be seen in more detail)
I found that the Adobe Illustrator API does not provide a straightforward way to automate the use of the Knife tool. However, through trial and error, I discovered that drawing thin shapes (0.01pt thick) at the intersections of the inner and outer paths of the Compound Path and then applying Pathfinder > Divide achieves the desired result, which can be automated. This led to the creation of the script shown below, but it is only a starting point and operates quite crudely by just creating intersections with thin lines on each Compound Path and applying Pathfinder. This results in a non-compound Path, but not as a single continuous path, rather it's segmented into multiple parts.
I would like to more elegantly solve this problem. Logically, the code needs to first identify random spots on the Compound Path where cuts along the internal and external paths can be made, to then implement logic in the script to place lines of 0.01pt thickness precisely at these spots. However, I have no idea what specific information I need for this, and extensive online research has turned up nothing, as this task is quite specific.
I would appreciate any help on this issue, and any suggestions on what information I should look for.
Thank you!
The example code I wrote above:
function drawThinRectangle(centerX, centerY, width, height, angle) {
var rect = app.activeDocument.pathItems.rectangle(centerY + height / 2, centerX - width / 2, width, height);
rect.stroked = false;
rect.filled = true;
rect.fillColor = app.activeDocument.swatches[0].color;
rect.rotate(angle);
return rect;
}
function applyPathfinderToGroup(groupItem) {
// Selects all page items inside the group
for (var i = 0; i < groupItem.pageItems.length; i++) {
groupItem.pageItems[i].selected = true;
}
// Apply Pathfinder Subtract
app.executeMenuCommand('Live Pathfinder Subtract');
app.executeMenuCommand('expandStyle');
// Ungroup the expanded pathfinder result
app.executeMenuCommand('ungroup');
}
function processCompoundPath(compoundPathItem, index) {
var doc = app.activeDocument;
var layer = compoundPathItem.layer;
var groupItems = layer.groupItems.add();
groupItems.name = "Comp_" + ("0" + (index + 1)).slice(-2);
var bounds = compoundPathItem.geometricBounds; // [x1, y1, x2, y2]
var centerX = (bounds[0] + bounds[2]) / 2;
var centerY = (bounds[1] + bounds[3]) / 2;
var layerWidth = bounds[2] - bounds[0];
var layerHeight = bounds[1] - bounds[3];
var maxDimension = Math.max(layerWidth, layerHeight);
// Create “lines” as thin rectangles for the current Compound Path
var thinRectVertical = drawThinRectangle(centerX, centerY, 0.001, layerHeight, 0);
var thinRectHorizontal = drawThinRectangle(centerX, centerY, layerWidth, 0.001, 0);
var thinRectDiagonal1 = drawThinRectangle(centerX, centerY, 0.001, maxDimension, 45);
var thinRectDiagonal2 = drawThinRectangle(centerX, centerY, 0.001, maxDimension, -45);
// Move compound path and lines to a new group
compoundPathItem.moveToBeginning(groupItems);
thinRectVertical.moveToBeginning(groupItems);
thinRectHorizontal.moveToBeginning(groupItems);
thinRectDiagonal1.moveToBeginning(groupItems);
thinRectDiagonal2.moveToBeginning(groupItems);
applyPathfinderToGroup(groupItems);
}
function main() {
var doc = app.activeDocument;
var allCompoundPaths = [];
for (var i = 0; i < doc.pageItems.length; i++) {
if (doc.pageItems[i].typename === 'CompoundPathItem') {
allCompoundPaths.push(doc.pageItems[i]);
}
}
if (allCompoundPaths.length === 0) {
alert('There are no compound paths in the document.');
return;
}
for (var j = 0; j < allCompoundPaths.length; j++) {
processCompoundPath(allCompoundPaths[j], j);
}
app.activeDocument.selection = null;
}
main();
