Copy link to clipboard
Copied
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
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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 ?)
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Thank you ! But I cannot run the script
Copy link to clipboard
Copied
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/
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Hi @Martin Dedron, sounds like a fun project. 🙂 Is your book going to be made in Illustrator or Indesign?
- Mark
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
Copy link to clipboard
Copied
though it worked one time, for my second path it says rthat there is an error on this line:
w = masterArtboard.artboardRect[2] - masterArtboard.artboardRect[0], h = -(masterArtboard.artboardRect[3] - masterArtboard.artboardRect
Copy link to clipboard
Copied
If you want a picture example on how it doesn't match the artboards:
Copy link to clipboard
Copied
Hi @Martin Dedron, thanks for trying it out. The script doesn't attempt to "fit the content to the artboards"... it (should) match the spacial relationship of the page item to the master artboard. Also when I wrote the script I assumed (haha) that the paths would be completely on the artboard—if they aren't, then it raises more problems such as (a) not being able to get the artboard dimensions in the first place (because item might not be on an artboard at all!) and (b) the final object falling mostly on a wrong artboard due to my layout scheme. To fix this I'll need to put them each in a clipping mask—I can add that.
If you think this might still be a promising approach for you, please send me one or two sample .ai files that currently fail and I'll bounce off those.
Once it's working, I'm imagining a nice setup could be to export the multi-artboard ai document as multi-page pdf and import into indesign like that, but using a little script to match each page to the pages of the indesign doc.
- Mark
Copy link to clipboard
Copied
Hi Mark !
Well as I'm in a rush I went full-on "learning by trying", and I noticed that if all the shapes exactly fit one artboard (which isn't what I thought was obvious: I tried to create a "destination artboard", having the exact size that I wanted to furtherly use), clipping them will be ok.
Then, I put the keyboard increments to a really low number and I place them manually. Some might overlap on two so, a visual check is needed.
Afterwards I datamerged them and it finally went "ok", I just had trouble with Indesign's functionment (I created all my pages but if I fill the main text block, the "intelligent" text distribution just creates a page BEFORE my edited pages, hum).
Now with some energy I nailed everything. Thanks again !
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
Hi @Martin Dedron, here's what I was imagining:
1. I make the blend on an artboard that matches the page size of the document (click to enlarge).
2. I expand and ungroup the blend so there are separate path items selected.
3. I run my script.
For showing the idea I have added a text frame with dummy text:
Copy link to clipboard
Copied
Hi @Martin Dedron, I just noticed that my script posted has a major bug which is almost certainly the reason it wasn't working sensibly for you. I have updated the code above, so if you need it again, give it a try. Sorry about that. Bugs often occur only in certain situations and that was the case here.
- Mark
Copy link to clipboard
Copied
Thank you 🙂
I haven't had the time to try it yet, but because of my way of thinking, I totally didn't think about doing it that way.
Indeed, I thought : "If I have four shapes but two are the symetry of the two other ones, therefore I have two shapes".
See linked file.
Henceforth I scaled my artboard size regarding the container in which they were supposed to fit. Having four on the same page, I also didn't (and still don't) know if it would work well with 4*100 steps (or more).
The main issue I had wasn't to refit them on the artboard (it's fastidious but I've done way worse), it is that
1. they slightly move inside of the artboard. It could be awesome to set a reference point in the "filet", the line. Indeed, the wave shape makes it move as the "middle" changes position ;
2. InDesign has a "what the hell!" way of using its datamerge !! Grrr. If you prepare your book with a main text block, pages number, etc. And datamerge those shapes inside of it, the automatic text fill won't fill the pages that were created with the right shapes : it will add pages BEFORE them. What a pleasure. Therefore you have either to copy and paste the shapes page after page (which I think is longer), or to chain the text blocks manually (which is ok for a hundred pages, but I wouldn't do it for a whole collection).
I will try to run the script again in a few days, thanks for the correction! If you have any idea regarding what could make the datamerge + positionning of those shapes more accurate and easy to use, please feel free to let me know.
Martin Dedron
Copy link to clipboard
Copied
Note to readers: my post here is now about Indesign not Illustrator.
Okay @Martin Dedron your example page helps. It's an interesting exercise. I'm assuming that your document uses facing pages (if not, the solution is just slightly different than what I am about to post).
I've written a script for Indesign that will import a multiple page pdf with one page of pdf per page of indesign document, with the option of duplicating and/or flipping the same page to the right-hand-page. To make the pdf ready to import into indesign, follow my instructions I posted earlier in Illustrator, using my script, specifically making sure the blended items are on artboards that match the indesign document page size and in the correct positions on the artboards.
Then save that output .ai document as .pdf (all artboards). Then open or make a document with correct dimensions and number of pages and run script below "Place Multipage PDF On Multiple Pages.js". Script will ask for pdf file so select the one you just saved from Illustrator.
To see it working, see the demo sample files attached.
- Mark
/*
Place Multipage PDF on Multiple Pages.js
for Adobe Indesign
by m1b
discussion here: https://community.adobe.com/t5/illustrator-discussions/export-separately-every-step-of-the-blend-tool/m-p/12978097
Imports a multi-page pdf into indesign, putting
one page of pdf on each page of indesign document
aligning at top left corner. (Ideal for when pdf
dimensions match indesign document dimensions.)
*/
var settings = {
// the image file to place (assumes is multiple pages pdf)
// leave undefined for user to choose pdf
// imageFile: new File('/Users/foobar/Desktop/blend-split-output.pdf'),
// layer name on which to place
// leave undefined to use active layer
// layerName: 'blend',
// place first page of image on page with this documentOffset
// 0 is first page in document
startDocumentOffset: 0,
// will place the same image on the facing page
repeatToFacingPage: true,
// will place the same image on the facing page flipped horizontally
flipOnRightHandPage: true,
};
function main() {
if (settings.imageFile == undefined) {
settings.imageFile = chooseFile('pdf');
if (settings.imageFile == undefined)
return;
}
var doc = app.activeDocument,
documentOffset = settings.startDocumentOffset,
firstImagePageNumber = 1,
imageFile = settings.imageFile;
if (!imageFile.exists) {
alert('File "' + imageFile + '" doesn\'t exist.');
return;
};
var targetLayer;
if (settings.layerName != undefined) {
targetLayer = doc.layers.itemByName(settings.layerName)
if (!targetLayer.isValid)
targetLayer = undefined;
}
// Explr.init(app.pdfPlacePreferences); return;
app.pdfPlacePreferences.pdfCrop = PDFCrop.CROP_MEDIA;
var finishedPlacingEveryPage = false,
docPageCounter = 0,
imagePageCounter = 0;
while (!finishedPlacingEveryPage) {
var page = doc.pages[documentOffset + docPageCounter];
app.pdfPlacePreferences.pageNumber = firstImagePageNumber + imagePageCounter;
if (!page.isValid)
break;
var placedImage = page.place(/* file */ imageFile, /* placePoint */[0, 0], /* destinationLayer */ targetLayer, /* showingOptions */ false, /* autoflowing */ false)[0];
if (
imagePageCounter > 0
&& placedImage.pdfAttributes.pageNumber == firstImagePageNumber
) {
placedImage.parent.remove();
finishedPlacingEveryPage = true;
continue;
};
// repeat to right hand page?
if (
settings.repeatToFacingPage == true
&& page.side == PageSideOptions.LEFT_HAND
) {
var facingPage = doc.pages[documentOffset + docPageCounter + 1];
if (facingPage.isValid) {
var repeatImage = placedImage.duplicate(facingPage);
docPageCounter++;
if (settings.flipOnRightHandPage == true)
repeatImage.flipItem(Flip.HORIZONTAL, AnchorPoint.CENTER_ANCHOR);
}
}
// flip image if necessary on right hand page
else if (
page.side == PageSideOptions.RIGHT_HAND
&& settings.flipOnRightHandPage == true
) {
placedImage.flipItem(Flip.HORIZONTAL, AnchorPoint.CENTER_ANCHOR);
}
docPageCounter++;
imagePageCounter++;
};
} // end main
function chooseFile(fileExtension) {
fileExtension == fileExtension || 'txt';
fileExtension = fileExtension.replace('.', '');
var f, fsFilter;
if ($.os.match("Windows")) {
fsFilter = "*." + fileExtension;
} else {
var regex = RegExp('\.' + fileExtension, 'i');
fsFilter = function (f) { return (regex.test(f.name) || f.constructor.name == 'Folder') };
};
f = File.openDialog("Please select a '" + fileExtension + "' File", fsFilter, false);
if (f != undefined && f.exists) return f;
}
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Place Multipage PDF');
P.S. Something that can make it hard to align graphics in indesign is when they aren't using the artboard for cropping. When importing a graphic to Indesign, click "Show options" in the Place dialog and change the bounding box to, for example, Trim or Bleed. This will respect the artboard sizes in the pdf and make positioning easy. The script does this, but you can do it anytime you are importing a graphic.