zondag 2 maart 2014

Scripts generating scripts - javascript and illustrator

I think I've found a new workflow that may not be new, but might be new to some.
I had the problem of having to generate a lot (3800) of files in illustrator.
These files had elements that would be generated  (by Flash) and had to be integrated into ai files.
Also I had to present it in HTML5 using x3Dom to get an idea of what I was doing.

Now I had made a as3 program, that took in 3D data from Rhino. (We just exported point and bi-arcs in text from Rhino) My script in Flash converted this data into 2D files vector that could be used as textures (when stamped down to PNG's).
We used the PNG-textures for the preview in HTML5, so we could walk through the textured building (this was for an architect), but we also needed the (vector) textures to be saved in a format that a printer could work with, we setlled on PDF, which I could generate from Flash with a library..

First step: generating JS from Flash for a Preview:
I had already interpreted the bi-arcs in Flash, so to do it again in Javascript wouldn't be much of a problem, but it turned out to be easier, to generate the javascript from Flash.
This way, I could spend my time elaborating on the data where I needed it and and leaving out what wasn't important.

Second Step: generating a JS script to generate files in Adobe Illustrator:
Although we first decided the output would be PDF, because the library did not export layers in the PDF page and because spot-colors were a problem, it turned out to be easier for the printer to get AI files instead.
I was able to comply, by doing the same trick again. I used Flash, to generate Javascript (JSX) that extends adobe illustrator and uses it to generate illustrator files.
(My basic generation script, without the parts generated by Flash is below)

This last step seems a quite promising development. We could go from Rhino (a scripted environment) to Flash (a scripted environment) and then use Illustrator to generate print-ready files (in again a scripted environment).
This means, that this workflow could be very helpfull for anyone with the same kind of problem.

Photoshop, In Design and Illustrator all support javascript extensions for scripting. In stead of going through actionscript (flash) to generate the scripts to extend illustrator, I could have used Javascript to generate the same. Also Adobe makes a point of supporting applescript and VBscript as well.
This enables the developer (or scripter) to do his work and most of the debugging in the environment he's most comfortable with and then exporting to whatever environment he wants. It may seem a bit cumbersome at first, but I assure you, once you get your head around it, it's VERY flexible.

One word of caution: Debugging jsx in illustrator sucks. So get a working script and let your script modify it to just add the data.

Here is a tutorial to get you started:
http://creativedroplets.com/tutorial-scripting-for-illustrator-cs6/

There is a LOT of support for scripts from adobe:
http://www.adobe.com/devnet/illustrator/scripting.html

And it's actually well documented this time. It only took me a few hours to write my generation script, which was my first script ever.This was a very nice surprise. Even though I'm not all that familiar with Adobe Illustrator, I had no trouble finding specific things like information about layers and spotcolors. I actually learned a few things about the way illustrator is put together.

I've bitched about Adobe's lack of vision in the past when compared to the things Macromedia used to do (and I'm still behind everything I said), but this seems a very promising new direction, which could result in a very active community.
When something is good, it needs to be said as well: Well done Adobe.

Just to be complete, here is my basic rendering and generation script.
I use Flash to create the data this script will use to generate ai-files, with two layers and two spot-colors.
It's been scrounged together from various sources offcourse, but it will tell you all you need to do, if you just want to generate ai-files by drawing paths into them.

To get you started, copy it into a text-file. name it jsx. The go to illustrator, choose scripts from the menu.
Navigate to the script and select it.
It will ask you to find a directory and it will put three files in it with generated content.
It's well commented, so it should be enough to get you started on your own.
If you like it, drop me a comment, to tell me what you made :)

/**********************************************************

Basic Generation script for illustrator made by Hjalmar with Flash...

*********************************************************/

/** 
 Creates a new document, 
 draws a baffle and 
 Saves every document as AI
*/

// Main Code [Execution of script begins here]

try {
 
 // Get the folder to save the files into
 var destFolder = null;
 destFolder = Folder.selectDialog( 'Select folder for AI files.', '~' );

 if (destFolder != null) 
 {
  var options, i, activeDoc, targetFile; 
  
  // Get the PDF options to be used
     
  for ( i = 0; i < 3; i++ ) 
  {
   // create a document!
   // Preset
   var doc_preset = new DocumentPreset;
   doc_preset.units = RulerUnits.Centimeters; // normal is .Inches;
   var activeDoc = app.documents.addDocument(DocumentColorSpace.CMYK, doc_preset); // add document
         
   // Get the file to save the document as ai into
   targetFile = this.getTargetFile("baffle_"+i, '.ai', destFolder);
   
   // set up the layers!
   var plotterLayer = activeDoc.activeLayer; // there's one made automatically, so we use that one... activeDoc.layers.add();
   plotterLayer.name = "cutcontour";
   var artLayer = activeDoc.layers.add();
   artLayer.name = "stationsblauw";

   // create all colors
   // Define the new color values in CMYK, but we are going to make them spot colors!
   CMYKblue = new CMYKColor();
   CMYKblue.black = 50.0;
   CMYKblue.cyan = 80.4;
   CMYKblue.magenta = 0;
   CMYKblue.yellow = 0;

   CMYKline = new CMYKColor();
   CMYKline.black = 0;
   CMYKline.cyan = 0.0;
   CMYKline.magenta = 32;
   CMYKline.yellow = 32;
   
   // Use the CMYK color object in the creation of spots
   // Create the new spots
   var blauwspot = app.activeDocument.spots.add();
   blauwspot.name = "stationsblauw";
   blauwspot.tint = 100;
   blauwspot.color = CMYKblue;
   
   var linespot = app.activeDocument.spots.add();
   linespot.name = "cutcontour";
   linespot.tint = 100;
   linespot.color = CMYKline;
   
   // Create a spotcolor objects, set the tint value,
   var spotBlue = new SpotColor();
   spotBlue.spot = blauwspot;
   spotBlue.tint = 100;

   var spotLine = new SpotColor();
   spotLine.spot = linespot;
   spotLine.tint = 100;

   // set the outline path as part of the plotterLayer!
   
   // Use the spot color to set the fill color
   var myLine = plotterLayer.pathItems.add();
   //set stroked to true so we can see the path
   myLine.stroked = true;
   myLine.strokeColor = spotLine;
   myLine.closed = true;
   myLine.setEntirePath([[220, 475], [375, 300], [200, 300]]);

   for(t=0;t<10;t++)
   {
    // draw a square on a random place on the artLayer
    var tbp = artLayer.pathItems.add();
    tbp.stroked = false;
    tbp.filled = true;
    tbp.fillColor = spotBlue;
    var tx=250+Math.random()*50;
    var ty=250+Math.random()*50;
    tbp.setEntirePath([[tx, ty], [tx+5, ty], [tx+5, ty+5],[tx, ty+5]]);
   }
   // Save as ai
   var saveOptions = new IllustratorSaveOptions();
   saveOptions.compatibility = Compatibility.ILLUSTRATOR8;
   saveOptions.flattenOutput = OutputFlattening.PRESERVEAPPEARANCE;
   app.activeDocument.saveAs( targetFile, saveOptions );  
   
   // we close the doc to save memory!
   app.activeDocument.close();
   
   //alert( 'Document saved as AI' );
  }
 }else
 {
  throw new Error('No folder selected');
 }
}
catch(e) {
 alert( e.message, "Script Alert", true);
}


/** Returns the file to save or export the document into.
 @param docName the name of the document
 @param ext the extension the file extension to be applied
 @param destFolder the output folder
 @return File object
*/
function getTargetFile(docName, ext, destFolder) {
 var newName = "";

 // if name has no dot (and hence no extension),
 // just append the extension
 if (docName.indexOf('.') < 0) {
  newName = docName + ext;
 } else {
  var dot = docName.lastIndexOf('.');
  newName += docName.substring(0, dot);
  newName += ext;
 }
 
 // Create the file object to save to
 var myFile = new File( destFolder + '/' + newName );
 
 // Preflight access rights
 if (myFile.open("w")) {
  myFile.close();
 }
 else {
  throw new Error('Access is denied');
 }
 return myFile;
}