Skip to content

Instantly share code, notes, and snippets.

@dangerdave007
Forked from TomByrne/MultiExporter.jsx
Created December 4, 2015 08:51
Show Gist options
  • Save dangerdave007/07b85b588ed2ff975e86 to your computer and use it in GitHub Desktop.
Save dangerdave007/07b85b588ed2ff975e86 to your computer and use it in GitHub Desktop.

Revisions

  1. @TomByrne TomByrne revised this gist Nov 17, 2014. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion MultiExporter.jsx
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,6 @@ getEpsOptions = function ( transparency, scaling, embedImage, embedFont, trimEdg
    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 ) {
  2. @TomByrne TomByrne revised this gist Dec 6, 2013. 1 changed file with 25 additions and 14 deletions.
    39 changes: 25 additions & 14 deletions MultiExporter.jsx
    Original file line number Diff line number Diff line change
    @@ -163,14 +163,14 @@ var multi_exporter = {
    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", copyBehaviour:false, getOptions:getPng8Options, saveFile:savePng8, activeControls:["scalingInput","transCheckBox","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"PNG 24", copyBehaviour:false, getOptions:getPng24Options, saveFile:savePng24, activeControls:["scalingInput","transCheckBox","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"PDF", copyBehaviour:false, getOptions:getPdfOptions, saveFile:savePdf, activeControls:["trimEdgesCheckBox"]},
    {name:"JPG", copyBehaviour:false, getOptions:getJpgOptions, saveFile:saveJpg, activeControls:["scalingInput","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"EPS", copyBehaviour:true, getOptions:getEpsOptions, saveFile:saveEps, activeControls:["embedImageCheckBox","embedFontCheckBox","trimEdgesCheckBox"]},
    {name:"SVG", copyBehaviour:true, getOptions:getSvgOptions, saveFile:saveSvg, activeControls:["embedImageCheckBox","trimEdgesCheckBox"]},
    {name:"FXG 1.0", copyBehaviour:true, getOptions:getFxg1Options, saveFile:saveFxg, activeControls:["trimEdgesCheckBox"]},
    {name:"FXG 2.0", copyBehaviour:true, getOptions:getFxg2Options, saveFile:saveFxg, activeControls:["trimEdgesCheckBox"]}],
    formatInfo: [ {name:"PNG 8", copyBehaviour:false, pixelDocSize:true, getOptions:getPng8Options, saveFile:savePng8, activeControls:["scalingInput","transCheckBox","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"PNG 24", copyBehaviour:false, pixelDocSize:true, getOptions:getPng24Options, saveFile:savePng24, activeControls:["scalingInput","transCheckBox","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"PDF", copyBehaviour:false, pixelDocSize:false, getOptions:getPdfOptions, saveFile:savePdf, activeControls:["trimEdgesCheckBox"]},
    {name:"JPG", copyBehaviour:false, pixelDocSize:true, getOptions:getJpgOptions, saveFile:saveJpg, activeControls:["scalingInput","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"EPS", copyBehaviour:true, pixelDocSize:false, getOptions:getEpsOptions, saveFile:saveEps, activeControls:["embedImageCheckBox","embedFontCheckBox","trimEdgesCheckBox"]},
    {name:"SVG", copyBehaviour:true, pixelDocSize:false, getOptions:getSvgOptions, saveFile:saveSvg, activeControls:["embedImageCheckBox","trimEdgesCheckBox"]},
    {name:"FXG 1.0", copyBehaviour:true, pixelDocSize:false, getOptions:getFxg1Options, saveFile:saveFxg, activeControls:["trimEdgesCheckBox"]},
    {name:"FXG 2.0", copyBehaviour:true, pixelDocSize:false, getOptions:getFxg2Options, saveFile:saveFxg, activeControls:["trimEdgesCheckBox"]}],

    artboardSelect: [ {code:"all", name:'All Artboards (except those beginning with - )'},
    {code:"current", name:'Current Artboard'},
    @@ -691,7 +691,7 @@ var multi_exporter = {
    var base_filename = 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)});
    copyDoc = this.copyDocument(docRef, formatInfo.pixelDocSize, 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);

    @@ -715,7 +715,7 @@ var multi_exporter = {
    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);
    copyDoc = this.copyDocument(docRef, formatInfo.pixelDocSize, artboard, rect, docRef.width, docRef.height, offset, this.isAdditionalLayer, layerDepths);
    var hasAdditLayers = copyDoc.layers.length>0;
    }
    }else{
    @@ -778,7 +778,7 @@ var multi_exporter = {

    offset = {x:offsetX+layerOffsetX, y:offsetY+layerOffsetY};
    var layerDepths = [];
    var copyDoc = this.copyDocument(docRef, artboard, rect, docW, docH, offset, this.isAdditionalLayer, layerDepths);
    var copyDoc = this.copyDocument(docRef, formatInfo.pixelDocSize, 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)

    @@ -886,7 +886,16 @@ var multi_exporter = {
    return ( !layer.name.match( /^\+/ ) && layer.name!=this.PREFS_LAYER_NAME && !layer.name.match( /^\-/) )
    },

    copyDocument: function(docRef, artboard, rect, w, h, offset, layerCheck, layerDepths) {
    copyDocument: function(docRef, pixelDocSize, artboard, rect, w, h, offset, layerCheck, layerDepths) {
    var docW;
    var docH;
    if(pixelDocSize){
    w = Math.round(w *1000) / 1000;
    h = Math.round(h *1000) / 1000;
    w = Math.ceil(w);
    h = Math.ceil(h);
    }

    var preset = new DocumentPreset();
    preset.width = w;
    preset.height = h;
    @@ -905,7 +914,7 @@ var multi_exporter = {
    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);
    this.copy_layer(layer, copyDoc.layers.add(), offset, w, h, false);
    ++count;
    }
    }else if(layerDepths){
    @@ -981,6 +990,8 @@ var multi_exporter = {
    },

    innerPadLayer: function(layer, docW, docH){
    docW = Math.round(docW * 100) / 100;
    docH = Math.round(docH * 100) / 100;
    for(var i=0; i<layer.pageItems.length; ++i){
    var item = layer.pageItems[i];
    var bounds = item.visibleBounds;
    @@ -991,7 +1002,7 @@ var multi_exporter = {
    var t = Math.round(bounds[3] * 100) / 100;
    var w = (r - l);
    var h = (b - t);
    if(w==docW && h==docH){
    if(w>docW-1 && h>docH-1){
    var scaleX = (w-1) / w * 100; // resize takes percentage values
    var scaleY = (h-1) / h * 100;
    item.resize(scaleX, scaleY, null, null, null, null, null, Transformation.CENTER);
  3. @TomByrne TomByrne revised this gist Dec 6, 2013. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions MultiExporter.jsx
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,15 @@

    // MultiExporter.js
    // 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
    //
    // Exports Illustrator artboards and/or layers as individual PNG or PDF files
    // Copyright 2013 Tom Byrne
    // Comments or suggestions to tom@tbyrne.org
    //
    // Copyright 2011 Matthew Ericson
    // Comments or suggestions to mericson@ericson.net


    var docRef = app.activeDocument;
  4. @TomByrne TomByrne revised this gist Dec 6, 2013. 1 changed file with 8 additions and 6 deletions.
    14 changes: 8 additions & 6 deletions MultiExporter.jsx
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,15 @@

    // MultiExporter.js
    // 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
    //
    // Copyright 2013 Tom Byrne
    // Comments or suggestions to tom@tbyrne.org
    // Exports Illustrator artboards and/or layers as individual PNG or PDF files
    //
    // Copyright 2011 Matthew Ericson
    // Comments or suggestions to mericson@ericson.net


    var docRef = app.activeDocument;
    @@ -989,9 +989,11 @@ var multi_exporter = {
    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;
    var w = (r - l);
    var h = (b - t);
    if(w==docW && h==docH){
    var scaleX = (w-1) / w * 100; // resize takes percentage values
    var scaleY = (h-1) / h * 100;
    item.resize(scaleX, scaleY, null, null, null, null, null, Transformation.CENTER);
    }
    }
  5. @TomByrne TomByrne revised this gist Dec 6, 2013. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions MultiExporter.jsx
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,15 @@

    // MultiExporter.js
    // 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
    //
    // Exports Illustrator artboards and/or layers as individual PNG or PDF files
    // Copyright 2013 Tom Byrne
    // Comments or suggestions to tom@tbyrne.org
    //
    // Copyright 2011 Matthew Ericson
    // Comments or suggestions to mericson@ericson.net


    var docRef = app.activeDocument;
  6. @TomByrne TomByrne created this gist Dec 6, 2013.
    1,146 changes: 1,146 additions & 0 deletions MultiExporter.jsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,1146 @@

    // MultiExporter.js
    // 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
    //
    // Exports Illustrator artboards and/or layers as individual PNG or PDF files
    //
    // Copyright 2011 Matthew Ericson
    // Comments or suggestions to mericson@ericson.net


    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 + '.png' );
    doc.exportFile(destFile, ExportType.PNG8 , options);
    }
    savePng24 = function ( doc, filePath, options, artboardIndex, artboardName ) {
    var destFile = new File( filePath + '.png' );
    doc.exportFile(destFile, ExportType.PNG24 , options);
    }
    savePdf = function ( doc, filePath, options, artboardIndex, artboardName ) {
    var destFile = new File( filePath + '.pdf' );
    options.artboardRange = (artboardIndex+1).toString();
    doc.saveAs( destFile, options, artboardIndex, artboardName )
    }
    saveJpg = function ( doc, filePath, options, artboardIndex, artboardName ) {
    var destFile = new File( filePath + '.jpg' );
    doc.exportFile(destFile, ExportType.JPEG , options);
    }
    saveEps = function ( doc, filePath, options, artboardIndex, artboardName ) {
    var destFile = new File( filePath + '.eps' );
    options.artboardRange = (artboardIndex+1).toString();
    doc.saveAs( destFile, options, artboardIndex, artboardName )
    }
    saveSvg = function ( doc, filePath, options, artboardIndex, artboardName ) {
    var destFile = new File( filePath + '.svg' );
    doc.exportFile(destFile, ExportType.SVG , options);
    }
    saveFxg = function ( doc, filePath, options, artboardIndex, artboardName ) {
    var destFile = new File( filePath + '.fxg' );
    options.artboardRange = (artboardIndex+1).toString();
    doc.saveAs( destFile, options, artboardIndex, artboardName )
    }




    var multi_exporter = {

    PREFS_LAYER_NAME: "nyt_exporter_info",

    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", copyBehaviour:false, getOptions:getPng8Options, saveFile:savePng8, activeControls:["scalingInput","transCheckBox","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"PNG 24", copyBehaviour:false, getOptions:getPng24Options, saveFile:savePng24, activeControls:["scalingInput","transCheckBox","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"PDF", copyBehaviour:false, getOptions:getPdfOptions, saveFile:savePdf, activeControls:["trimEdgesCheckBox"]},
    {name:"JPG", copyBehaviour:false, getOptions:getJpgOptions, saveFile:saveJpg, activeControls:["scalingInput","trimEdgesCheckBox","innerPaddingCheckBox"]},
    {name:"EPS", copyBehaviour:true, getOptions:getEpsOptions, saveFile:saveEps, activeControls:["embedImageCheckBox","embedFontCheckBox","trimEdgesCheckBox"]},
    {name:"SVG", copyBehaviour:true, getOptions:getSvgOptions, saveFile:saveSvg, activeControls:["embedImageCheckBox","trimEdgesCheckBox"]},
    {name:"FXG 1.0", copyBehaviour:true, getOptions:getFxg1Options, saveFile:saveFxg, activeControls:["trimEdgesCheckBox"]},
    {name:"FXG 2.0", 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();

    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;
    }
    },

    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 ) {

    this.multiExporterPrefs = docRef.layers.add();
    this.multiExporterPrefs.name = this.PREFS_LAYER_NAME;

    var nyt_exporter_info_xml = this.multiExporterPrefs.textFrames.add();

    var saved_data = new XML( '<nyt_prefs></nyt_prefs>' );
    saved_data.appendChild( new XML('<nyt_prefix></nyt_prefix>') );
    saved_data.appendChild( new XML('<nyt_suffix></nyt_suffix>') );
    saved_data.appendChild( new XML('<nyt_base_path>~/Desktop</nyt_base_path>') );
    saved_data.appendChild( new XML('<nyt_scaling>100%</nyt_scaling>') );
    saved_data.appendChild( new XML('<nyt_transparency>true</nyt_transparency>') );
    saved_data.appendChild( new XML('<nyt_embedImage>true</nyt_embedImage>') );
    saved_data.appendChild( new XML('<nyt_embedFont>true</nyt_embedFont>') );
    saved_data.appendChild( new XML('<nyt_trimEdges>true</nyt_trimEdges>') );
    saved_data.appendChild( new XML('<nyt_innerPadding>false</nyt_innerPadding>') );
    saved_data.appendChild( new XML('<nyt_format>PNG 24</nyt_format>') );
    saved_data.appendChild( new XML('<nyt_artboards>all</nyt_artboards>') );
    saved_data.appendChild( new XML('<nyt_layers>all</nyt_layers>') );
    saved_data.appendChild( new XML('<nyt_exportArtboards>false</nyt_exportArtboards>') );
    saved_data.appendChild( new XML('<nyt_ignoreWarnings>false</nyt_ignoreWarnings>') );

    nyt_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.prefix = this.prefs_xml.nyt_prefix;
    this.suffix = this.prefs_xml.nyt_suffix;
    this.base_path = this.prefs_xml.nyt_base_path;
    this.scaling = this.prefs_xml.nyt_scaling;
    this.transparency = this.prefs_xml.nyt_transparency == "true" ? true : false;
    this.embedImage = this.prefs_xml.nyt_embedImage == "true" ? true : false;
    this.ignoreWarnings = this.prefs_xml.nyt_ignoreWarnings == "true" ? true : false;
    this.embedFont = this.prefs_xml.nyt_embedFont == "true" ? true : false;
    this.trimEdges = this.prefs_xml.nyt_trimEdges == "true" ? true : false;
    this.innerPadding = this.prefs_xml.nyt_innerPadding == "true" ? true : false;
    this.format = this.prefs_xml.nyt_format;
    this.artboards = this.prefs_xml.nyt_artboards.toString();
    this.layers = this.prefs_xml.nyt_layers.toString();
    this.whole_artboard_mode = this.prefs_xml.nyt_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.nyt_scaling || this.prefs_xml.nyt_scaling == '' ) {
    this.scaling = '100%';
    }
    parse_success = true;

    } catch ( e ) {
    Window.alert( 'Please delete the this.multiExporterPrefs layer and try again.' );
    }

    }

    return parse_success;
    },


    // 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.oreintation = '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.oreintation = '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);

    // PREFIX GRP
    row = this.dlg.add('group', undefined, '')
    row.oreintation = 'row';
    row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]

    var prefixSt = row.add('statictext', undefined, 'File prefix:');
    prefixSt.size = [100,20]

    this.prefixEt = row.add('edittext', undefined, this.prefix);
    this.prefixEt.size = [ 300,20 ];

    // suffix row
    row = this.dlg.add('group', undefined, '')
    row.oreintation = 'row';
    row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]

    row = this.dlg.add('group', undefined, '')
    row.oreintation = 'row';
    row.alignment = [ScriptUI.Alignment.LEFT, ScriptUI.Alignment.TOP]

    var suffixSt = row.add('statictext', undefined, 'File suffix:');
    suffixSt.size = [100,20]

    this.suffixEt = row.add('edittext', undefined, this.suffix);
    this.suffixEt.size = [ 300,20 ];

    // scaling row
    row = this.dlg.add('group', undefined, '')
    row.oreintation = '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.update_export_desc( );

    this.dlg.progBar = progBar;

    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();
    },
    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.prefix = this.prefixEt.text;
    this.suffix = this.suffixEt.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.nyt_base_path = this.base_path;
    this.prefs_xml.nyt_scaling = this.scaling;
    this.prefs_xml.nyt_prefix = this.prefix;
    this.prefs_xml.nyt_suffix = this.suffix;
    this.prefs_xml.nyt_transparency = this.transparency;
    this.prefs_xml.nyt_embedImage = this.embedImage;
    this.prefs_xml.nyt_ignoreWarnings = this.ignoreWarnings;
    this.prefs_xml.nyt_embedFont = this.embedFont;
    this.prefs_xml.nyt_trimEdges = this.trimEdges;
    this.prefs_xml.nyt_innerPadding = this.innerPadding;
    this.prefs_xml.nyt_format = this.format;
    this.prefs_xml.nyt_artboards = this.artboards;
    this.prefs_xml.nyt_layers = this.layers;
    this.prefs_xml.nyt_exportArtboards = this.whole_artboard_mode;

    this.multiExporterPrefs.textFrames[0].contents = this.prefs_xml.toXMLString();
    },


    // 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.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;
    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();