Made a two-way AIA to JSON converter
I've always disliked working with Actions in Illustrator scripting and it's always bothered me that even though many things we need in scripting are achievable through actions, the scripting API's use of them is extremely basic and not fleshed out. We only really have 3 interactions: whether to load, unload, or execute obscurely formatted text. A while back I began brainstorming a new API for them but was too frustrated I was only 99% done and couldn't perfect it in order to share.
A typical example of AIA text:
/version 3
/name [ 12
5465737420416374696f6e73
]
/isOpen 1
/actionCount 3
/action-1 {
/name [ 22
4f706163697479203630202873656c656374696f6e29
]
/keyIndex 0
/colorIndex 7
/isOpen 0
/eventCount 1
/event-1 {
/useRulersIn1stQuadrant 1
/internalName (ai_plugin_transparency)
/localizedName [ 12
5472616e73706172656e6379
]
/isOpen 0
/isOn 1
/hasDialog 0
/parameterCount 1
/parameter-1 {
/key 1869635939
/showInPalette 1
/type (unit real)
/value 60.0000038147
/unit 592474723
}
}
}
/action-2 {
/name [ 11
41646420416e63686f7273
]
/keyIndex 53
/colorIndex 0
/isOpen 0
/eventCount 1
/event-1 {
/useRulersIn1stQuadrant 0
/internalName (ai_plugin_AddAnchorPoint)
/localizedName [ 17
41646420416e63686f7220506f696e7473
]
/isOpen 0
/isOn 1
/hasDialog 0
/parameterCount 0
}
}
/action-3 {
/name [ 8
5365742046696c6c
]
/keyIndex 0
/colorIndex 0
/isOpen 0
/eventCount 1
/event-1 {
/useRulersIn1stQuadrant 0
/internalName (ai_plugin_setColor)
/localizedName [ 9
53657420636f6c6f72
]
/isOpen 1
/isOn 1
/hasDialog 0
/parameterCount 6
/parameter-1 {
/key 1768186740
/showInPalette -1
/type (ustring)
/value [ 10
46696c6c20636f6c6f72
]
}
/parameter-2 {
/key 1718185068
/showInPalette -1
/type (boolean)
/value 1
}
/parameter-3 {
/key 1954115685
/showInPalette -1
/type (enumerated)
/name [ 9
52474220636f6c6f72
]
/value 2
}
/parameter-4 {
/key 1919247406
/showInPalette -1
/type (real)
/value 221.0
}
/parameter-5 {
/key 1735550318
/showInPalette -1
/type (real)
/value 0.0
}
/parameter-6 {
/key 1651275109
/showInPalette -1
/type (real)
/value 0.0
}
}
}
When ran with the ActionSuite.js:
#include "../ActionSuite.js";
var testActions = new ActionSet(new File("~/desktop/sample.aia"))
var actionsAsJSON = testActions.toJSON();
Becomes:
{
"version": 3,
"name": "Test Actions",
"isOpen": 1,
"actionCount": 3,
"actions": [
{
"name": "Opacity 60 (selection)",
"keyIndex": 0,
"colorIndex": 7,
"isOpen": 0,
"eventCount": 1,
"events": [
{
"useRulersIn1stQuadrant": 1,
"internalName": "(ai_plugin_transparency)",
"localizedName": "Transparency",
"isOpen": 0,
"isOn": 1,
"hasDialog": 0,
"parameterCount": 1,
"parameters": [
{
"key": "opac",
"showInPalette": 1,
"type": "(unit real)",
"value": 60.0000038147,
"unit": 592474723
}
]
}
]
},
{
"name": "Add Anchors",
"keyIndex": 53,
"colorIndex": 0,
"isOpen": 0,
"eventCount": 1,
"events": [
{
"useRulersIn1stQuadrant": 0,
"internalName": "(ai_plugin_AddAnchorPoint)",
"localizedName": "Add Anchor Points",
"isOpen": 0,
"isOn": 1,
"hasDialog": 0,
"parameterCount": 0
}
]
},
{
"name": "Set Fill",
"keyIndex": 0,
"colorIndex": 0,
"isOpen": 0,
"eventCount": 1,
"events": [
{
"useRulersIn1stQuadrant": 0,
"internalName": "(ai_plugin_setColor)",
"localizedName": "Set color",
"isOpen": 1,
"isOn": 1,
"hasDialog": 0,
"parameterCount": 6,
"parameters": [
{
"key": "idct",
"showInPalette": -1,
"type": "(ustring)",
"value": "Fill color"
},
{
"key": "fill",
"showInPalette": -1,
"type": "(boolean)",
"value": 1
},
{
"key": "type",
"showInPalette": -1,
"type": "(enumerated)",
"name": "RGB color",
"value": 2
},
{
"key": "red.",
"showInPalette": -1,
"type": "(real)",
"value": 221
},
{
"key": "gren",
"showInPalette": -1,
"type": "(real)",
"value": 0
},
{ "key": "blue", "showInPalette": -1, "type": "(real)", "value": 0 }
]
}
]
}
]
}
Completely decoded and human-readable. The goal here was to allow scripting to create and run dynamic actions on the fly, and to be able to further understand parameters of Actions that seemed too obscure to fit to our needs while giving it a more familiar interface modeled on the already existing API of scripting:
// We should be able to load actions easily from a given file:
var mySet = new ActionSet(new File(Folder.desktop + "/someActionSet.aia"));
// And then just run one instantly:
mySet.actions.run("export300dpiJPEG");
// If we want to load them and save this set for the user:
mySet.load(); // it should be this easy
And the ability to create them dynamically on the fly:
var myActionSet = new ActionSet("Sample");
var myAction = new Action("recolorit");
myAction.events.add(
new ActionEvent({
localizedName: "selectAll",
internalName: "(adobe_selectAll)",
hasDialog: 0,
}),
new ActionEvent({
localizedName: "Set color",
internalName: "(adobe_plugin_setColor)",
parameters: [
new ActionParam({ key: "Set color", value: "idct" }),
new ActionParam({ key: "Fill color", value: "fill" }),
new ActionParam({ key: "type", value: "RGB color" }),
new ActionParam({ key: "red.", value: 255 }),
new ActionParam({ key: "gren", value: 50 }),
new ActionParam({ key: "blue", value: 0 }),
],
})
);
myActionSet.actions.add(myAction);
myAction.run();
While this works in the current version of the script, it still is pretty obscure given some of the redundancy of writing out ActionParams like idct longhand, or needing to know the exact internalName value and required parameters of each in order to construct a valid Action. At the least, the parsing part of this could allow you to create an Action then load it's AIA and convert to JSON to see the parameters needed in order to more easily tweak things yourself, then re-encode it as AIA and save it somewhere:
var rawActionString = myActionSet.toAIA();
The source code to this Action API is here. I'm sure it's not perfect since I didn't test literally every possible Action and at the moment, only the non-minified version works as expected since TerserJS seems to mangle key-values into raw unicode when the minified version is used. I'd like to eventually rewrite this in a more performant way -- right now, trying to parse an ActionSet with 10+ actions can freeze the app for 2ish seconds so it's likely not fit for commercial use and including the entire script in with your own to utilize fully, but at the least I thought others might be able to make use of the JSON part.
