Copy link to clipboard
Copied
Hi, I was just wondering if it's possible to export all of the images in an AI symbol Library into individual artboards or files. I have a symbol library with a couple of hundred icons in it, and I was these as individual artboards or files.
Thanks.
Leah.
Copy link to clipboard
Copied
Looks like a task for a script. Maybe the scripting gods here have ideas.
Copy link to clipboard
Copied
Artboards are limited to 100 per document and one would be loathe to creating hundreds of files. So the script will distribute the symbol items, each on its artboard, across separate documents, 100 per document.
The symbols library file should be somewhere like
C:\Program Files (x86)\Adobe\Adobe Illustrator CS6\Presets\en_GB\Symbols
var file1 = File.openDialog("Open Symbol Library File");
app.open(file1);
var doc1 = app.documents[file1.displayName];
var y = 0, x = 0, row = 1;
function createSymbolItems() {
for (var i = 0; i < doc1.symbols.length; i++) {
symbolItem1 = doc1.symbolItems.add(doc1.symbols[i]);
symbolItem1.left = x, symbolItem1.top = y;
symbolItem1.width = 50, symbolItem1.height = 50;
if (i < (10 * row) - 1) {
x += 50;
} else {
x = 0;
y -= 50;
row++;
}
}
}
createSymbolItems();
var start = doc1.symbolItems.length - 1;
function distribute(i) {
doc1.activate();
app.selection = null;
for (var j = i - 100; i > (j > -1 ? j : -1); i--){
doc1.symbolItems[i].selected = true;
}
app.copy();
var doc2 = app.documents.add();
app.paste();
for (var k = 0; k < doc2.symbolItems.length; k++){
if (k == 1) {
doc2.artboards[0].remove();
}
doc2.artboards.add(doc2.symbolItems[k].visibleBounds);
}
start = start - 100;
if (start > 0) {
distribute(start);
}
}
distribute(start);
doc1.close(SaveOptions.DONOTSAVECHANGES);
Copy link to clipboard
Copied
so nice! here the latest version with some nice updates 😉
added little options:
- for scaling (sadly just for plain paths)
- to have a bit margins between the artboards
- named artboards after symbolnames with number indicator infront (for easy export with nice names ;))
// Initialize variables
var doc1 = null;
// Conversion functions - 1:1 since Illustrator uses 72ppi where 1pt = 1px
function pxToPt(px) { return px; }
function ptToPx(pt) { return pt; }
// Check if any document is open
if (app.documents.length > 0) {
doc1 = app.activeDocument;
}
// Create dialog window
var dialog = new Window("dialog", "Symbol Export Settings");
dialog.orientation = "column";
// Add file selection group
var fileGroup = dialog.add("panel", undefined, "Source File");
fileGroup.orientation = "column";
fileGroup.alignChildren = "left";
var useCurrentRb = fileGroup.add("radiobutton", undefined, "Use Current Document");
var chooseFileRb = fileGroup.add("radiobutton", undefined, "Choose AI File");
// Set initial state based on document availability
if (doc1 === null) {
useCurrentRb.enabled = false;
chooseFileRb.value = true;
} else {
useCurrentRb.value = true;
useCurrentRb.enabled = true;
}
var chooseGroup = fileGroup.add("group");
var filePathText = chooseGroup.add("edittext", undefined, "");
filePathText.preferredSize.width = 200;
var chooseBtn = chooseGroup.add("button", undefined, "Browse...");
// Set initial state of file selection controls
filePathText.enabled = (doc1 === null);
chooseBtn.enabled = (doc1 === null);
// Enable/disable file selection based on radio button
chooseFileRb.onClick = function() {
filePathText.enabled = chooseFileRb.value;
chooseBtn.enabled = chooseFileRb.value;
}
useCurrentRb.onClick = function() {
filePathText.enabled = false;
chooseBtn.enabled = false;
}
// Browse button functionality
chooseBtn.onClick = function() {
var file = File.openDialog("Select Illustrator File", "*.ai");
if (file) {
filePathText.text = file.fsName;
// Open file and update symbol list
try {
var tempDoc = app.open(file);
updateSymbolList(tempDoc);
tempDoc.close(SaveOptions.DONOTSAVECHANGES);
} catch(e) {
alert("Could not open file: " + e);
}
}
}
// Add symbol size input (now in pixels)
var sizeGroup = dialog.add("group");
sizeGroup.add("statictext", undefined, "Symbol Size (px):");
var symbolSizeInput = sizeGroup.add("edittext", undefined, "64"); // Default 64px instead of 50pt
symbolSizeInput.characters = 6;
var explainScale = dialog.add("group");
explainScale.add("statictext", undefined, "(!!! needs plain Paths, NO STROCK or EFFECT SCALEING !!!");
// Add margin input (now in pixels)
var marginGroup = dialog.add("group");
marginGroup.add("statictext", undefined, "Margin (px):");
var marginInput = marginGroup.add("edittext", undefined, "24"); // Default 24px instead of 20pt
marginInput.characters = 6;
// Add symbol selection list
var listGroup = dialog.add("group");
listGroup.orientation = "column";
listGroup.alignChildren = "fill";
listGroup.add("statictext", undefined, "Select Symbols to Export:");
// Create selection list
var symbolList = listGroup.add("listbox", undefined, [], {multiselect: true});
symbolList.preferredSize.width = 300;
symbolList.preferredSize.height = 200;
// Function to populate symbol list
function updateSymbolList(sourceDoc) {
symbolList.removeAll(); // Clear existing items
for (var i = 0; i < sourceDoc.symbols.length; i++) {
var item = symbolList.add("item", sourceDoc.symbols[i].name);
item.selected = true;
}
}
// Initialize list with current document symbols only if we have one
if (doc1 !== null) {
updateSymbolList(doc1);
}
// Add Select All/None buttons
var selectGroup = dialog.add("group");
var selectAll = selectGroup.add("button", undefined, "Select All");
var selectNone = selectGroup.add("button", undefined, "Select None");
selectAll.onClick = function() {
for (var i = 0; i < symbolList.items.length; i++) {
symbolList.items[i].selected = true;
}
}
selectNone.onClick = function() {
for (var i = 0; i < symbolList.items.length; i++) {
symbolList.items[i].selected = false;
}
}
// Add buttons
var buttons = dialog.add("group");
buttons.add("button", undefined, "OK");
buttons.add("button", undefined, "Cancel");
// Show dialog
if (dialog.show() == 1) { // OK was pressed
// Get the source document
var doc1;
if (chooseFileRb.value) {
if (filePathText.text) {
try {
doc1 = app.open(File(filePathText.text));
} catch(e) {
alert("Could not open file: " + e);
exit();
}
} else {
alert("Please select a file first!");
exit();
}
} else {
doc1 = app.activeDocument;
}
// Convert pixel values to points for Illustrator
var symbolSize = pxToPt(Number(symbolSizeInput.text));
var margin = pxToPt(Number(marginInput.text));
// Get selected symbols
var selectedSymbols = [];
for (var i = 0; i < symbolList.items.length; i++) {
if (symbolList.items[i].selected) {
selectedSymbols.push(doc1.symbols[i]);
}
}
// Layout only selected symbols (using point values internally)
var x = 0, y = 0, row = 1;
for (var i = 0; i < selectedSymbols.length; i++) {
symbolItem1 = doc1.symbolItems.add(selectedSymbols[i]);
// Get original dimensions
var originalBounds = symbolItem1.geometricBounds;
var originalWidth = originalBounds[2] - originalBounds[0];
var originalHeight = originalBounds[1] - originalBounds[3];
// Calculate scale percentage
var scalePercentage = (symbolSize / Math.max(originalWidth, originalHeight)) * 100;
// Position first, then scale
symbolItem1.left = x;
symbolItem1.top = y;
// Scale with stroke preservation
symbolItem1.selected = true;
app.executeMenuCommand('expandStyle'); // Expand appearance first
app.executeMenuCommand('expandStyle'); // Sometimes needs two passes
// Scale the expanded item
symbolItem1.resize(
scalePercentage, // x percentage
scalePercentage, // y percentage
true, // transform patterns
true, // transform gradients
true, // transform stroke patterns
true // transform linewidths
);
if (i < (10 * row) - 1) {
x += symbolSize + margin;
} else {
x = 0;
y -= symbolSize + margin;
row++;
}
}
// Copy to new document
app.copy();
// Create new document with same settings as source
var preset = new DocumentPreset();
preset.colorMode = doc1.documentColorSpace;
preset.units = doc1.rulerUnits;
preset.width = 800;
preset.height = 600;
var doc2 = app.documents.addDocument(doc1.documentColorSpace, preset);
// Remove default swatches and symbols (if any)
while(doc2.symbols.length > 0) {
doc2.symbols[0].remove();
}
app.paste();
// Create artboards from symbols and match names
for (var k = 0; k < doc2.symbolItems.length; k++){
var currentSymbolItem = doc2.symbolItems[k];
// Find matching symbol from selected symbols by comparing names
var matchingSymbol = null;
for (var s = 0; s < selectedSymbols.length; s++) {
if (currentSymbolItem.symbol.name === selectedSymbols[s].name) {
matchingSymbol = selectedSymbols[s];
break;
}
}
var newArtboard = doc2.artboards.add(currentSymbolItem.visibleBounds);
if (matchingSymbol) {
newArtboard.name = (k + 1) + "_" + matchingSymbol.name;
} else {
newArtboard.name = (k + 1) + "_unknown";
}
}
doc2.artboards[0].remove()
if (chooseFileRb.value) {
doc1.close(SaveOptions.DONOTSAVECHANGES);
}
} else {
// User cancelled
alert("Export cancelled");
}
Copy link to clipboard
Copied
Femke,
just a hint: In more recent versions of Illustrator one can have up to 1000 artboards per document.
Copy link to clipboard
Copied
@Kurt Gold Thanks. That should make the script straightforward. (I cannot test it though.)
var file1 = File.openDialog("Open Symbol Library File");
app.open(file1);
var doc1 = app.documents[file1.displayName];
var y = 0, x = 0, row = 1;
for (var i = 0; i < doc1.symbols.length; i++) {
symbolItem1 = doc1.symbolItems.add(doc1.symbols[i]);
symbolItem1.left = x, symbolItem1.top = y;
symbolItem1.width = 50, symbolItem1.height = 50;
symbolItem1.selected = true;
if (i < (10 * row) - 1) {
x += 50;
} else {
x = 0;
y -= 50;
row++;
}
}
app.copy();
var doc2 = app.documents.add();
app.paste();
for (var k = 0; k < doc2.symbolItems.length; k++){
doc2.artboards.add(doc2.symbolItems[k].visibleBounds);
}
doc2.artboards[0].remove();
doc1.close(SaveOptions.DONOTSAVECHANGES);
Copy link to clipboard
Copied
Femke, I think both of your approaches will have to be slightly modified in order to use them in the latest (German) version of Illustrator.
After opening the .ai file that contains the symbols, both scripts quit running with an alert (Error 21: undefined is no object). It is referring to line 6 (first approach) and line 5 (second approach):
-> for (var i = 0; i < doc1.symbols.length; i++) {
Copy link to clipboard
Copied
Hmm. It's an innocuous line, so I presume that the problem is with reading the file's name. What about changing line 3 to
var doc1 = app.activeDocument;
So the script will look like
var file1 = File.openDialog("Open Symbol Library File");
app.open(file1);
var doc1 = app.activeDocument;
var y = 0, x = 0, row = 1;
for (var i = 0; i < doc1.symbols.length; i++) {
symbolItem1 = doc1.symbolItems.add(doc1.symbols[i]);
symbolItem1.left = x, symbolItem1.top = y;
symbolItem1.width = 50, symbolItem1.height = 50;
symbolItem1.selected = true;
if (i < (10 * row) - 1) {
x += 50;
} else {
x = 0;
y -= 50;
row++;
}
}
app.copy();
var doc2 = app.documents.add();
app.paste();
for (var k = 0; k < doc2.symbolItems.length; k++){
doc2.artboards.add(doc2.symbolItems[k].visibleBounds);
}
doc2.artboards[0].remove();
doc1.close(SaveOptions.DONOTSAVECHANGES);
Copy link to clipboard
Copied
very good! thanks!
Copy link to clipboard
Copied
thank u @femkeblanco! very good starting point. i did some more extras so size and padding also documentinput and the items that should be processed can be choosen when script is loaded. also i made sure no color-conversion happens.
// Initialize variables
var doc1 = null;
// Check if any document is open
if (app.documents.length > 0) {
doc1 = app.activeDocument;
}
// Conversion functions
function pxToPt(px) { return px * 0.75; }
function ptToPx(pt) { return pt / 0.75; }
// Create dialog window
var dialog = new Window("dialog", "Symbol Export Settings");
dialog.orientation = "column";
// Add file selection group
var fileGroup = dialog.add("panel", undefined, "Source File");
fileGroup.orientation = "column";
fileGroup.alignChildren = "left";
var useCurrentRb = fileGroup.add("radiobutton", undefined, "Use Current Document");
var chooseFileRb = fileGroup.add("radiobutton", undefined, "Choose AI File");
// Set initial state based on document availability
if (doc1 === null) {
useCurrentRb.enabled = false;
chooseFileRb.value = true;
} else {
useCurrentRb.value = true;
useCurrentRb.enabled = true;
}
var chooseGroup = fileGroup.add("group");
var filePathText = chooseGroup.add("edittext", undefined, "");
filePathText.preferredSize.width = 200;
var chooseBtn = chooseGroup.add("button", undefined, "Browse...");
// Set initial state of file selection controls
filePathText.enabled = (doc1 === null);
chooseBtn.enabled = (doc1 === null);
// Enable/disable file selection based on radio button
chooseFileRb.onClick = function() {
filePathText.enabled = chooseFileRb.value;
chooseBtn.enabled = chooseFileRb.value;
}
useCurrentRb.onClick = function() {
filePathText.enabled = false;
chooseBtn.enabled = false;
}
// Browse button functionality
chooseBtn.onClick = function() {
var file = File.openDialog("Select Illustrator File", "*.ai");
if (file) {
filePathText.text = file.fsName;
// Open file and update symbol list
try {
var tempDoc = app.open(file);
updateSymbolList(tempDoc);
tempDoc.close(SaveOptions.DONOTSAVECHANGES);
} catch(e) {
alert("Could not open file: " + e);
}
}
}
// Add symbol size input (now in pixels)
var sizeGroup = dialog.add("group");
sizeGroup.add("statictext", undefined, "Symbol Size (px):");
var symbolSizeInput = sizeGroup.add("edittext", undefined, "64"); // Default 64px instead of 50pt
symbolSizeInput.characters = 6;
// Add margin input (now in pixels)
var marginGroup = dialog.add("group");
marginGroup.add("statictext", undefined, "Margin (px):");
var marginInput = marginGroup.add("edittext", undefined, "24"); // Default 24px instead of 20pt
marginInput.characters = 6;
// Add symbol selection list
var listGroup = dialog.add("group");
listGroup.orientation = "column";
listGroup.alignChildren = "fill";
listGroup.add("statictext", undefined, "Select Symbols to Export:");
// Create selection list
var symbolList = listGroup.add("listbox", undefined, [], {multiselect: true});
symbolList.preferredSize.width = 300;
symbolList.preferredSize.height = 200;
// Function to populate symbol list
function updateSymbolList(sourceDoc) {
symbolList.removeAll(); // Clear existing items
for (var i = 0; i < sourceDoc.symbols.length; i++) {
var item = symbolList.add("item", sourceDoc.symbols[i].name);
item.selected = true;
}
}
// Initialize list with current document symbols only if we have one
if (doc1 !== null) {
updateSymbolList(doc1);
}
// Add Select All/None buttons
var selectGroup = dialog.add("group");
var selectAll = selectGroup.add("button", undefined, "Select All");
var selectNone = selectGroup.add("button", undefined, "Select None");
selectAll.onClick = function() {
for (var i = 0; i < symbolList.items.length; i++) {
symbolList.items[i].selected = true;
}
}
selectNone.onClick = function() {
for (var i = 0; i < symbolList.items.length; i++) {
symbolList.items[i].selected = false;
}
}
// Add buttons
var buttons = dialog.add("group");
buttons.add("button", undefined, "OK");
buttons.add("button", undefined, "Cancel");
// Show dialog
if (dialog.show() == 1) { // OK was pressed
// Get the source document
var doc1;
if (chooseFileRb.value) {
if (filePathText.text) {
try {
doc1 = app.open(File(filePathText.text));
} catch(e) {
alert("Could not open file: " + e);
exit();
}
} else {
alert("Please select a file first!");
exit();
}
} else {
doc1 = app.activeDocument;
}
// Convert pixel values to points for Illustrator
var symbolSize = pxToPt(Number(symbolSizeInput.text));
var margin = pxToPt(Number(marginInput.text));
// Get selected symbols
var selectedSymbols = [];
for (var i = 0; i < symbolList.items.length; i++) {
if (symbolList.items[i].selected) {
selectedSymbols.push(doc1.symbols[i]);
}
}
// Layout only selected symbols (using point values internally)
var x = 0, y = 0, row = 1;
for (var i = 0; i < selectedSymbols.length; i++) {
symbolItem1 = doc1.symbolItems.add(selectedSymbols[i]);
symbolItem1.left = x;
symbolItem1.top = y;
symbolItem1.width = symbolSize;
symbolItem1.height = symbolSize;
symbolItem1.selected = true;
if (i < (10 * row) - 1) {
x += symbolSize + margin;
} else {
x = 0;
y -= symbolSize + margin;
row++;
}
}
// Copy to new document
app.copy();
// Create new document with same settings as source
var preset = new DocumentPreset();
preset.colorMode = doc1.documentColorSpace;
preset.units = doc1.rulerUnits;
preset.width = 800;
preset.height = 600;
var doc2 = app.documents.addDocument(doc1.documentColorSpace, preset);
// Remove default swatches and symbols (if any)
while(doc2.symbols.length > 0) {
doc2.symbols[0].remove();
}
app.paste();
// Create artboards from symbols and match names
for (var k = 0; k < doc2.symbolItems.length; k++){
var currentSymbolItem = doc2.symbolItems[k];
// Find matching symbol from selected symbols by comparing names
var matchingSymbol = null;
for (var s = 0; s < selectedSymbols.length; s++) {
if (currentSymbolItem.symbol.name === selectedSymbols[s].name) {
matchingSymbol = selectedSymbols[s];
break;
}
}
var newArtboard = doc2.artboards.add(currentSymbolItem.visibleBounds);
if (matchingSymbol) {
newArtboard.name = (k + 1) + "_" + matchingSymbol.name;
} else {
newArtboard.name = (k + 1) + "_unknown";
}
}
doc2.artboards[0].remove()
if (chooseFileRb.value) {
doc1.close(SaveOptions.DONOTSAVECHANGES);
}
} else {
// User cancelled
alert("Export cancelled");
}
Copy link to clipboard
Copied
one little issue is the pt to px conversion, it has factor what i wrong for illstrator
// Conversion functions
function pxToPt(px) { return px }
function ptToPx(pt) { return pt }
Copy link to clipboard
Copied
This version works fine, Femke.
Thanks for your very good contribution.
Copy link to clipboard
Copied
thank you so much everyone. I'll give this a try.
Copy link to clipboard
Copied
Very good and useful, Femke!