Skip to main content
Inspiring
May 4, 2024
Answered

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

 

This topic has been closed for replies.
Correct answer MotionThunder

Well, that certainly depends on what you mean by "any complexity".

 

You may want to download the sample file below. It contains four compound paths. I'd not call them overly complex. Try to run your script in that file and see what happens.

 

Compound Stress Test

 

Please don't get me wrong. I think your script is very good (thanks for sharing), but one may keep in mind that it will not always work as intended.


Hello,

Today I was testing different scripts for processing the shapes you provided as an example and was able to create another script that is more suitable for processing strict monolithic shapes with gaps.

The previous script, on the other hand, works best with freeform shapes.



P.S. I had to remove one part on one of the shapes, because in any of the scripts, if you make a cut there, that part will be a separate path, and the goal was to create solid paths from complex shapes.

P.S.S. I removed the big rectangle with holes because Adobe software takes too long to process it and I couldn't record video.

I will attach to this post the code for two script variants that work differently with different forms, and each can be applied in a certain situation where the other fails. Maybe someday this post will be useful to someone.


1 reply

Kurt Gold
Community Expert
May 4, 2024

In case you mainly have rather simple compound paths as shown in your screenshot, it can be done with an action.

 

Would an action even be an option for you?

 

Or are there compound paths which are way more complicated?

Inspiring
May 4, 2024

del

Inspiring
May 4, 2024

del