I think there would be a lot more work done through Adobe Illustrator Javascript if it did not fail in critical areas. There are two weak areas that I discovered, one which is not easy to find an answer, and one which seems like it is a bug.

Bug: referencing artboards

AI javascript prevents a reference to the artboards of non-active documents. So care is needed in some situations to make the correct doc the activeDocument in order to access the artboard. E.g., “ogDoc.artboards” ACTUALLY refers to “activeDocument.artboards” (though “ogDoc.layers” refers to “ogDoc.layers”).
So you have to set activeDocument to the dos that has the artboard you need. Simple, but REALLY frustrating for a while.

Bad design: naming a new file

When you create a new document, it starts out without a name. You have to give it a name, or else you will NOT be able to save it. Of course, you cannot just set the document’s name (or else I would not be writing this). Instead, you have to change the path. But you cannot just set the path = name. You have to use this function:

  • newDoc.path.changePath(filename);
  • This is the most important line of code to know for saving a new doc, and it took a long time to find it, since I did not know what exactly to search for. Who would guess that setting a file name is done only by setting the path, and no way else?

    With that out of the way, here is a gem of a Javascript. It will take all top-level layers in one file and copy all items in that top-level layer to another file, and save it as an SVG, PDF, or whatever else you might set up. The beauty of this script is that it preserves the layer structure, the layer names, and repositions according to the copied artboard.

    Please read this first – this code is not generic: This is designed for a document with multiple artboards, all with the size 1100×900, and the position of layer items is aligned to that artboard structure. You have to align your layer items with an artboard, and name your layer with the index number of the artboard to copy. This will be easy enough to change since it is well-documented throughout, but for now this Javascript is non-generic.

    // ==========
    // Create new files based on the top-level layers.
    // ASSUMES: The first two characters of a layer indicate the index of artboard that is supposed to show them.
    // Does not copy or export the layer (or sub-layer) if the layer's name begins with an underscore ("_").
    // ==========
    //alert( activeDocument.artboards.length );
    //alert( activeDocument.layers.length );
    //alert( activeDocument.artboards[ parseInt(activeDocument.layers[24].name.substr(0,2)) ] );
    var newDocDim = [1100, 900];
    var ogDoc = documents[0];
    // ==========
    function saveLayersToFile(ogDoc)
        var ogLys;
        var newDoc;
        var nm;
        var idx;
        // For testing:
        //for(  var i = 1; i >= 0; i--)
        // Cycle through all top-level layers.
        // Each top-level layer will be a new file.
        for(  var i = 0; i = 0; j--)
            // Skip this layer if the layer's name begins with an underscore ("_").
            if( ogLyrs[j].name.substr(0,1) == '_' )
            // Store locked state of the source layer.
            // Note: Copying is allowed from a locked layer, but pasting to a locked layer is not.
            isInitiallyLocked = ogLyrs[j].locked;
            ogLyrs[j].locked = false;
            // Create layer, and copy the layer name.
            curLy = outLyrs.add();
            curLy.zOrderPosition = 0;
            curLy.name = ogLyrs[j].name;
            // Duplicate items on a layer.  Does not duplicate sub-layers, though.
            // As far as I can tell, this will grab all the items within a layer.
            // However, there are a lot of potential things to grab, so I have included
            // the rest of the references I found in Adobe's JS ref PDF below.
            duplicateLayerItems(ogLyrs[j].pageItems, "pageItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].graphItems, "graphItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].groupItems, "groupItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].meshItems, "meshItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].nonNativeItems, "nonNativeItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].pathItems, "pathItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].compoundPathItems, "compoundPathItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].placedItems, "placedItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].pluginItems, "pluginItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].rasterItems, "rasterItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].symbolItems, "symbolItems", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].textFrames, "textFrames", curLy, offsetRect);
            //duplicateLayerItems(ogLyrs[j].legacyTextItems, "legacyTextItems", curLy, offsetRect);
            // RECURSE: Create all sub-layers in the new doc, and copy the items.
            if( ogLyrs[j].layers.length > 0 )
            // restore locked state:
            if( isInitiallyLocked )
                ogLyrs.locked = true;
                curLy.locked = true;
            // For testing:
    // ==========
    function duplicateLayerItems(items, nm, outLy, offsetRect)
        if( items.length == 0 )
            alert (
                //"vals = "
                //+ items[0].left + ","
                //+ items[0].top + ";  "
                //+ offsetRect[0] + ","
                //+ offsetRect[1] + " _ "
                //+ offsetRect[2] + ","
                //+ offsetRect[3]
        var newItem;
        // Copy all items.
        for( var i = items.length - 1; i >= 0 ; i--)
            // duplicate() is the best way to copy an unknown item type, but it is a bit slow.
            newItem = items[i].duplicate(outLy); //, ElementPlacement.PLACEATEND);
            // Reposition the items to the new doc's origin (0,0).
            // This code is a bit of a fake, since I did not have time to work out
            // why the position was offset the new doc's height.
            // This may need tweaking in the future.
            newItem.left = items[i].left - offsetRect[0]; // + newDocDim[0];
            newItem.top = items[i].top - offsetRect[1] + newDocDim[1];
            //alert( "pos = " + newItem.position[0] + ", " + newItem.position[1] );
    // ==========

    – 30 –