Copy link to clipboard
Copied
I'm trying to create individualized business cards with an individual's name and membership number on each card. I have a template with 40 cards on it and want to import a csv file so that I auto-populate the name and membership number on each of the 40 cards. I have managed to import a csv file and used the variables window to assign text to an object. The only problem is that it only populates the first data set from the csv so all 40 cards have the same name/ID. How do I populate so that a new data set goes into each card on my template?
Thanks for any help!
Copy link to clipboard
Copied
That is not how variables work.
You make one template, assign the variables to the data and then all the cards get generated in a batch export.
Copy link to clipboard
Copied
Why do you want to put 40 different cards in one file? Who’s asking for that? What does your print provider require? Are they asking for 40 different designs on one artboard, or 40 different designs in one PDF file, or something else?
As Monica says, Illustrator’s Data Merge feature is designed to generate 40 different artwork files, one file for each CSV row. The rest is an imposition problem.
Copy link to clipboard
Copied
I am printing on a Roland LEF300. I have a physical jig that holds 40 cards and so I want to print 40 cards at a time and not one at a time..... I have almost 300 to print.
This client wants ID cards for every member of their company and each one has to have its own name and ID number.
I have found a video that helps although it's not the ideal solution. https://www.youtube.com/watch?v=50WQPxTlVL0
In this way I can create a picture file for each card and then I have to reimport 40 at a time to fit into my digital 'jig'
Copy link to clipboard
Copied
Then you have to take 2 steps: one for the creation of PDFs with a batch and then another one prnting those PDFs. Of use InDesigns Datamerge
Copy link to clipboard
Copied
Like others have said, this would probably be easiest to achieve via Indesign Data Merge via a multi record merge. unless there is some reason illustrator has to be used that is not being shared.
set up the file dimensions to hold your 40 cards.
do the multi-record merge option to flood the file and generate all 300 some at once. should take minimal time to set up.
Copy link to clipboard
Copied
ID cards. Not business cards. That makes more sense.
Yeah, AI’s Data Merge is very limited. For any flexibility you need to use scripting.
Here’s a rudimentary script that takes an .ai document containing multiple named groups and inserts a line of CSV data into each. It uses the Layers palette (not the Variables palette) to name and number templated items. I have attached sample CSV and AI files that show how to set them up.
Save it as “render cards.jsx”, choose File > Scripts > Other Script and select the script, and pick a CSV file when prompted. All going well, it will populate N template objects with the first N rows of the CSV. (If your AI document has 40 templates and your CSV has 300 rows, you’ll need to delete the first 40 rows after each run.)
/******************************************************************************/
// render cards.jsx
// Render CSV rows into multiple templates in a single document.
// The template document must be frontmost in Illustrator before running the script.
// Each template is a *group* of text frames and other items.
// These groups must be named in the Layers palette as "card 1", "card 2", "card 3, etc".
//
// Text frames containing text to be replaced must be named in the Layers palette.
// A text frame's name must exactly match a CSV column name. Unnamed/Unrecognized text frames are ignored.
//
// The script could be expanded to relink images, set colors, remove empty elements, etc. This is left as an exercise.
// This code is released into the Public Domain.
(function() {
var TEMPLATE_PREFIX = "card ";
/******************************************************************************/
// helper functions
function readFile(f) {
f.encoding = 'utf-8';
if (!f.open('r')) { throw new Error("Can't open file: " + f.fullName); }
var s;
try {
s = f.read();
} catch (e) {
f.close();
throw e;
}
f.close();
return s;
}
function writeFile(f, s, isAppend) {
f.encoding = 'utf-8';
f.lineFeed = 'Windows';
if (!f.open(isAppend ? 'a' : 'w')) { throw new Error("Can't open file: " + f.fullName); }
var s;
try {
if (!isAppend) { f.write('\uFEFF'); }
f.write(s);
} catch (e) {
f.close();
throw e;
}
f.close();
}
/******************************************************************************/
// parse CSV file data
function parseCSVLine(data, headings) {
// Parses one line of CSV data, returning it and the remaining data
// data : string -- the CSV data
// headings : [string] | undefined -- undefined when reading first (headings) line
// Result: {fields: {string} | [string] | null, data: string} --the line's fields plus any remaining lines of CSV data
//
// Notes: On return, fields is an object if headings array is given (headings are used as object keys), or an array of fields if no headings are provided. The number of headings must match the number of CSV fields, otherwise an error is thrown.
var col = 0, eol = false; fields = headings ? {} : [];
var isEmpty = true;
while (!eol) { // find next comma or double quote, or end of line
var value = '', done = false, m = data.match(/[",]|[\r\n]+/);
switch ((m || '')[0]) {
case ',':
value = data.slice(0, m.index);
data = data.slice(m.index + 1); // step over text + comma
break;
case '"': // quoted field
data = data.slice(1); // discard opening quote
while (!done && data) {
m = data.match(/"/);
// note: quoted values can include line breaks so all we can do is read to next double-quote character
if (!m) { throw new Error("Missing double-quote at end of CSV column " + col + "."); }
var index = m.index;
value += data.slice(0, index);
if (data[index + 1] === '"') { // is the double quote followed by a second double quote (escape sequence)?
value += '"'; // replace the 2 double quotes with 1
index++;
} else { // it's a single double-quote, which ends the quoted value
done = true;
}
data = data.slice(index + 1); // step over quote(s)
}
if (data[0] === ',') {
data = data.slice(1); // step over trailing comma
} else {
data = data.replace(/^[\r\n]+/, ''); // strip trailing linebreak[s]
eol = true;
}
break;
default: // CR/LF = found end of line/end of file; last value is anything up to it
if (m) {
value = data.slice(0, m.index);
data = data.slice(m.index + m[0].length); // step over text and comma
} else {
value = data;
data = '';
}
eol = true;
}
if (headings) { // values is object with heading strings as keys
var heading = headings[col];
if (heading === undefined) {
throw new Error("Mismatched CSV columns. (Did you choose the right CSV file?) Expected " + headings.length
+ " columns but found a value in column " + col + ": '" + value + "'");
}
fields[heading] = value;
} else { // values is Array of heading strings
fields.push(value);
}
if (value) { isEmpty = false; }
col++;
if (col > 1000) { throw new Error("Too many CSV columns. (Did you choose the right CSV file?)"); }
}
if (headings && col !== headings.length) {
throw new Error("Mismatched CSV columns. (Did you choose the right CSV file?) Expected " + headings.length
+ " columns but found " + col + ".");
}
return {values: isEmpty ? null : fields, remainingData: data};
}
function parseCSVFile(csvFile) {
// Parse a UTF8-encoded .csv file. The first line must contain column headings.
// csvFile : File
// Result: [{field1:value1,...}]
var data = readFile(csvFile);
var result = parseCSVLine(data);
var remainingData = result.remainingData;
var headings = result.values;
var rows = [];
while (remainingData) {
var result = parseCSVLine(remainingData, headings);
var row = result.values;
if (row) { rows.push(row); } // ignore empty rows
remainingData = result.remainingData;
}
return rows;
}
/******************************************************************************/
function renderGroup(group, values) {
for (var i = 0; i < group.pageItems.length; i++) {
var item = group.pageItems[i];
var value = item.name ? values[item.name] : undefined;
switch (item.typename) {
case 'TextFrame':
if (value !== undefined) {
item.contents = value; // insert text into text frame
}
break;
case 'PlacedItem':
if (value !== undefined) {
// linking to a named image file is left as an exercise
}
break;
case 'GroupItem':
renderGroup(item, values);
break;
}
}
}
function renderCards(csvFile) {
if (!csvFile) { return; }
var doc = app.activeDocument;
var data = parseCSVFile(csvFile);
var templates = doc.layers[0].groupItems;
for (var i = 0; i < templates.length; i++) {
//var template = templates[i]; // iterate templates by stacking order
var template = templates.getByName(TEMPLATE_PREFIX + (i + 1)); // or by name, e.g. "card 1", "card 2",...
var values = data[i];
if (!template || !values) { break; }
renderGroup(template, values);
}
}
renderCards(File.openDialog("Please choose a .csv file:"));
})();
Copy link to clipboard
Copied
If you are printing this yourself, and intend to do this a lot, the better tool is to use InDesign as it has the ability to do multiple records on one sheet. You could still create your main design in Illustrator (i.e. one base blank), and place that 40-up on a parent page in ID, then layer your text variables on top of it, and data merge as many 40-up sheets as your require.
However, If all you have is Illustrator, then, yes, as mentioned by @Monika Gause, you only need one template and then export all the cards; You could still create a document where you PLACE all these individual PDFs onto a 40-up page for you to print... definitely not automatic, but less work than without the variable merge.
Copy link to clipboard
Copied
Thank you all for the advice. The main reason for using illustrator is that I know this program fairly well and I've never touched ID. The learning curve to do all this sounds a little daunting! It has to go back into illustrator in the end to get set up correctly for the RIP software so I think I'm just going to do 40 at a time!