Copy link to clipboard
Copied
Since building dynamic actions is a topic unto itself, we often search for a reference thread to show somebody how to do this - and we often do so while trying to discuss work which is already involved and has nothing to do with actions or loading and playing them. Therefore I'm creating this thread to show an example and I'll paste the url to it when such questions arise.
Sometimes in Illustrator scripting we need to accomplish tasks which (sometimes counterintuitively) do not have scripting access via the DOM.
Fortunately since Illustrator CS6, they gave us the ability to play an action from a script with the app.doScript() command - which is not at all the same as Indesign's function of the same name. This one lets you play an action that exists inside the Actions panel. Immediately this may seem disappointing as users cannot be counted on to have specific actions at any given time.
However, they also gave the ability to load and remove actions from .aia action files. Your .aia file just needs to be somewhere and app.loadAction() can read it right into the Actions panel. Same with app.unloadAction(setName, actionName) - where (thanks to qwertyfly) using (setName, "") an empty string argument for the action name will remove the entire set. And when you try to remove an action that does not exist, well, it throws an error - which is how you can check for making absolutely sure that an action set is completely removed.
This may seem like a lot of work - to write a file, read it, play it and then discard it, often to do something that you'd think scripting should do in the first place.
Sometimes the action alone is enough to satisfy an objective - such as changing the document color mode. Other times it is necessary to alter actions in order to get use out of them - such as when you try to create a routine for saving a high-resolution "Export" JPG that is different in output and options form the "Save for Web" JPG. You may want to change some of the parameters such as resolution or the actual destination of the file.
Here is how you can do this.
First, record your action as you would normally: record a new set with a new action, call them what you need and then in the Actions flyout menu, save out a .aia file where you can find it. You can open the file in a text editor and read the contents - they are lines of special Actions 'code' which contains some cryptic text.
There are lines which look like a bunch of gibberish characters, they are hex-encoded strings for some parameter item which are strings, and they contain above them a number to signify the amount of characters inside the encoded string. (this is important later because this number also needs to be set properly when you put your own value in there) Other parameter items are simple numbers, but their keys are still obscured.
The truth is, while the string parameters are hexadecimal-encoded, the keys are both hexadecimal and decimal encoded! So if you wanted to know the special 4-letter keys, you'll have to run those through two decoder routines.
Next, you will need to put this entire string into your script and use some string-replacement or string-building to put your own data in those places of the action string where they matter. For example, putting your own file path into a save action.
And, after that you need to write a procedure for writing this new altered string to the file system and loading it into your Actions panel. Mind you, to leave things "as they were" you would need to remove the .aia file and the action that you have loaded.
Let's try with the save-a-jpeg workaround!
Here is the .aia string which is recorded from an Export JPEG action.
/version 3
/name [ 8
5475746f7269616c
]
/isOpen 1
/actionCount 1
/action-1 {
/name [ 11
4578706f7274204a504547
]
/keyIndex 0
/colorIndex 0
/isOpen 1
/eventCount 1
/event-1 {
/useRulersIn1stQuadrant 0
/internalName (adobe_exportDocument)
/localizedName [ 9
4578706f7274204173
]
/isOpen 1
/isOn 1
/hasDialog 1
/showDialog 0
/parameterCount 7
/parameter-1 {
/key 1885434477
/showInPalette 0
/type (raw)
/value < 100
0a00000001000000030000000200000000002c01020000000000000001000000
69006d006100670065006d006100700000006f00630000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000100
>
/size 100
}
/parameter-2 {
/key 1851878757
/showInPalette 4294967295
/type (ustring)
/value [ 25
2f55736572732f566173696c7948616c6c2f4465736b746f70
]
}
/parameter-3 {
/key 1718775156
/showInPalette 4294967295
/type (ustring)
/value [ 16
4a5045472066696c6520666f726d6174
]
}
/parameter-4 {
/key 1702392942
/showInPalette 4294967295
/type (ustring)
/value [ 12
6a70672c6a70652c6a706567
]
}
/parameter-5 {
/key 1936548194
/showInPalette 4294967295
/type (boolean)
/value 1
}
/parameter-6 {
/key 1935764588
/showInPalette 4294967295
/type (boolean)
/value 1
}
/parameter-7 {
/key 1936875886
/showInPalette 4294967295
/type (ustring)
/value [ 1
32
]
}
}
}
We can see many parameters and their various cryptic blocks, but what you want to do is decode as many /type (ustring) elements as possible to get a sense of what the action is doing. At this website, you can do this fairly easily although tediously: Convert Hexadecimal To String Online
For example: "4a5045472066696c6520666f726d6174" turns into "JPEG file format".
In this action example, I am not worried about changing the other parameters dynamically - I'm assuming the settings used in my action are suitable for my purposes such as resolution being 300 for all time. The part I'd like to change is my file path so that my JPEG goes to the right place.
/value [ 25 | ||||
2f55736572732f566173696c7948616c6c2f4465736b746f70 | ||||
] |
This line yields: "/Users/VasilyHall/Desktop"
So this is the line I'll need to replace.
Before anything else - here is how I'd embed the action string with ease. Using a text editor like Sublime text which lets you put many cursors down at one time, I can paste the action string in and find every nextline character. Then it's easy to highlight each line and put quotes around it as well as a comma in the end, or plusses - depending if you want to store the string as an array or a plain string in the script.
I find the plusses a little cluttering so I opt to use this format:
var actionString = [ "string",
"string"
].join("\n");
So my dynamic portion of the string which will be used with string replacement would look like this:
" /value [ {{number_of_characters}}",
" {{hex_encoded_path}}",
" ]",
When the action is ready to be dispatched, a string replacement would look like this:
var myNewPath = Folder.myDocuments.toString() + "/Destination";
var myNewPathEncoded = hexEncode(myNewPath); // find a hex encode function via google
var thisActionString = actionString.replace("{{hex_encoded_path}}", myNewPathEncoded).replace("{{number_of_characters}}", myNewPath.length);
Now it's time to write the file.
var f = File(actionFileLocation);
f.open('w');
f.write(thisActionString);
f.close();
And now it's time to load the action.
app.loadAction(actionFileLocation);
Now we can play the action.
app.doScript("Export JPEG", "Tutorial");
This should save your jpeg, and as of this writing, this is the only way to get the JPEG export which isn't the Save-for-Web variety.
But, let us not forget the cleanup.
Remove the .aia file:
f.remove();
Remove the single-use dynamic action:
app.unloadAction("Tutorial", "");
There you have it: building dynamic actions to do simple and non-simple things, which regular scripting just can't do.
Copy link to clipboard
Copied
Thank @Silly-V!
If you need quick reference for all the possible export settings, I've create an easy-to-read table in the ExportDocAsJPEG in ScriptSettings.md. Also, if anyone has builds or corrections (within reason), make a request on github (or DM me) and I'll update.
Copy link to clipboard
Copied
awesome! thanks for sharing @Y8eebtBS
Copy link to clipboard
Copied
someone made a useful tool for this on reddit:
"I already posted the code you need here in the replies, but I actually find myself doing this all the time and have made a personal panel for copying concatenated .aia text so I can easily paste it inside a .jsx file. You can find my copycat panel here, the extension is located at ./archive/copycat_1.0.0.zxp, and you'd install it using a ZXP Installer like this one, then relaunch AI and find in Windows > Extensions > copycat.
At that point, you'd just drag your .aia file into the panel, then paste the result into your main script to use as the contents parameter of runActionFromString."
Copy link to clipboard
Copied
someone made a useful tool for this on reddit:
By @AJJ22656695e0lw
that would be Tom aka @Inventsable
Copy link to clipboard
Copied
I was wondering how you can add it to an existing ActionSet. I see now it will add a new Set with the same name. I tried looking into what False is in the function doScript, but cant seerm to find a reference
Copy link to clipboard
Copied
IMHO the only way to manage anything like that is to parse aia text and to splice together such an aia text that you could erase the old set with the remove method that has no argument for action-name but only one string argument specifying the set name. I am not sure what happens if two action sets with the same name are loaded and the removal method is used though.
But, regardless, it will not throw an error until there is no such action-set named that name left in the panel - so you can keep looping with a while loop until there are no more such-named sets left and you are able to retrieve an error in a try-catch block.
So, only if you have access & management of the text files to be able to 'know' what exactly is loaded inside the actions panel, you could tecnically manipulate the text to add more action events, or splice in action events and replace the target set with your special new spliced set.
Copy link to clipboard
Copied
If i remember correctly, when 2 actions with the same name exist. It deletes the first one. I was adding one action dynamically which was name exactly the same. So now when i use this method, i add suffix of _tmp so i deletes the correct one.