Skip to main content
Martin Dedron
Inspiring
May 21, 2022
Answered

Export separately every step of the blend tool

  • May 21, 2022
  • 3 replies
  • 3654 views

Good afternoon,

 

I want to export SEPARATELY every step of a blend between two shapes and then apply them to different pages of a book.

The request is pretty simple: I want to have one straight line evolving in a subtle way to a wavy line. To do so, I have my starting path and my arrival path. I can use the blend tool to create as many steps as I need (matching the number of pages of the book).

 

However, if I want to export, I would have to select one by one each one of those paths to then "export selection". Which is a huge lot of clicking and clicking while I am sure there is a script to fit each of those objects into a different artboard.

I am looking for such a script, that would save me a lot of time.

 

Then I will have the question on how to datamerge into an existing document that includes a main text block, but I think the biggest issue is about the Illustrator export being fastidious. 

 

Any help is welcomed.

Thank you, 

Martin Dedron

This topic has been closed for replies.
Correct answer Martin Dedron

I thought Monika mentioned a script, but it was a plug-in.

This script should work exporting to PDF (just make sure that your PDF export does not open Acrobat).

http://www.ericson.net/content/2011/06/export-illustrator-layers-andor-artboards-as-pngs-and-pdfs/


Thank you ! 

I went with @m1b 's method and, with a bit of a struggle, managed to obtain what I wanted. But I will look at that for sure.

3 replies

m1b
Community Expert
Community Expert
May 21, 2022

Hi @Martin Dedron, sounds like a fun project. 🙂 Is your book going to be made in Illustrator or Indesign?

- Mark

m1b
Community Expert
Community Expert
May 22, 2022

Hi @Martin Dedron, I had an idea for a script that might really help your project.

 

To use it, first start with a blend and expand it then ungroup it and keep all the paths selected. Then run my script. It will create a new illustrator document, then create new artboards that match the size of the artboard in the original document, and then duplicate each selected page item to the new document, positioned on the corresponding artboard.

- Mark

 

Here's the script—everything really happens in the first function and the rest of the functions are just little utility functions that make things convenient.

 

/*
    Duplicate Items To New Doc Artboards.js
    for Adobe Illustrator 2022

    by m1b
    here: https://community.adobe.com/t5/illustrator-discussions/export-separately-every-step-of-the-blend-tool/m-p/12956749

*/


duplicateItemsToNewDocArtboards(app.activeDocument.selection, 10, -1);


/**
 * duplicateItemsToNewDocArtboards
 * creates a new document and then
 * duplicates each item to a new
 * artboard on that document
 * @param {Array[PageItem]} items - the page items to duplicate
 * @param {[Number]} gap - spacing in points between artboards
 */
function duplicateItemsToNewDocArtboards(items, gap, direction) {
    if (items == undefined)
        return;

    gap = gap || 0;
    direction = direction || 1;

    var masterArtboard = getArtboardsOfItem(items[0])[0];

    if (masterArtboard == undefined)
        masterArtboard = getParentDocument(items[0]).artboards[0];

    var newArtboards = [],
        sideLength = Math.ceil(Math.sqrt(items.length)),
        w = masterArtboard.artboardRect[2] - masterArtboard.artboardRect[0],
        h = -(masterArtboard.artboardRect[3] - masterArtboard.artboardRect[1]),
        tx = masterArtboard.artboardRect[0],
        ty = masterArtboard.artboardRect[1],
        dx = (w + gap) * sideLength / 2,
        dy = (h + gap) * sideLength / 2,
        newDoc = app.documents.add();

    if (direction == -1) {
        reversedItems = [];
        for (var i = items.length - 1; i >= 0; i--)
            reversedItems.push(items[i]);
        items = reversedItems;
    }

    for (var i = 0; i < items.length; i++) {
        var x = i % sideLength,
            y = Math.floor(i / sideLength),
            xpos = (w + gap) * x - dx,
            ypos = (h + gap) * y - dy;

        newArtboards[i] = newDoc.artboards.add([xpos, -ypos, xpos + w, -(ypos + h)]);

        var dup = items[i].duplicate(newDoc, ElementPlacement.PLACEATBEGINNING);
        dup.position = [items[i].left + xpos - tx, items[i].top - ypos - ty];
    }
    newDoc.artboards[0].remove();
}



/**
 * getArtboardsOfItem
 * returns array of artboards that intersect the item
 * @param {PageItem} item - a page item
 * @param {[Array[Artboard]]} _artboards - artboards to search, if undefined, search all
 * @param {[Boolean]} preferIndex - if true, returns array of artboard indices {Array[Number]}
 * @returns {Array[Artboard]} - array of artboards
 */
function getArtboardsOfItem(item, _artboards, preferIndex) {
    var doc = getParentDocument(item);
    _artboards = _artboards || doc.artboards;
    var bounds = getItemBounds(item);
    var result = [];
    for (var i = 0; i < _artboards.length; i++) {
        if (boundsDoIntersect(bounds, _artboards[i].artboardRect))
            result.push(preferIndex
                ? i
                : _artboards[i]
            );
    }
    return result
}



/**
 * getItemBounds
 * attempts to calculate items bounds
 * including correct bounds of clipped group
 * @param {PageItem} item - a page item
 * @param {Boolean} geometric - false = visibleBounds, true = geometricBounds
 * @param {Array[4]} bounds - [l,t,r,b]
 */
function getItemBounds(item, geometric, bounds) {
    if (item == undefined) return;
    var newBounds = [];
    if (item.typename == 'GroupItem') {

        var children = item.pageItems,
            contentBounds = [];
        if (item.hasOwnProperty('clipped') && item.clipped == true) {
            // item is clipping group
            var clipBounds;
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                if (child.hasOwnProperty('clipping') && child.clipping == true) {
                    // the clipping item
                    clipBounds = child.geometricBounds;
                } else {
                    // a clipped content item
                    var b = expandBounds(getItemBounds(child, geometric, bounds), contentBounds);
                }
            }
            if (clipBounds != undefined)
                newBounds = intersectionOfBounds([clipBounds, contentBounds]);
            else
                newBounds = contentBounds;
        }

        else {
            // item is a normal group
            for (var i = 0; i < children.length; i++) {
                var b = expandBounds(getItemBounds(children[i], geometric, bounds), contentBounds);
            }
            newBounds = contentBounds;
        }
    } else {
        // item is not clipping group
        newBounds = geometric ? item.geometricBounds : item.visibleBounds;
    }
    if (bounds == undefined) {
        bounds = newBounds;
    } else {
        bounds = expandBounds(newBounds, bounds);
    }
    return bounds;
}



/**
 * expandBounds
 * returns bounds that encompass two bounds
 * @param {Array[4]} b1 - bounds [l,t,r,b]
 * @param {Array[4]} b2 - bounds [l,t,r,b]
 * @returns {Array[4]} [l,t,b,r]
 */
function expandBounds(b1, b2) {
    var expanded = b2;
    for (var i = 0; i < 4; i++) {
        if (b1[i] != undefined && b2[i] == undefined) expanded[i] = b1[i];
        if (b1[i] == undefined && b2[i] != undefined) expanded[i] = b2[i];
        if (b1[i] == undefined && b2[i] == undefined) return;
    }
    if (b1[0] < b2[0]) expanded[0] = b1[0];
    if (b1[1] > b2[1]) expanded[1] = b1[1];
    if (b1[2] > b2[2]) expanded[2] = b1[2];
    if (b1[3] < b2[3]) expanded[3] = b1[3];
    return expanded;
}


/**
 * intersectionOfBounds
 * calculates intersecting rectangle
 * @param {Array[Array[4]]} arrayOfBounds - array of [l,t,b,r] arrays
 * @returns {Array[4]} [l,t,b,r]
 */
function intersectionOfBounds(arrayOfBounds) {
    bounds = arrayOfBounds.slice(0).sort(function (a, b) { return b[0] - a[0] || a[1] - b[1] });
    var intersection = bounds.shift();
    while (b = bounds.shift()) {
        if (!boundsDoIntersect(intersection, b)) return;
        var l = Math.max(intersection[0], b[0]),
            t = Math.min(intersection[1], b[1]),
            r = Math.min(intersection[2], b[2]),
            b = Math.max(intersection[3], b[3]);
        intersection = [l, t, r, b];
    }
    return intersection;
}

/**
 * boundsDoIntersect
 * returns true when bounds intersect
 * @param {Array[4]} b1 - bounds [l,t,r,b]
 * @param {Array[4]} b2 - bounds [l,t,r,b]
 * @returns {boolean}
 */
function boundsDoIntersect(b1, b2) {
    return !(
        b2[0] > b1[2] ||
        b2[2] < b1[0] ||
        b2[1] < b1[3] ||
        b2[3] > b1[1]
    );
}


/**
 * getParentDocument
 * @param {PageItem} obj - a page item
 * @returns {Document} the page item's document
 */
function getParentDocument(obj) {
    while (obj.hasOwnProperty('parent') && obj.constructor.name != 'Document')
        obj = obj.parent;
    return obj;
}

 

EDIT: fixed positioning bug and removed error when first item isn't on any artboard.

Martin Dedron
Inspiring
May 26, 2022

That's awesome @Martin Dedron good to hear you got it done. I'm not sure I follow your solution perfectly but it sounds epic. 🙂

 

For next time learning... there's a feature of my conception of your problem and my solution that I didn't make clear earlier—that it avoids any manual positioning in the final files. It can do this by: 1. making the master artboard  have a sensible relationship with page size, eg. the same size, and 2. page items will be in the correct position on the master artboard such that they will be in the correct position on the final page. This means that the blended items must be stacked, not spread out (unless they should be spread out on the final pages!). If those 2 conditions are met, when they are datamerged or imported they will be in the correct position already. Also this would be a great time to add an Object Style to the frames in Indesign so that the position can be changed for all of the "frames" at once by editing the Object Style.

- Mark


Thank you.

I'm not sure I understand to be true:

1. I tried the master artboard having a. the same size as the shape to be exported ; b. the master artboard having the same size as the whole compound shape ; none of them resulted in these being placed automatically.

2. What do you mean by stacked and spread out ? On Illustrator I decomposed then ungrouped the object. I'm not sure what you mean.

 

Have a good day,

Martin

Ton Frederiks
Community Expert
Community Expert
May 21, 2022

As Monika said you can make layers from the blend.

Expand the blend, ungroup and use Release to Layers (Sequence)

They will become sublayers. Select all the sublayers and drag them above the main layer.

Delete the main layer and use the script.

Martin Dedron
Inspiring
May 23, 2022

Thank you ! But I cannot run the script

Ton Frederiks
Community Expert
Community Expert
May 23, 2022

I thought Monika mentioned a script, but it was a plug-in.

This script should work exporting to PDF (just make sure that your PDF export does not open Acrobat).

http://www.ericson.net/content/2011/06/export-illustrator-layers-andor-artboards-as-pngs-and-pdfs/

Monika Gause
Community Expert
Community Expert
May 21, 2022

There is a script to export layers. You could use the Make layers function in the layers panel menu to get layers for objects.

Or you could use the Export for screens feature (but then you would need a reference object to get the size and position in the layout correctly.

 

https://github.com/TomByrne/IllustratorSmartExport

Martin Dedron
Inspiring
May 23, 2022

Thank you ! I cannot install the script (it says to use a ZXP file but there is none in the content, maybe it's because it's written in the readme that it won't be updated anymore ?)