JSX scripting makes controlling Adobe Creative Suite from an extension you’re developing a breeze. Scripting opens up the realm of creating guides, selecting tools, creating layers, running filters, and so on. To get you started, Adobe Extension Builder creates a basic *.jsx file with a sample function in every new project:
function jsxFunction() { // ... your code goes here ... return '<object><property id="success"><true /></property></object>'; } |
To call that function from AS3, it’s easy:
var result:SyncResult = CSXSInterface.instance.evalScript('jsxFunction'); |
The Workflow
First, install the Scripting Listener plugin. With it installed, whenever you do something in Photoshop/Illustrator/etc, it will write the code needed to perform those steps to ScriptingListenerJS.log on your desktop. Copy the parts you need from there and put them in your *.jsx file, wrapped in a function. Then just call evalScript() with the function name, and you’re good!
Function Arguments
Sometimes you might need to pass a value to a JSX function from AS3—maybe it’s a coordinate, maybe it’s the path of a file, maybe it’s a color. Arguments is where life gets janky. In CS4 products, only one argument is supported. And in CS5+, certain characters like quotation marks and backslashes will cause a PlugPlugRequestFailed status—for no valid reason.
The solution? Feed evalScript() arguments as if you’re feeding a bird masticated baby food. Concatenate your arguments and hex-encode them. This will prevent mysteriously-forbidden characters and bypass CS4′s limit of only one argument.
Encoding Arguments in AS3
public class JSXArguments { public static function encode(arguments:Array):String { return hexEncode(arguments.join('__:__')); } private static function hexEncode(str:String):String { var result:String = ''; var hex:String; var i:int = 0; while (i < str.length) { hex = str.charCodeAt(i++).toString(16); while (hex.length < 3) hex = '0' + hex; result += hex; } return result; } } // example usage: CSXSInterface.instance.evalScript('doSomething', JSXArguments.encode( [1, 2, 'Hel/lo\\ Wo/rld!'] )); |
For simplicity’s sake, this only supports basic integral types—ints, floats, strings. Furthermore, when you use your arguments in your JSX script (explained below), they’ll be strings. So if you want to preserve a number, you’ll have to call parseInt or parseFloat to convert it. If you need to pass objects or arrays, you’ll need to get fancy and serialize them before hex-encoding—JSON.encode works wonders.
Decoding Arguments in the JSX Script
function decodeArgs(argStr) { if (argStr) { var decodedArgs = ''; for (var i = 0; i < argStr.length; i += 3) { decodedArgs += String.fromCharCode('0x' + argStr.substring(i, i + 3)); } return decodedArgs.split('__:__'); } return []; } // example usage: function doSomething(encodedArgs) { var args = decodeArgs(encodedArgs); var x = parseInt(args[0]); // 1 var y = parseInt(args[1]); // 2 var message = args[2]; // "Hel/lo\\ Wo/rld!" // ... } |
Wrap-up
Scripting opens up tons to your extension—there are just a few bizarre quirks to work around. Hopefully this guide helps! If anything written here is fuzzy or could be elaborated on, please ping me on Twitter.