javascriptscriptingadobeadobe-illustrator

Adding separate artboard for each layer based on the content width using Illustrator scripting


I have already written a code to extract content from a csv file and add each chunk of text on each layer of illustrator. At the moment I could add content for fixed artboard. But I need to add separate art board while keeping the width 23mm. So, artboard height similar to content height of the particular layer. I'm getting an error "TypeError: text.parentArtboard is undefined" Kindly help me to resolve the above issue.

var csv = '''clipName,Trans,fname
A1 ,test Text1,A1_ENG
A2 ,Pigment dyed fabric w.,A2_ENG
A3 ,UPF 50+ fabric. Only covered areas are protected. To maintain this level of protection the garment must be rinsed in fresh water after each use.,A3_ENG
A4 ,Light colours may become transparent when wet,A4_ENG'''



/* var csv_file = File.openDialog();
csv_file.open("r")
var csv = csv_file.read();
csv_file.close() */
var lines = csv.split("\n");


// MAIN -------------------------------------------------------------

// make character styles
var FONT1 = make_style("font1", "ArialMT", 5.5);

// process lines
for (var i=1; i<lines.length; i++) {
    var data = get_data_from(lines[i]);
    make_layer(data.name)
    var text = make_text(data.contents);
    
    apply_styles(text);
    
    put_in_center(text);
     // Create a new artboard
    //artboard()
}

// END

// functions --------------------------------------------------------

function make_style(style_name, font_name, size) {
      // try to add a new style
    try { var style = app.activeDocument.characterStyles.add(style_name) } 
    // or pick a style with the same name if it exists already
    catch(e) { var style = app.activeDocument.characterStyles.getByName(style_name) }
    
    //var style = app.activeDocument.characterStyles.add(style_name);
    style.characterAttributes.size = size;
    style.characterAttributes.textFont = textFonts.getByName(font_name);
    return style;
}

function addArtboard(text, artboardWidth ) {
    // Get all layers in the text
    var layers = text.layers;
    
    // Set the artboard width to 23
    var artboard = text.parentArtboard;
    artboard.width = artboardWidth;
    
    // Declare variable to keep track of content height
    var contentHeight = 0;
    
    // Loop through all layers
    for (var i = 0; i < layers.length; i++) {
        var layer = layers[i];
        
        // Position the layer
        layer.x = 0;
        layer.y = contentHeight;
        
        // Update content height
        contentHeight += layer.height;
    }
    
    // Set the artboard height based on the content height
    artboard.height = contentHeight;
}

function get_data_from(line) {
    
    var arr = line.split(",");
    var fname = arr[2]
    var VL1   = arr[0];
    var VL2   = arr[1];
    //alert("Your message here...", fname);
    //return {"name":Fname, "contents":[VL1, VL2, VL3, VL4,VL5, VL6, VL7, VL8, VL9]};
    return {"name":fname, "contents":[VL2]};
}
//string.includes(substring)
function rearrangeText(text, artboardWidth) {
  // Split the text into words
  var words = text.split(" ");
  var rearrangedText = "";
  var currentLine = "";
  
  // Loop through each word
  for (var i = 0; i < words.length; i++) {
    var word = words[i];
    // If the current line + the next word would exceed the artboard width
    if (currentLine.length + word.length > artboardWidth) {
      // Add the current line to the rearranged text
      rearrangedText += currentLine + "\n";
      // Reset the current line
      currentLine = "";
    }
    // Add the word to the current line
    currentLine += word + " ";
  }
  // Add the last line to the rearranged text
  rearrangedText += currentLine;
  return rearrangedText;
}

    
function make_layer(layer_name) {
    var new_layer = app.activeDocument.layers.add();
    new_layer.name = layer_name;
}

function make_text(array) {
    var text = app.activeDocument.textFrames.add();
        text.contents = rearrangeText(array.join("\n"),23);
         addArtboard(text.contents,23) //Try to add new artboar based on the text content size
    return text;
}
function artboard() {
    var layers = app.activeDocument.layers;
    var textLayers = [];
    for (var i = 0; i < layers.length; i++) {
        if (layers[i].kind == LayerKind.TEXT) {
            textLayers.push(layers[i]);
        }
    }
    var width = 23; // width in mm
    for (var i = 0; i < textLayers.length; i++) {
        var textLayer = textLayers[i];
        var textBounds = textLayer.bounds;
        var artboardWidth = width * app.activeDocument.rulerUnits;
        var artboardHeight = textBounds[3] - textBounds[1];
        var artboard = app.activeDocument.artboards.add(textBounds);
        artboard.width = artboardWidth;
        artboard.height = artboardHeight;
        textLayer.move(artboard);
    }
}


function to_center(artboard, item){
    var artboard_x = artboard.artboardRect[0] + artboard.artboardRect[2];
    var artboard_y = artboard.artboardRect[1] + artboard.artboardRect[3];
    var x = (artboard_x - item.width)/2;
    var y = (artboard_y + item.height)/2;
    item.position = [x, y];
}

function apply_styles(text) {
    // not the best piece of code, I'm sure it can be done better
    text.textRange.paragraphAttributes.justification = Justification.CENTER;
    FONT1.applyTo(text.textRange);

 
}

function put_in_center(obj) {
    var rect = app.activeDocument.artboards[0].artboardRect;
    var page_w = rect[2] - rect[0];
    var page_h = rect[1] - rect[3];
    var shift_x = page_w/2 - obj.width/2;
    var shift_y = -page_h/2 + obj.height/2;
    obj.position = [rect[0] + shift_x, rect[1] + shift_y];
}

When I remove the function addArtboard(text, artboardWidth ) all content will be nicely rearrange based on the width of the artboard. But, artboard size doesn't change due to the code error. Experts kindly help me with this. Image of the content arrangement on illustrator layers are mention below

enter image description here


Solution

  • If understand the task correctly you can add this function into the code:

    function distribute_texts_and_create_artboards() {
    
        const mm    = 2.83465;   // mm/pt
        var shift_x = 30 * mm;   // horizontal shifts for texts
        var width   = 25 * mm;   // artboard width
    
        var doc = app.activeDocument;
        var frames = doc.textFrames;
    
        // move all the frames and create an artboard for the every text frame
    
        for (var i=0; i<frames.length; i++) {
    
            var frame = frames[i];
            frame.translate(shift_x * i, 0); // move the frame horizontally
    
            var frame_x1 = frame.geometricBounds[0];
            var frame_y1 = frame.geometricBounds[1];
            var frame_x2 = frame.geometricBounds[2];
            var frame_y2 = frame.geometricBounds[3];
    
            var artboard_x = frame_x1 - (width - frame.width)/2;
            var artboard_y = frame_y1;
            var artboard_w = frame_x2 + (width - frame.width)/2;
            var artboard_h = frame.height;
    
            var artboard_rect = [artboard_x, artboard_y, artboard_w, -artboard_h];
            var new_ab = doc.artboards.add(artboard_rect); // create a new artboard
            new_ab.name = frame.parent.name; // artboard name = layer name
    
            // frame.position = [frame.position[0], frame.position[1]/2]; // to centred the frame vertically
        }
    
        doc.artboards[0].remove(); // delete the old first artboard
    }
    

    and call it at the end of the 'MAIN' section:

    ...
    }
    
    distribute_texts_and_create_artboards();
    
    // END
    
    ...
    

    and comment out the line:

    // put_in_center(text);
    

    It should give you the layout as follows:

    enter image description here

    Probably it makes sense to tweak the vertical position of the frames of the artboards a bit. But since you haven't provided an example of desired result I left it as is, for now. Let me know if you need it or uncomment the line:

    frame.position = [frame.position[0], frame.position[1]/2];
    

    And you don't need the functions addArtboard() and artboard() anymore in the code.


    Update

    Here is the function that saves all the text frames from layers as separate PDFs into the same folder as current AI file. File names are the same as layer names.

    function save_layers_as_pdfs() {
        var doc = app.activeDocument;
    
        // pdf options
        var options = new PDFSaveOptions();
        options.compatibility = PDFCompatibility.ACROBAT5;
        options.generateThumbnails = true;
        options.preserveEditability = false;
        options.preset = "[Smallest File Size]";
    
        var mm = 2.83465;     // mm/pt
        var width = 25 * mm;  // artboard width
    
        var layers = doc.layers;
        for (var i=0; i<layers.length; i++) {
            var layer = layers[i];
            layer.hasSelectedArtwork = true;
            if (app.selection.length == 0) continue;
            app.copy();
            app.selection = null;
    
            // create a new file
            var file = File(doc.path + '/' + layer.name + '.pdf');
            var new_doc = app.documents.add();
            app.paste();
    
            // change the artboard size
            var frame = new_doc.textFrames[0];
    
            var frame_x1 = frame.geometricBounds[0];
            var frame_y1 = frame.geometricBounds[1];
            var frame_x2 = frame.geometricBounds[2];
            var frame_y2 = frame.geometricBounds[3];
    
            var artboard_x = frame_x1 - (width - frame.width)/2;
            var artboard_y = frame_y1;
            var artboard_w = frame_x1 + frame.width + (width - frame.width)/2;
            var artboard_h = frame_y1 - frame.height;
    
            doc.artboards[0].artboardRect = [artboard_x, artboard_y, artboard_w, artboard_h];
    
            // save a pdf and close document
            new_doc.saveAs(file, options);
            new_doc.close(SaveOptions.DONOTSAVECHANGES);
        }
    }
    

    You can call this function at the end of the MAIN section.

    The result:

    enter image description here

    And make sure your csv data is correct: the separators, quote marks, tabulations, etc.