Skip to content

Instantly share code, notes, and snippets.

@hughker
Forked from TomByrne/MultiExporter.jsx
Last active August 29, 2015 14:27
Show Gist options
  • Save hughker/c8078e0bdd0b77f1edea to your computer and use it in GitHub Desktop.
Save hughker/c8078e0bdd0b77f1edea to your computer and use it in GitHub Desktop.
An Illustrator script for exporting layers and/or artboards into separate files (PNG8 / PNG24 / EPS / PDF / SVG / JPG / FXG).See http://www.tbyrne.org/export-illustrator-layers-to-svg-files
// MultiExporter.jsx
// Version 0.1
// Version 0.2 Adds PNG and EPS exports
// Version 0.3 Adds support for exporting at different resolutions
// Version 0.4 Adds support for SVG, changed EPS behaviour to minimise output filesize
// Version 0.5 Fixed cropping issues
// Version 0.6 Added inner padding mode to prevent circular bounds clipping
// Version 1.0
//
// Copyright 2014 Tom Byrne
// Comments or suggestions to [email protected]
//
// Copyright 2011 Matthew Ericson
var docRef = app.activeDocument;
// Format specific functionality
getPng8Options = function(transparency, scaling, embedImage, embedFont, trimEdges) {
var options = new ExportOptionsPNG8();
options.antiAliasing = true;
options.transparency = transparency;
options.artBoardClipping = true;
options.horizontalScale = scaling;
options.verticalScale = scaling;
return options;
}
getPng24Options = function(transparency, scaling, embedImage, embedFont, trimEdges) {
var options = new ExportOptionsPNG24();
options.antiAliasing = true;
options.transparency = transparency;
options.artBoardClipping = true;
options.horizontalScale = scaling;
options.verticalScale = scaling;
return options;
}
getPdfOptions = function(transparency, scaling, embedImage, embedFont, trimEdges) {
var options = new PDFSaveOptions();
options.compatibility = PDFCompatibility.ACROBAT5;
options.generateThumbnails = true;
options.preserveEditability = false;
return options;
}
getJpgOptions = function(transparency, scaling, embedImage, embedFont, trimEdges) {
var options = new ExportOptionsJPEG();
options.antiAliasing = true;
options.artBoardClipping = true;
options.horizontalScale = scaling;
options.verticalScale = scaling;
return options;
}
getEpsOptions = function(transparency, scaling, embedImage, embedFont, trimEdges) {
var options = new EPSSaveOptions();
options.embedLinkedFiles = embedImage;
options.embedAllFonts = embedFont;
options.includeDocumentThumbnails = true;
options.saveMultipleArtboards = false;
return options;
}
getSvgOptions = function(transparency, scaling, embedImage, embedFont, trimEdges) {
options = new ExportOptionsSVG();
options.embedRasterImages = embedImage;
options.saveMultipleArtboards = true;
return options;
}
getFxg1Options = function(transparency, scaling, embedImage, embedFont, trimEdges) {
options = new FXGSaveOptions();
options.version = FXGVersion.VERSION1PT0;
return options;
}
getFxg2Options = function(transparency, scaling, embedImage, embedFont, trimEdges) {
options = new FXGSaveOptions();
options.version = FXGVersion.VERSION2PT0;
return options;
}
// Format specific save functions
savePng8 = function(doc, filePath, options, artboardIndex, artboardName) {
var destFile = new File(filePath);
doc.exportFile(destFile, ExportType.PNG8, options);
}
savePng24 = function(doc, filePath, options, artboardIndex, artboardName) {
var destFile = new File(filePath);
doc.exportFile(destFile, ExportType.PNG24, options);
}
savePdf = function(doc, filePath, options, artboardIndex, artboardName) {
var destFile = new File(filePath);
options.artboardRange = (artboardIndex + 1).toString();
doc.saveAs(destFile, options, artboardIndex, artboardName)
}
saveJpg = function(doc, filePath, options, artboardIndex, artboardName) {
var destFile = new File(filePath);
doc.exportFile(destFile, ExportType.JPEG, options);
}
saveEps = function(doc, filePath, options, artboardIndex, artboardName) {
var destFile = new File(filePath);
options.artboardRange = (artboardIndex + 1).toString();
doc.saveAs(destFile, options, artboardIndex, artboardName)
}
saveSvg = function(doc, filePath, options, artboardIndex, artboardName) {
var destFile = new File(filePath);
doc.exportFile(destFile, ExportType.SVG, options);
}
saveFxg = function(doc, filePath, options, artboardIndex, artboardName) {
var destFile = new File(filePath);
options.artboardRange = (artboardIndex + 1).toString();
doc.saveAs(destFile, options, artboardIndex, artboardName)
}
var multi_exporter = {
OLD_PREFS_LAYER_NAME: "nyt_exporter_info",
PREFS_LAYER_NAME: "MultiExporter Props",
DEFAULT_PATTERN: "<ArtboardName>_<LayerName>.<Ext>",
multiExporterPrefs: null,
prefix: '',
suffix: '',
base_path: '~/Desktop',
transparency: false,
embedImage: true,
embedFont: true,
trimEdges: true,
innerPadding: false,
ignoreWarnings: false,
format: "PNG 24",
artboards: null,
layers: null,
dlg: null,
prefs_xml: null,
currentFormatInfo: null,
num_to_export: 0,
failed_artboards: null,
failed_layers: null,
export_artboards: null,
export_layers: null,
whole_artboard_mode: false,
formatList: null,
artboardList: null,
progLabel: null,
// these are controls that are format dependant
controlNames: ["scalingInput", "transCheckBox", "embedImageCheckBox", "embedFontCheckBox", "trimEdgesCheckBox", "innerPaddingCheckBox"],
scalingInput: null,
transCheckBox: null,
embedImageCheckBox: null,
embedFontCheckBox: null,
trimEdgesCheckBox: null,
ignoreCheckBox: null,
exportArtboardsCheckBox: null,
// copyBehaviour - for vector outputs the output must be done from a copy of the document (to avoid hidden layers being included in output)
formatInfo: [{
name: "PNG 8",
ext: 'png',
copyBehaviour: false,
getOptions: getPng8Options,
saveFile: savePng8,
activeControls: ["scalingInput", "transCheckBox", "trimEdgesCheckBox", "innerPaddingCheckBox"]
}, {
name: "PNG 24",
ext: 'png',
copyBehaviour: false,
getOptions: getPng24Options,
saveFile: savePng24,
activeControls: ["scalingInput", "transCheckBox", "trimEdgesCheckBox", "innerPaddingCheckBox"]
}, {
name: "PDF",
ext: 'pdf',
copyBehaviour: false,
getOptions: getPdfOptions,
saveFile: savePdf,
activeControls: ["trimEdgesCheckBox"]
}, {
name: "JPG",
ext: 'jpg',
copyBehaviour: false,
getOptions: getJpgOptions,
saveFile: saveJpg,
activeControls: ["scalingInput", "trimEdgesCheckBox", "innerPaddingCheckBox"]
}, {
name: "EPS",
ext: 'eps',
copyBehaviour: true,
getOptions: getEpsOptions,
saveFile: saveEps,
activeControls: ["embedImageCheckBox", "embedFontCheckBox", "trimEdgesCheckBox"]
}, {
name: "SVG 1.1",
ext: 'svg',
copyBehaviour: true,
getOptions: getSvgOptions,
saveFile: saveSvg,
activeControls: ["embedImageCheckBox", "trimEdgesCheckBox"]
}, {
name: "FXG 1.0",
ext: 'fxg',
copyBehaviour: true,
getOptions: getFxg1Options,
saveFile: saveFxg,
activeControls: ["trimEdgesCheckBox"]
}, {
name: "FXG 2.0",
ext: 'fxg',
copyBehaviour: true,
getOptions: getFxg2Options,
saveFile: saveFxg,
activeControls: ["trimEdgesCheckBox"]
}],
artboardSelect: [{
code: "all",
name: 'All Artboards (except those beginning with - )'
}, {
code: "current",
name: 'Current Artboard'
}, {
name: '---'
}],
layerSelect: [{
code: "all",
name: 'All Layers (except those beginning with - )'
}, {
code: "none",
name: 'None (for use with \'Export Artboard Images\')'
}, {
code: "selected",
name: 'Selected Items\' Layers'
}, {
name: '---'
}],
init: function() {
var parse_success = this.load_prefs();
this.TOKENS = ["--Tokens--", this.ARTBOARD_NUM_TOKEN, this.ARTBOARD_NAME_TOKEN, this.LAYER_NUM_TOKEN, this.LAYER_NAME_TOKEN, this.FILE_EXT_TOKEN];
if (parse_success) {
this.show_dialog();
}
},
findExportTypeByCode: function(code) {
for (var i = 0; i < this.exportTypes.length; ++i) {
var type = this.exportTypes[i];
if (type.code == code) return type;
}
},
updatePrefNode: function(node) {
if (node.nodeKind() != "element") return;
var name = node.name().toString();
if (name.indexOf("nyt_") == 0) node.setName(name.substr(4));
for (var i = 0; i < node.children().length(); ++i) {
this.updatePrefNode(node.children()[i]);
}
},
xmlEncode: function(str) {
str = str.replace(/&/g, "&amp;");
str = str.replace(/\</g, "&lt;");
str = str.replace(/\>/g, "&gt;");
str = str.replace(/"/g, "&quot;");
str = str.replace(/'/g, "&apos;");
return str;
},
load_prefs: function() {
var parse_success = false;
// find existing layers or add new one
try {
this.multiExporterPrefs = docRef.layers.getByName(this.PREFS_LAYER_NAME);
} catch (e) {
try {
this.multiExporterPrefs = docRef.layers.getByName(this.OLD_PREFS_LAYER_NAME);
this.multiExporterPrefs.name = this.PREFS_LAYER_NAME;
} catch (e) {
this.multiExporterPrefs = docRef.layers.add();
this.multiExporterPrefs.name = this.PREFS_LAYER_NAME;
var exporter_info_xml = this.multiExporterPrefs.textFrames.add();
var saved_data = new XML('<prefs></prefs>');
saved_data.appendChild(new XML('<pattern>' + this.xmlEncode(this.DEFAULT_PATTERN) + '</pattern>'));
saved_data.appendChild(new XML('<base_path>~/Desktop</base_path>'));
saved_data.appendChild(new XML('<scaling>100%</scaling>'));
saved_data.appendChild(new XML('<transparency>true</transparency>'));
saved_data.appendChild(new XML('<embedImage>true</embedImage>'));
saved_data.appendChild(new XML('<embedFont>true</embedFont>'));
saved_data.appendChild(new XML('<trimEdges>true</trimEdges>'));
saved_data.appendChild(new XML('<innerPadding>false</innerPadding>'));
saved_data.appendChild(new XML('<format>PNG 24</format>'));
saved_data.appendChild(new XML('<artboards>all</artboards>'));
saved_data.appendChild(new XML('<layers>all</layers>'));
saved_data.appendChild(new XML('<exportArtboards>false</exportArtboards>'));
saved_data.appendChild(new XML('<ignoreWarnings>false</ignoreWarnings>'));
exporter_info_xml.contents = saved_data.toXMLString();
this.multiExporterPrefs.printable = false;
this.multiExporterPrefs.visible = false;
}
}
// get xml out of the 1 text item on that layer and parse it
if (this.multiExporterPrefs.textFrames.length != 1) {
Window.alert('Please delete the ' + this.PREFS_LAYER_NAME + ' layer and try again.');
} else {
try {
this.prefs_xml = new XML(this.multiExporterPrefs.textFrames[0].contents);
this.updatePrefNode(this.prefs_xml);
this.multiExporterPrefs.textFrames[0].contents = this.prefs_xml.toXMLString();
this.pattern = this.prefs_xml.pattern || this.DEFAULT_PATTERN;
this.base_path = this.prefs_xml.base_path;
this.scaling = this.prefs_xml.scaling;
this.transparency = this.prefs_xml.transparency == "true" ? true : false;
this.embedImage = this.prefs_xml.embedImage == "true" ? true : false;
this.ignoreWarnings = this.prefs_xml.ignoreWarnings == "true" ? true : false;
this.embedFont = this.prefs_xml.embedFont == "true" ? true : false;
this.trimEdges = this.prefs_xml.trimEdges == "true" ? true : false;
this.innerPadding = this.prefs_xml.innerPadding == "true" ? true : false;
this.format = this.prefs_xml.format;
this.artboards = this.prefs_xml.artboards.toString();
this.layers = this.prefs_xml.layers.toString();
this.whole_artboard_mode = this.prefs_xml.exportArtboards == "true" ? true : false;
if (!this.artboards) {
this.artboards = this.artboardSelect[0].code;
} else if (parseInt(this.artboards).toString() == this.artboards) {
this.artboards = parseInt(this.artboards);
}
if (!this.layers) {
this.layers = this.layerSelect[0].code;
} else if (parseInt(this.layers).toString() == this.layers) {
this.layers = parseInt(this.layers);
}
if (!this.prefs_xml.scaling || this.prefs_xml.scaling == '') {
this.scaling = '100%';
}
parse_success = true;
} catch (e) {
Window.alert('Please delete the this.multiExporterPrefs layer and try again.');
}
}
return parse_success;
},
patternChanged: function() {
if (!this.export_layers || !this.currentFormatInfo) {
this.exampleSt.text = "";
return;
}
var example;
if (this.export_layers.length && this.export_artboards.length) {
var artboardI = this.export_artboards[0];
var layerI = this.export_layers[0];
this.exampleSt.text = this.makeFileName(this.patternEt.text, this.currentFormatInfo.ext, artboardI + 1, docRef.artboards[artboardI].name, layerI + 1, docRef.layers[layerI].name);
} else if (this.export_artboards.length) {
var artboardI = this.export_artboards[0];
this.exampleSt.text = this.makeFileName(this.patternEt.text, this.currentFormatInfo.ext, artboardI + 1, docRef.artboards[artboardI].name, "", "");
} else {
this.exampleSt.text = "";
}
},
addToken: function() {
if (this.tokenList.selection > 0) {
var selected = Number(this.tokenList.selection);
var token = this.TOKENS[selected];
this.patternEt.text += token;
this.patternChanged();
}
this.tokenList.selection = 0;
},
// dialog display
show_dialog: function() {
// Export dialog
this.dlg = new Window('dialog', 'Multi Exporter');
var row;
// ARTBOARD TYPE ROW
row = this.dlg.add('group', undefined, '')
row.orientation = 'row';
row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]
var typeSt = row.add('statictext', undefined, 'Export artboards:');
typeSt.size = [100, 20];
var artboardNames = [];
for (var i = 0; i < this.artboardSelect.length; ++i) {
artboardNames.push(this.artboardSelect[i].name)
}
for (var i = 0; i < docRef.artboards.length; i++) {
var artboard = docRef.artboards[i];
artboardNames.push((i + 1) + ": " + artboard.name);
}
this.artboardList = row.add('dropdownlist', undefined, artboardNames);
this.artboardList.selection = this.findDataIndex(this.artboards, this.artboardSelect);
this.exportArtboardsCheckBox = row.add('checkbox', undefined, 'Export Artboard Images');
this.exportArtboardsCheckBox.value = this.whole_artboard_mode;
// LAYER TYPE ROW
row = this.dlg.add('group', undefined, '')
row.orientation = 'row';
row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]
var typeSt = row.add('statictext', undefined, 'Export layers:');
typeSt.size = [100, 20];
var layerNames = [];
for (var i = 0; i < this.layerSelect.length; ++i) {
layerNames.push(this.layerSelect[i].name)
}
for (var i = 0; i < docRef.layers.length; i++) {
var layer = docRef.layers[i];
layerNames.push((i + 1) + ": " + layer.name);
}
this.layerList = row.add('dropdownlist', undefined, layerNames);
this.layerList.selection = this.findDataIndex(this.layers, this.layerSelect);
// Pattern GRP
row = this.dlg.add('group', undefined, '')
row.orientation = 'row';
row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]
var patternSt = row.add('statictext', undefined, 'Filename Pattern:');
patternSt.size = [100, 20]
this.patternEt = row.add('edittext', undefined, this.pattern);
this.patternEt.size = [300, 20];
this.patternEt.addEventListener("keyup", function() {
multi_exporter.patternChanged();
});
this.patternEt.onChange = function() {
multi_exporter.patternChanged();
};
this.tokenList = row.add('dropdownlist', undefined, this.TOKENS);
this.tokenList.onChange = function() {
multi_exporter.addToken();
};
this.tokenList.selection = 0;
// Example GRP
row = this.dlg.add('group', undefined, '')
row.orientation = 'row';
row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]
var patternSt = row.add('statictext', undefined, 'Example Filename:');
patternSt.size = [105, 20]
this.exampleSt = row.add('statictext', undefined, '');
this.exampleSt.size = [300, 20];
// scaling row
row = this.dlg.add('group', undefined, '')
row.orientation = 'row';
row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]
var scalingLabel = row.add('statictext', undefined, 'Scaling:');
scalingLabel.size = [100, 20]
this.scalingInput = row.add('edittext', undefined, this.scaling);
this.scalingInput.size = [100, 20];
var scalingTip = row.add('statictext', undefined, '(Normally 100%; Use 200% for Retina display exports)');
scalingTip.size = [300, 20]
// DIR GROUP
row = this.dlg.add('group', undefined, '')
row.orientation = 'row'
row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]
var dirSt = row.add('statictext', undefined, 'Output directory:');
dirSt.size = [100, 20];
this.dirEt = row.add('edittext', undefined, this.base_path);
this.dirEt.size = [300, 20];
var chooseBtn = row.add('button', undefined, 'Choose ...');
chooseBtn.onClick = function() {
multi_exporter.dirEt.text = Folder.selectDialog();
}
// FORMAT ROW
row = this.dlg.add('group', undefined, '');
row.orientation = 'row'
row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]
var formatSt = row.add('statictext', undefined, 'Export format:');
formatSt.size = [100, 20];
var formatNames = [];
for (var i = 0; i < this.formatInfo.length; ++i) {
formatNames.push(this.formatInfo[i].name)
}
this.formatList = row.add('dropdownlist', undefined, formatNames);
this.formatList.selection = 1;
for (var i = 0; i < this.formatList.items.length; i++) {
if (multi_exporter.format == this.formatList.items[i].text) {
this.formatList.selection = i;
}
}
this.embedImageCheckBox = row.add('checkbox', undefined, 'Embed Imagery');
this.embedImageCheckBox.value = this.embedImage;
this.embedFontCheckBox = row.add('checkbox', undefined, 'Embed Fonts');
this.embedFontCheckBox.value = this.embedFont;
// TRANSPARENCY AND TRIM ROW
row = this.dlg.add('group', undefined, '');
row.orientation = 'row'
row.alignment = [ScriptUI.Alignment.CENTER, ScriptUI.Alignment.TOP]
this.transCheckBox = row.add('checkbox', undefined, 'Transparency');
this.transCheckBox.value = this.transparency;
this.trimEdgesCheckBox = row.add('checkbox', undefined, 'Trim Edges');
this.trimEdgesCheckBox.value = this.trimEdges;
this.innerPaddingCheckBox = row.add('checkbox', undefined, 'Inner Padding (to prevent curved edge clipping)');
this.innerPaddingCheckBox.value = this.innerPadding;
// progress bar
var progBar = this.dlg.add('progressbar', undefined, 0, 100);
progBar.size = [400, 10]
this.progLabel = this.dlg.add('statictext', undefined, '...');
this.progLabel.size = [400, 20];
// buttons row
row = this.dlg.add('group', undefined, '');
row.orientation = 'row'
var cancelBtn = row.add('button', undefined, 'Cancel', {
name: 'cancel'
});
cancelBtn.onClick = function() {
multi_exporter.dlg.close()
};
var saveBtn = row.add('button', undefined, 'Save and Close', {
name: 'saveClose'
});
saveBtn.onClick = function() {
multi_exporter.saveOptions();
multi_exporter.dlg.close()
};
// OK button
var okBtn = row.add('button', undefined, 'Export', {
name: 'ok'
});
okBtn.onClick = function() {
multi_exporter.saveOptions(); // save options before export in case of errors
try {
multi_exporter.run_export();
} catch (e) {
alert(e);
}
};
this.ignoreCheckBox = row.add('checkbox', undefined, 'Ignore Warnings');
this.ignoreCheckBox.value = this.ignoreWarnings;
// Export type handler
this.artboardList.onChange = function() {
multi_exporter.artboards = multi_exporter.getListData(multi_exporter.artboardList.selection.index, multi_exporter.artboardSelect);
multi_exporter.update_export_desc();
};
this.layerList.onChange = function() {
multi_exporter.layers = multi_exporter.getListData(multi_exporter.layerList.selection.index, multi_exporter.layerSelect);
multi_exporter.update_export_desc();
};
this.exportArtboardsCheckBox.onClick = function() {
multi_exporter.whole_artboard_mode = multi_exporter.exportArtboardsCheckBox.value;
multi_exporter.update_export_desc();
};
// Format change handler
this.formatList.onChange = function() {
multi_exporter.checkFormat();
multi_exporter.patternChanged();
};
multi_exporter.update_export_desc();
this.dlg.progBar = progBar;
this.patternChanged();
this.checkFormat();
this.dlg.show();
},
findDataIndex: function(data, selectList) {
if (typeof(data) == "string" && parseInt(data).toString() == data) {
data = parseInt(data);
}
if (typeof(data) == "number") {
return selectList.length + data;
} else {
for (var i = 0; i < selectList.length; ++i) {
if (selectList[i].code == data) {
return i;
}
}
}
alert("no find: " + data);
},
getListData: function(index, selectList) {
if (index >= selectList.length) {
return index - selectList.length;
} else {
return selectList[index].code;
}
},
checkFormat: function(progLabel) {
var formatInfo = this.formatInfo[this.formatList.selection.index];
this.currentFormatInfo = formatInfo;
for (var i = 0; i < this.controlNames.length; i++) {
var controlName = this.controlNames[i];
this[controlName].enabled = (this.indexOf(formatInfo.activeControls, controlName) != -1);
}
},
indexOf: function(array, element) {
for (var i = 0; i < array.length; i++) {
if (array[i] == element) return i;
}
return -1;
},
update_export_desc: function() {
this.export_artboards = [];
this.export_layers = [];
if (this.artboards == "all") {
for (var i = 0; i < docRef.artboards.length; ++i) {
var artboard = docRef.artboards[i];
if (!artboard.name.match(/^\-/)) {
this.export_artboards.push(i);
}
}
} else if (this.artboards == "current") {
this.export_artboards.push(docRef.artboards.getActiveArtboardIndex());
} else if (typeof(this.artboards) == "number") {
this.export_artboards.push(this.artboards);
}
if (this.layers == "all") {
for (var i = 0; i < docRef.layers.length; ++i) {
var layer = docRef.layers[i];
if (!this.isAdditionalLayer(layer) && this.isIncludeLayer(layer)) {
this.export_layers.push(i);
}
}
} else if (this.layers == "selected") {
for (var i = 0; i < docRef.layers.length; ++i) {
var layer = docRef.layers[i];
if (!this.isAdditionalLayer(layer) && this.isIncludeLayer(layer) && layer.hasSelectedArtwork) {
this.export_layers.push(i);
}
}
this.export_layers.push(docRef.artboards.getActiveArtboardIndex());
} else if (typeof(this.layers) == "number") {
this.export_layers.push(this.layers);
}
this.updateExportCounts();
this.patternChanged();
},
updateExportCounts: function() {
this.num_to_export = this.export_artboards.length * this.export_layers.length;
var artboardExportTxt;
if (this.whole_artboard_mode) {
this.num_to_export += this.export_artboards.length;
if (this.export_layers.length) {
artboardExportTxt = " (and " + this.export_artboards.length + " artboard images)";
} else {
this.progLabel.text = 'Will export ' + this.export_artboards.length + ' of ' + docRef.artboards.length + ' artboards';
return;
}
} else {
artboardExportTxt = "";
}
if (this.export_artboards.length > 1 && this.export_layers.length > 1) {
this.progLabel.text = 'Will export ' + this.num_to_export + ' files (' + this.export_layers.length + ' layers * ' + this.export_artboards.length + ' artboards)' + artboardExportTxt;
} else if (this.export_layers.length > 0 && this.export_artboards.length == 1) {
var artboard = docRef.artboards[this.export_artboards[0]];
this.progLabel.text = 'Will export ' + this.export_layers.length + ' of ' + docRef.layers.length + ' layers on artboard "' + artboard.name + '"' + artboardExportTxt;
} else if (this.export_layers.length > 0 && this.export_artboards.length > 0) {
var artboard = docRef.artboards[this.export_artboards[0]];
this.progLabel.text = 'Will export ' + this.export_layers.length + ' layers on "' + this.export_artboards.length + '" artboards' + artboardExportTxt;
} else {
this.progLabel.text = 'Please select valid artboards / layers';
}
},
saveOptions: function() {
this.pattern = this.patternEt.text;
this.base_path = this.dirEt.text;
this.transparency = this.transCheckBox.value;
this.embedImage = this.embedImageCheckBox.value;
this.embedFont = this.embedFontCheckBox.value;
this.trimEdges = this.trimEdgesCheckBox.value;
this.innerPadding = this.innerPaddingCheckBox.value;
this.ignoreWarnings = this.ignoreCheckBox.value;
this.format = this.formatList.selection.text;
this.scaling = parseFloat(this.scalingInput.text.replace(/\% /, ''));
this.prefs_xml.base_path = this.base_path;
this.prefs_xml.scaling = this.scaling;
this.prefs_xml.pattern = this.pattern;
this.prefs_xml.transparency = this.transparency;
this.prefs_xml.embedImage = this.embedImage;
this.prefs_xml.ignoreWarnings = this.ignoreWarnings;
this.prefs_xml.embedFont = this.embedFont;
this.prefs_xml.trimEdges = this.trimEdges;
this.prefs_xml.innerPadding = this.innerPadding;
this.prefs_xml.format = this.format;
this.prefs_xml.artboards = this.artboards;
this.prefs_xml.layers = this.layers;
this.prefs_xml.exportArtboards = this.whole_artboard_mode;
this.multiExporterPrefs.textFrames[0].contents = this.prefs_xml.toXMLString();
},
ARTBOARD_NUM_TOKEN: "<ArtboardNum>",
ARTBOARD_NAME_TOKEN: "<ArtboardName>",
LAYER_NUM_TOKEN: "<LayerNum>",
LAYER_NAME_TOKEN: "<LayerName>",
FILE_EXT_TOKEN: "<Ext>",
makeFileName: function(pattern, ext, artNum, artName, layNum, layName) {
var ret = pattern;
ret = ret.split(this.ARTBOARD_NUM_TOKEN).join(artNum);
ret = ret.split(this.ARTBOARD_NAME_TOKEN).join(artName);
ret = ret.split(this.LAYER_NUM_TOKEN).join(layNum);
ret = ret.split(this.LAYER_NAME_TOKEN).join(layName);
ret = ret.split(this.FILE_EXT_TOKEN).join(ext);
return ret;
},
// run_export function. does the dirty work
run_export: function() {
this.failed_artboards = [];
this.failed_layers = [];
var formatInfo = this.currentFormatInfo;
var copyBehaviour = formatInfo.copyBehaviour || this.trimEdges;
var num_exported = 0;
var options = formatInfo.getOptions(this.transparency, this.scaling, this.embedImage, this.embedFont, this.trimEdges);
if (!copyBehaviour) {
var were_shown = this.get_shown_layers();
}
if (!this.export_artboards.length || (!this.export_layers.length && !this.whole_artboard_mode)) {
alert('Please select valid artboards / layers');
return;
}
if (!this.base_path) {
alert('Please select select a destination');
return;
}
// offsetting must be in relation to the center of the first artboard
var firstRect = docRef.artboards[0].artboardRect;
var firstCentX = (firstRect[2] - firstRect[0]) / 2;
var firstCentY = (firstRect[1] - firstRect[3]) / 2;
for (var i = 0; i < this.export_artboards.length; i++) {
var artboard = docRef.artboards[this.export_artboards[i]];
var artboardName = artboard.name;
starting_artboard = docRef.artboards.setActiveArtboardIndex(i);
var rect = artboard.artboardRect;
var offsetX = firstRect[0] - rect[0];
var offsetY = firstRect[1] - rect[1];
var artW = rect[2] - rect[0];
var artH = rect[1] - rect[3];
var copyDoc;
// if exporting artboard by artboard, export layers as is
if (this.whole_artboard_mode) {
try {
var base_filename = this.base_path + "/" + this.makeFileName(this.pattern, formatInfo.ext, i + 1, artboardName, "", ""); //this.base_path + "/" + this.prefix + artboardName + this.suffix;
if (copyBehaviour) {
var offset = {
x: offsetX,
y: offsetY
};
copyDoc = this.copyDocument(docRef, artboard, rect, artW, artH, offset, function(layer) {
return (layer.name != multi_exporter.PREFS_LAYER_NAME && layer.visible)
});
formatInfo.saveFile(copyDoc, base_filename, options, i, artboardName);
copyDoc.close(SaveOptions.DONOTSAVECHANGES);
copyDoc = null;
} else {
formatInfo.saveFile(docRef, base_filename, options, i, artboardName);
}
} catch (e) {
this.failed_artboards.push(i);
}
this.updateProgress(++num_exported);
}
if (this.export_layers.length) {
if (copyBehaviour) {
if (!this.trimEdges) {
var layerDepths = [];
var offset = {
x: offsetX,
y: offsetY
};
copyDoc = this.copyDocument(docRef, artboard, rect, docRef.width, docRef.height, offset, this.isAdditionalLayer, layerDepths);
var hasAdditLayers = copyDoc.layers.length > 0;
}
} else {
this.hide_all_layers();
}
for (var j = 0; j < this.export_layers.length; j++) {
var layer = docRef.layers[this.export_layers[j]];
var lyr_name = layer.name;
try {
var layerRect
// only process layer if it has bounds (i.e. not guide layer) and falls within current artboard bounds
layerRect = this.get_layer_bounds(layer)
if (layerRect == null) continue;
if (layerRect[0] < layerRect[2] && layerRect[1] > layerRect[3]) {
var isVis = this.intersects(rect, layerRect);
if (!hasAdditLayers && !isVis && !this.trimEdges) {
// skip layers where nothing is visible
continue;
}
var base_filename = this.base_path + "/" + this.makeFileName(this.pattern, formatInfo.ext, i + 1, artboardName, j + 1, lyr_name);
/*if ( this.export_artboards.length==1 ) {
base_filename = this.base_path + "/" + this.prefix + lyr_name + this.suffix;
} else{
base_filename = this.base_path + "/" + this.prefix + artboardName + '-' + lyr_name + this.suffix;
}*/
if (copyBehaviour) {
if (this.trimEdges) {
if (copyDoc) {
copyDoc.close(SaveOptions.DONOTSAVECHANGES);
copyDoc = null;
}
// crop to artboard
if (layerRect[0] < rect[0]) {
layerRect[0] = rect[0];
} else {
intendedX = 0;
}
if (layerRect[1] > rect[1]) {
layerRect[1] = rect[1];
}
if (layerRect[2] > rect[2]) {
layerRect[2] = rect[2];
}
if (layerRect[3] < rect[3]) {
layerRect[3] = rect[3];
} else {
intendedY = 0;
}
layerOffsetY = rect[3] - layerRect[3];
layerOffsetX = rect[0] - layerRect[0];
docW = layerRect[2] - layerRect[0];
docH = layerRect[1] - layerRect[3];
offset = {
x: offsetX + layerOffsetX,
y: offsetY + layerOffsetY
};
var layerDepths = [];
var copyDoc = this.copyDocument(docRef, artboard, rect, docW, docH, offset, this.isAdditionalLayer, layerDepths);
var hasAdditLayers = copyDoc.layers.length > 1; // there will be one empty layer in the new file (which can be ignored)
if (!hasAdditLayers && !isVis) {
// skip layers where nothing is visible
continue;
}
}
if (isVis) {
// only copy layer if it is visible (if not only visible '+' layers will be output)
var new_layer = this.copy_layer(layer, copyDoc.layers.add(), offset, copyDoc.width, copyDoc.height, this.innerPadding);
new_layer.visible = true;
var depth = layerDepths[this.export_layers[j]];
while (new_layer.zOrderPosition < depth) {
new_layer.zOrder(ZOrderMethod.BRINGFORWARD);
}
while (new_layer.zOrderPosition > depth) {
new_layer.zOrder(ZOrderMethod.SENDBACKWARD);
}
}
formatInfo.saveFile(copyDoc, base_filename, options, i, artboardName);
if (new_layer && !this.trimEdges) {
new_layer.remove();
new_layer = null;
}
} else {
layer.visible = true;
formatInfo.saveFile(docRef, base_filename, options, i, artboardName);
layer.visible = false;
}
}
} catch (e) {
this.failed_artboards.push(i);
this.failed_layers.push(j);
if (new_layer && !this.trimEdges) {
new_layer.remove();
new_layer = null;
}
}
this.updateProgress(++num_exported);
}
if (copyDoc) {
copyDoc.close(SaveOptions.DONOTSAVECHANGES);
copyDoc = null;
}
}
}
if (!copyBehaviour) {
this.show_layers(were_shown);
}
if ((!this.failed_layers.length && !this.failed_artboards.length) || !this.redoFailed(this.failed_layers, this.failed_artboards)) {
this.dlg.close();
}
},
redoFailed: function(failed_layers, failed_artboards) {
var newLayers = [];
for (var i = 0; i < failed_layers.length; ++i) {
var index = this.export_layers[failed_layers[i]];
if (this.indexOf(newLayers, index) == -1) newLayers.push(index);
}
var newArtboards = [];
for (var i = 0; i < failed_artboards.length; ++i) {
var index = this.export_artboards[failed_artboards[i]];
if (this.indexOf(newArtboards, index) == -1) newArtboards.push(index);
}
if (newLayers.length) {
var layerNames = "";
for (var i = 0; i < newLayers.length; ++i) {
var index = newLayers[i];
layerNames += "\n - " + docRef.layers[index].name;
}
var msg = newLayers.length + " layers failed across " + newArtboards.length + " artboards:" + layerNames + "\n Retry?";
} else {
var artboardNames = "";
for (var i = 0; i < newArtboards.length; ++i) {
var index = newArtboards[i];
artboardNames += "\n - " + docRef.artboards[index].name;
}
var msg = newArtboards.length + " artboards failed:" + artboardNames + "\nRetry?";
}
if (confirm(msg)) {
this.export_artboards = newArtboards;
this.export_layers = newLayers;
this.updateExportCounts();
this.run_export();
return true;
}
return false;
},
traceRect: function(rect) {
if (!rect) return "no rect";
return "l: " + Math.round(rect[0]) + " t: " + Math.round(rect[1]) + " r: " + Math.round(rect[2]) + " b: " + Math.round(rect[3]) + " w: " + (rect[2] - rect[0]) + " h: " + (rect[1] - rect[3]);
},
isAdditionalLayer: function(layer) {
return (layer.name.match(/^\+/) && layer.visible);
},
isIncludeLayer: function(layer) {
return (!layer.name.match(/^\+/) && layer.name != this.PREFS_LAYER_NAME && !layer.name.match(/^\-/))
},
copyDocument: function(docRef, artboard, rect, w, h, offset, layerCheck, layerDepths) {
var preset = new DocumentPreset();
preset.width = w;
preset.height = h;
preset.colorMode = docRef.documentColorSpace;
preset.units = docRef.rulerUnits;
var copyDoc = app.documents.addDocument(docRef.documentColorSpace, preset);
copyDoc.pageOrigin = docRef.pageOrigin;
copyDoc.rulerOrigin = docRef.rulerOrigin;
var count = 1; // indices are 1 based!
var n = docRef.layers.length;
for (var j = docRef.layers.length - 1; j >= 0; j--) {
layer = docRef.layers[j];
if (layerCheck(layer)) {
var layerBounds = this.get_layer_bounds(layer);
if (layerBounds && this.intersects(rect, layerBounds)) {
this.copy_layer(layer, copyDoc.layers.add(), offset, w, h, this.innerPadding);
++count;
}
} else if (layerDepths) {
layerDepths[j] = count;
}
}
return copyDoc;
},
updateProgress: function(num_exported) {
this.progLabel.text = 'Exported ' + num_exported + ' of ' + this.num_to_export;
this.dlg.progBar.value = num_exported / this.num_to_export * 100;
this.dlg.update();
},
copy_layer: function(from_layer, to_layer, offset, docW, docH, doInnerPadding) {
to_layer.artworkKnockout = from_layer.artworkKnockout;
to_layer.blendingMode = from_layer.blendingMode;
to_layer.color = from_layer.color;
to_layer.dimPlacedImages = from_layer.dimPlacedImages;
to_layer.isIsolated = from_layer.isIsolated;
to_layer.name = from_layer.name;
to_layer.opacity = from_layer.opacity;
to_layer.preview = from_layer.preview;
to_layer.printable = from_layer.printable;
to_layer.sliced = from_layer.sliced;
to_layer.typename = from_layer.typename;
if (!offset.norm) {
var oldBounds = this.get_layer_bounds(from_layer);
//for mystery reasons, this only works if done before copying items across
}
var items = from_layer.pageItems;
try {
this.copy_items(items, to_layer);
} catch (e) {
alert("copy items failed");
}
// copy backwards for correct z-ordering
for (var i = from_layer.layers.length - 1; i >= 0; --i) {
var child = from_layer.layers[i];
if (child.visible) this.copy_layer(child, to_layer.layers.add(), offset, docW, docH, false)
}
if (!offset.norm) {
var newBounds = this.get_layer_bounds(to_layer);
if (this.rect_equal(oldBounds, newBounds)) {
//$.sleep(5000); // sleeping doesn't help!!
if (!this.ignoreWarnings) alert("Illustrator visibleBounds issue workaround.\nTry removing groups on layer '" + from_layer.name + "' to avoid this in future.\nPlease press OK");
newBounds = this.get_layer_bounds(to_layer);
// sometimes it takes a moment for bounds to be updated
}
if (oldBounds && newBounds) {
offset.x += oldBounds[0] - newBounds[0];
offset.y += oldBounds[3] - newBounds[3];
offset.norm = true;
}
}
if (to_layer.parent.artboards != null) { // only if top level layer
try {
this.shift_layer(to_layer, offset.x, offset.y);
} catch (e) {
alert("shift layer failed");
}
}
if (doInnerPadding) this.innerPadLayer(to_layer, docW, docH);
return to_layer;
},
innerPadLayer: function(layer, docW, docH) {
for (var i = 0; i < layer.pageItems.length; ++i) {
var item = layer.pageItems[i];
var bounds = item.visibleBounds;
// round to two decimal points
var l = Math.round(bounds[0] * 100) / 100;
var b = Math.round(bounds[1] * 100) / 100;
var r = Math.round(bounds[2] * 100) / 100;
var t = Math.round(bounds[3] * 100) / 100;
if (l == 0 && t == 0 && r == docW && b == docH) {
var scaleX = (r - 1) / r * 100; // resize takes percentage values
var scaleY = (b - 1) / b * 100;
item.resize(scaleX, scaleY, null, null, null, null, null, Transformation.CENTER);
}
}
for (var i = 0; i < layer.layers.length; ++i) {
innerPadLayer(layer.layers[i], docW, docH);
}
},
rect_equal: function(rect1, rect2) {
return rect1[0] == rect2[0] && rect1[1] == rect2[1] && rect1[2] == rect2[2] && rect1[3] == rect2[3];
},
copy_items: function(from_list, to_layer) {
var visWas = to_layer.visible;
to_layer.visible = true;
for (var i = 0; i < from_list.length; ++i) {
var item = from_list[i].duplicate(to_layer, ElementPlacement.PLACEATEND);
/*if(shiftX!=0 || shiftY!=0){
item.translate(shiftX, shiftY)
}*/
}
to_layer.visible = visWas;
},
shift_layer: function(layer, shiftX, shiftY) {
this.shift_items(layer.pageItems, shiftX, shiftY);
// copy backwards for correct z-ordering
for (var i = layer.layers.length - 1; i >= 0; --i) {
this.shift_layer(layer.layers[i], shiftX, shiftY)
}
},
shift_items: function(items, shiftX, shiftY) {
if (shiftX == undefined) shiftX = 0;
if (shiftY == undefined) shiftY = 0;
for (var i = 0; i < items.length; ++i) {
items[i].translate(shiftX, shiftY)
}
},
hide_all_layers: function() {
var n = docRef.layers.length;
for (var i = 0; i < n; ++i) {
layer = docRef.layers[i];
lyr_name = layer.name;
// any layers that start with + are always turned on
if (this.isAdditionalLayer(layer)) {
layer.visible = true;
} else {
layer.visible = false;
}
}
},
get_shown_layers: function() {
var shown = []
var n = docRef.layers.length;
for (var i = 0; i < n; ++i) {
layer = docRef.layers[i];
if (layer.visible) {
shown.push(i);
}
}
return shown;
},
get_layer_bounds: function(layer) {
var rect;
var items = layer.pageItems;
for (var i = 0; i < items.length; ++i) {
var item = items[i];
if (item.guides) {
continue;
}
var visBounds = item.visibleBounds;
if (visBounds == null) continue;
if (rect == null) {
rect = visBounds;
} else {
if (rect[0] > visBounds[0]) {
rect[0] = visBounds[0];
}
if (rect[1] < visBounds[1]) {
rect[1] = visBounds[1];
}
if (rect[2] < visBounds[2]) {
rect[2] = visBounds[2];
}
if (rect[3] > visBounds[3]) {
rect[3] = visBounds[3];
}
}
}
for (var i = 0; i < layer.layers.length; ++i) {
var childRect = this.get_layer_bounds(layer.layers[i]);
if (childRect == null) continue;
if (rect == null) {
rect = childRect;
} else {
if (rect[0] > childRect[0]) {
rect[0] = childRect[0];
}
if (rect[1] < childRect[1]) {
rect[1] = childRect[1];
}
if (rect[2] < childRect[2]) {
rect[2] = childRect[2];
}
if (rect[3] > childRect[3]) {
rect[3] = childRect[3];
}
}
}
return rect;
},
intersects: function(rect1, rect2) {
return !(rect2[0] > rect1[2] ||
rect2[1] < rect1[3] ||
rect2[2] < rect1[0] ||
rect2[3] > rect1[1]);
},
show_layers: function(layerIndices) {
var n = layerIndices.length;
for (var i = 0; i < n; ++i) {
layer = docRef.layers[layerIndices[i]];
layer.visible = true;
}
}
};
multi_exporter.init();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment