Hi, I'm Brian Reavis.
I'm a Web Engineer at Creative Market. I love mountains.

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.

Copyright © 2013 – Brian Reavis. All rights reserved. The views expressed here are my own and do not necessarily reflect the views of Creative Market.