Skip to main content
Inspiring
May 13, 2024
Answered

JavaScript to copy text from one Illustrator file to another Illustrator file

  • May 13, 2024
  • 1 reply
  • 3144 views

I have this ExtendScript to copy text from one Illustrator file to another Illustrator file. The data in the illustrator file is on different layers. The template has text-frames on separate layers. The script copies the text from one layer of the Data file and pastes it into the text frame matching the source layer. i.e. the Data and the Template files have the same layer structure. If any layer is missing, in the Template file, then that text is ignored and doesn't get copied.

 

Now, I have a different situation:

Data File:

1) The entire text is on a single layer called 'excel data'. The text is distributed in multiple text frames. Each text-frame has specific text and are tagged accordingly. This can be viewed by twirl-opening the layer in the layer panel.

 

Template File:

2) The template has text frames all over the artwork. The text frames contains tag-names as text. All the text frames in the template are on one singel layer called 'artwork'.

3) The order of the layer or text-frame is not fixed.

 

I want a Javascript (modified version of my current script) to read the data from the Data file and paste it into the requisite text-frame in the Template file.

 

Link to Illustrator files:
https://drive.google.com/drive/folders/136h80mYPvTJLxQRw1hQCHDDyqULZ8aHc?usp=sharing

 

Please let me know if more details are required.

 

Here's my current script.

// Script to copy Text from Illustrator file and pasting into the Illustrator Template File.

// PREREQUISITES:
// Illustrator Data file containing data on different layers. Layer names should match the layer names in the Template file.
// Illustrator Template file, containing Text-Frames to get text from the Data file. Text-Frames should be on the specic layer matching the layer names as that in the Data file. For example:
// Data File layer name: 'Main Text'
// Template File Layer name: Text Frame placed on the 'Main Text' layer.

function showDialog() {
  var dialog = new Window(
    'dialog',
    'Copy/Paste Text between Illustrator File(s)'
  );
  dialog.alignChildren = 'fill';
  dialog.alignChildren = 'left';

  // Panel for template file selection
  var templateFilePanel = dialog.add('panel', undefined, '');
  templateFilePanel.add('statictext', undefined, 'Template File:');
  templateFilePanel.orientation = 'row';
  var templateFilePathInput = templateFilePanel.add('edittext', undefined, '', {
    readonly: true
  });
  templateFilePathInput.size = [302, 20];
  var templateFileBrowseBtn = templateFilePanel.add(
    'button',
    undefined,
    'Browse'
  );
  templateFileBrowseBtn.onClick = function() {
    var file = File.openDialog('Select the Template File', '*.ai', false);
    if (file) {
      templateFilePathInput.text = file.fsName;
    }
  };

  // Panel for data file selection
  var dataFilePanel = dialog.add('panel', undefined, '');
  dataFilePanel.add('statictext', undefined, 'Data File:');
  dataFilePanel.orientation = 'row';
  var dataFilePathInput = dataFilePanel.add('edittext', undefined, '', {
    readonly: true
  });
  dataFilePathInput.size = [330, 20];
  var dataFileBrowseBtn = dataFilePanel.add('button', undefined, 'Browse');
  dataFileBrowseBtn.onClick = function() {
    var file = File.openDialog('Select the Data File', '*.ai', false);
    if (file) {
      dataFilePathInput.text = file.fsName;
    }
  };

  // Panel for output folder selection
  var outputPanel = dialog.add('panel', undefined, '');
  outputPanel.add('statictext', undefined, 'Select Folder to Save New File:');
  outputPanel.orientation = 'row';
  var outputPathInput = outputPanel.add('edittext', undefined, '', {
    readonly: true
  });
  outputPathInput.size = [210, 20];
  var outputBrowseBtn = outputPanel.add('button', undefined, 'Browse');
  outputBrowseBtn.onClick = function() {
    var folder = Folder.selectDialog('Select Folder to Save New File');
    if (folder) {
      outputPathInput.text = folder.fsName;
    }
  };

  // Dialog buttons
  var buttonGroup = dialog.add('group');
  buttonGroup.alignment = 'center';
  buttonGroup.add('button', undefined, 'OK', { name: 'ok' });
  buttonGroup.add('button', undefined, 'Cancel', { name: 'cancel' });

  if (dialog.show() === 1) {
    // User clicked OK
    return {
      dataFilePath: dataFilePathInput.text,
      templateFilePath: templateFilePathInput.text,
      outputPath: outputPathInput.text
    };
  } else {
    return null; // User clicked Cancel or closed the dialog
  }
}

// Function to copy data from source to target based on layer names
function transferData(source, target) {
  // Create a dictionary to check target layers quickly
  var targetLayerNames = {};
  for (var k = 0; k < target.layers.length; k++) {
    targetLayerNames[target.layers[k].name] = target.layers[k];
  }

  // Iterate over each layer in the source document
  for (var i = 0; i < source.layers.length; i++) {
    var sourceLayer = source.layers[i];
    // Check if the layer exists in the target document by looking up the dictionary
    if (targetLayerNames.hasOwnProperty(sourceLayer.name)) {
      var targetLayer = targetLayerNames[sourceLayer.name];

      // Iterate over each text frame in the source layer
      for (var j = 0; j < sourceLayer.textFrames.length; j++) {
        if (j < targetLayer.textFrames.length) {
          // Copy text from source to target if corresponding text frame exists
          var sourceText = sourceLayer.textFrames[j];
          var targetText = targetLayer.textFrames[j];
          targetText.contents = sourceText.contents;
        } else {
          // Log error or information when source has more text frames than target
          $.writeln(
            "Info: Additional text frame in source layer '" +
              sourceLayer.name +
              "' at position " +
              j +
              ' has no corresponding frame in target.'
          );
        }
      }
    } else {
      // Log information when no corresponding layer is found in the target document
      $.writeln(
        "Info: No corresponding layer found in target for source layer '" +
          sourceLayer.name +
          "'. Layer ignored."
      );
    }
  }
}

function main() {
  var fileSelections = showDialog();
  if (fileSelections) {
    var dataDoc = app.open(File(fileSelections.dataFilePath)); // Open the selected data file
    var templateDoc = app.open(File(fileSelections.templateFilePath)); // Open the selected template file
    transferData(dataDoc, templateDoc); // Run the transfer function

    // Save the new document
    var dataFileName = decodeURI(File(fileSelections.dataFilePath).name);

    // To save as 'templateFileName_dataFileName.ai'
    var templateFileName = decodeURI(
      File(fileSelections.templateFilePath).name
    );
    var newFileName = templateFileName.replace('.ai', '') + '_' + dataFileName;

    // // To save as 'dataFileName.ai_Output'
    // var newFileName = dataFileName.replace('.ai', '') + '_Output';

    var saveFile = new File(fileSelections.outputPath + '/' + newFileName);
    templateDoc.saveAs(saveFile);

    templateDoc.close();
    dataDoc.close();
    alert('Data successfully transferred and file saved as: \n' + newFileName);
  }
}

main();

 

This topic has been closed for replies.
Correct answer code_seeeeeker

So, the updated snippet I shared should work no matter the layer order from one file to the other.

 

The script simply goes through the data file and builds a dictionary of every textFrame. The dictionary keys are the "tag" names and the dictionary values are the corresponding text content from the textFrame. The script then goes through every textFrame inside of the template file and checks within the dictionary to see if there is a matching "tag". If there is a match, the text contents of the matching textFrame are updated to text from the data file.

 

If the script encounters a "tag" (textFrame name) inside of the template file that doesn't correspond to a key in the dictionary it just skips it. This means you "tags" must be identical (including letter case) between files but the actual order doesn't matter.

 

Now, if you have a different data file layout, this script will not work as it was designed to work with the initial files you provided.


Thanks, for looking into it, however, I'm experiencing something different, Please see the latest OUTPUT file here:
https://drive.google.com/drive/folders/15cPTmTC-u5dkYk6TOm68y6WZC8sOiCXq?usp=drive_link

I have encircled the areas where the data didn't get transferred.

1 reply

femkeblanco
Legend
May 13, 2024

So the only difference is that iterating and checking layers is no longer required, all the text frames being in one layer in the source (excel data) and target (artwork)?  If so, see if this works (I've added two lines, 95 and 96, and commented-out the loop and conditional immediately below): 

function showDialog() {
  var dialog = new Window(
    'dialog',
    'Copy/Paste Text between Illustrator File(s)'
  );
  dialog.alignChildren = 'fill';
  dialog.alignChildren = 'left';

  // Panel for template file selection
  var templateFilePanel = dialog.add('panel', undefined, '');
  templateFilePanel.add('statictext', undefined, 'Template File:');
  templateFilePanel.orientation = 'row';
  var templateFilePathInput = templateFilePanel.add('edittext', undefined, '', {
    readonly: true
  });
  templateFilePathInput.size = [302, 20];
  var templateFileBrowseBtn = templateFilePanel.add(
    'button',
    undefined,
    'Browse'
  );
  templateFileBrowseBtn.onClick = function() {
    var file = File.openDialog('Select the Template File', '*.ai', false);
    if (file) {
      templateFilePathInput.text = file.fsName;
    }
  };

  // Panel for data file selection
  var dataFilePanel = dialog.add('panel', undefined, '');
  dataFilePanel.add('statictext', undefined, 'Data File:');
  dataFilePanel.orientation = 'row';
  var dataFilePathInput = dataFilePanel.add('edittext', undefined, '', {
    readonly: true
  });
  dataFilePathInput.size = [330, 20];
  var dataFileBrowseBtn = dataFilePanel.add('button', undefined, 'Browse');
  dataFileBrowseBtn.onClick = function() {
    var file = File.openDialog('Select the Data File', '*.ai', false);
    if (file) {
      dataFilePathInput.text = file.fsName;
    }
  };

  // Panel for output folder selection
  var outputPanel = dialog.add('panel', undefined, '');
  outputPanel.add('statictext', undefined, 'Select Folder to Save New File:');
  outputPanel.orientation = 'row';
  var outputPathInput = outputPanel.add('edittext', undefined, '', {
    readonly: true
  });
  outputPathInput.size = [210, 20];
  var outputBrowseBtn = outputPanel.add('button', undefined, 'Browse');
  outputBrowseBtn.onClick = function() {
    var folder = Folder.selectDialog('Select Folder to Save New File');
    if (folder) {
      outputPathInput.text = folder.fsName;
    }
  };

  // Dialog buttons
  var buttonGroup = dialog.add('group');
  buttonGroup.alignment = 'center';
  buttonGroup.add('button', undefined, 'OK', { name: 'ok' });
  buttonGroup.add('button', undefined, 'Cancel', { name: 'cancel' });

  if (dialog.show() === 1) {
    // User clicked OK
    return {
      dataFilePath: dataFilePathInput.text,
      templateFilePath: templateFilePathInput.text,
      outputPath: outputPathInput.text
    };
  } else {
    return null; // User clicked Cancel or closed the dialog
  }
}

// Function to copy data from source to target based on layer names
function transferData(source, target) {
  // Create a dictionary to check target layers quickly
  var targetLayerNames = {};
  for (var k = 0; k < target.layers.length; k++) {
    targetLayerNames[target.layers[k].name] = target.layers[k];
  }

  var sourceLayer = source.layers["excel data"];
  var targetLayer = target.layers["artwork"];
  // Iterate over each layer in the source document
  // for (var i = 0; i < source.layers.length; i++) {
  //   var sourceLayer = source.layers[i];
    // Check if the layer exists in the target document by looking up the dictionary
    // if (targetLayerNames.hasOwnProperty(sourceLayer.name)) {
    //   var targetLayer = targetLayerNames[sourceLayer.name];

      // Iterate over each text frame in the source layer
      for (var j = 0; j < sourceLayer.textFrames.length; j++) {
        if (j < targetLayer.textFrames.length) {
          // Copy text from source to target if corresponding text frame exists
          var sourceText = sourceLayer.textFrames[j];
          var targetText = targetLayer.textFrames[j];
          targetText.contents = sourceText.contents;
        } else {
          // Log error or information when source has more text frames than target
          $.writeln(
            "Info: Additional text frame in source layer '" +
              sourceLayer.name +
              "' at position " +
              j +
              ' has no corresponding frame in target.'
          );
        }
      }
    // } else {
    //   // Log information when no corresponding layer is found in the target document
    //   $.writeln(
    //     "Info: No corresponding layer found in target for source layer '" +
    //       sourceLayer.name +
    //       "'. Layer ignored."
    //   );
    // }
  // }
}

function main() {
  var fileSelections = showDialog();
  if (fileSelections) {
    var dataDoc = app.open(File(fileSelections.dataFilePath)); // Open the selected data file
    var templateDoc = app.open(File(fileSelections.templateFilePath)); // Open the selected template file
    transferData(dataDoc, templateDoc); // Run the transfer function

    // Save the new document
    var dataFileName = decodeURI(File(fileSelections.dataFilePath).name);

    // To save as 'templateFileName_dataFileName.ai'
    var templateFileName = decodeURI(
      File(fileSelections.templateFilePath).name
    );
    var newFileName = templateFileName.replace('.ai', '') + '_' + dataFileName;

    // // To save as 'dataFileName.ai_Output'
    // var newFileName = dataFileName.replace('.ai', '') + '_Output';

    var saveFile = new File(fileSelections.outputPath + '/' + newFileName);
    templateDoc.saveAs(saveFile);

    templateDoc.close();
    dataDoc.close();
    alert('Data successfully transferred and file saved as: \n' + newFileName);
  }
}

main();
Inspiring
May 14, 2024

Thanks, this is closer to what I was looking. But I noticed that the script didn't work efficiently. Some data didn't transfer and some came wrong. For example. in the Template, there are multiple text frames for tag-names like Brand, Guarantee, etc. Text-frames for 'BOP_Text[cs]', and 'Brand' didn't get the new copy, whereas, the text for 'Guarantee' came in correct. The other placeholder text-frame for 'Barcode' get wrong text.

Here are the Before and After snapshots for your review, and thanks in advance for all your cooperation.



Inspiring
May 15, 2024

Any suggestions, please