Copy link to clipboard
Copied
Hello, all!
I have a javascript for Photoshop that displays a dialog at launch, asking for a text string. When I make an action running that script, I'd like the action to also record the text string inputed in the dialog. I've read elsewhere on this forum that this should be possible if you register your script as a plugin, which I tried to to like by including this in the script:
/*
@@@BUILDINFO@@@ PoserFrames.jsx 3.0
*/
/*
// BEGIN__HARVEST_EXCEPTION_ZSTRING
<javascriptresource>
<name>Poser Frames</name>
<menu>automate</menu>
<enableinfo>true</enableinfo>
<eventid>f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3</eventid>
<terminology><![CDATA[<< /Version 1
/Events <<
/f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3 [(Poser Frames) /imageReference <<
/Recipe [($$$/Actions/Key/PoserFrames/Recipe=Recipe) /uint]
>>]
>>
>> ]]></terminology>
</javascriptresource>
// END__HARVEST_EXCEPTION_ZSTRING
Alas, no dialog input is recorded with the action. Has someone any idea where I'm going wrong?
/Joakim
1 Correct answer
/*
// BEGIN__HARVEST_EXCEPTION_ZSTRING
<javascriptresource>
<name>Poser Frames</name>
<menu>automate</menu>
<enableinfo>true</enableinfo>
<eventid>f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3</eventid>
<terminology><![CDATA[<< /Version 1
/Events <<
/f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3 [(Poser Frames) <<
/recipe [(Recipie text) /string]
>>]
>>
>> ]]></terminology>
...
Explore related tutorials & articles
Copy link to clipboard
Copied
@hertze – This has been on my "to do" list, as I haven't done this before... So I can't help from first-hand experience.
1) Is the GUID/UUID unique (not conflicting with any other script currently installed)
2) As you didn't post the full code, are you using scriptUI for the interface?
EDIT: You might find the following to be helpful - https://www.davidebarranca.com/2012/11/action-recordable-scripts-in-photoshop/
Copy link to clipboard
Copied
1) Yes, I used an oline UUID generator, so it should be unique.
2) Yes, I tried dipping my toes in scriptUI for the dialog. I used the following code:
function displayDialog() {
var dialog = new Window("dialog");
dialog.size = [500, 150];
dialog.text = "Run Poser Frames with recipe";
dialog.orientation = "column";
dialog.alignChildren = ["left","top"];
dialog.spacing = 10;
dialog.margins = 20;
dialog.statictext1 = dialog.add("statictext", undefined, undefined, {name: "label"});
dialog.statictext1.text = "Your recipe:";
dialog.statictext1.alignment = ["fill","top"];
dialog.edittext1 = dialog.add("edittext", undefined, undefined,{ multiline: true });
dialog.edittext1.alignment = ["fill","top"];
dialog.edittext1.size = [400, 50];
var submit = dialog.add("button", undefined, undefined, {name: "submit"});
submit.text = "Run Poser Frames!";
dialog.submit.onClick = function() {
var thisRecipe = dialog.edittext1.text;
dialog.close();
alert(thisRecipe);
};
dialog.show();
}
I actually came across David Barranca's 2012 article, but hoped there was a simpler way. I can't claim to fully understand how to adapt his example code for my purposes, but it would require significant changes to the flow of my rather large script, which I'm hoping to avoid...
The full script is on GitHub: https://github.com/hertze/PoserFrames/tree/dev-UI
Copy link to clipboard
Copied
It's the file named "Poserframes.jsx" I should add!
Copy link to clipboard
Copied
Sigh, after reading up about <javascriptresource> and Action Manager integration in the Javascript Scripting Reference I realize how little I understand about UI scripting and how to pull this off. It's serious when you don't even understand the instructions, right?
Copy link to clipboard
Copied
There are others here that can help, I don't think that I'm the one. I'll take another look at the default Adobe fit image script when I have time.
Edit: Fit Image makes it look so clear and easy! :]
Copy link to clipboard
Copied
Ha, I'm not a good enough coder for that to look easy. Acording to the scripting guide "Conditional Mode Change.jsx" is an even better example on setting a script up as a plugin and how to pass arguments to the Action Manager for inclusion in actions. Maybe I'll try to understand how that works...
Copy link to clipboard
Copied
@Paul Riggott provided something concerning persistentSettings more than a decade ago that still seems to work.
If one runs the Script it provides an alert that counts up across multiple runs.
// need to initialize the custom settings option in javascript, in flex the try/catch isn't enough to prevent an error for some reason.
var persistentSettings;
try {
persistentSettings = app.getCustomOptions("my_settings_key");
} catch(e) {};
//
/*if (persistentSettings == null) {
persistentSettings = new ActionDescriptor();
persistentSettings.putData(0," ");
app.putCustomOptions("my_settings_key",persistentSettings,true);
};*/
//
// define document;
//var myDocument = app.activeDocument;
if (!persistentSettings) {var theNumber = 1}
else {var theNumber = persistentSettings.getData(0)};
alert (theNumber);
theNumber++;
persistentSettings = new ActionDescriptor();
persistentSettings.putData(0, theNumber);
app.putCustomOptions("my_settings_key", persistentSettings, true);
Copy link to clipboard
Copied
Thanks! I'll look into if that might work as a solution for me!
Copy link to clipboard
Copied
/*
// BEGIN__HARVEST_EXCEPTION_ZSTRING
<javascriptresource>
<name>Poser Frames</name>
<menu>automate</menu>
<enableinfo>true</enableinfo>
<eventid>f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3</eventid>
<terminology><![CDATA[<< /Version 1
/Events <<
/f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3 [(Poser Frames) <<
/recipe [(Recipie text) /string]
>>]
>>
>> ]]></terminology>
</javascriptresource>
// END__HARVEST_EXCEPTION_ZSTRING
*/
var isCancelled = false;
main()
isCancelled ? 'cancel' : undefined
function main() {
if (!app.playbackParameters.count) {
//normal run (from scripts menu)
var result = displayDialog();
if (!result || result == '') { isCancelled = true; return } else {
var d = new ActionDescriptor;
d.putString(stringIDToTypeID('recipe'), result)
app.playbackParameters = d;
}
}
else {
var recipe = app.playbackParameters.getString(stringIDToTypeID('recipe'));
if (app.playbackDisplayDialogs == DialogModes.ALL) {
// user run action in dialog mode (edit action step)
var result = displayDialog(recipe);
if (!result || result == '') { isCancelled = true; return } else {
var d = new ActionDescriptor;
d.putString(stringIDToTypeID('recipe'), result)
app.playbackParameters = d;
}
}
if (app.playbackDisplayDialogs != DialogModes.ALL) {
// user run script without recording
alert('variable recordered in action:\n' + recipe);
}
}
}
function displayDialog(thisRecipe) {
var dialog = new Window("dialog");
dialog.size = [500, 150];
dialog.text = "Run Poser Frames with recipe";
dialog.orientation = "column";
dialog.alignChildren = ["left", "top"];
dialog.spacing = 10;
dialog.margins = 20;
dialog.statictext1 = dialog.add("statictext", undefined, undefined, { name: "label" });
dialog.statictext1.text = "Your recipe:";
dialog.statictext1.alignment = ["fill", "top"];
dialog.edittext1 = dialog.add("edittext", undefined, undefined, { multiline: true });
dialog.edittext1.alignment = ["fill", "top"];
dialog.edittext1.size = [400, 50];
dialog.edittext1.text = thisRecipe ? thisRecipe : '';
var submit = dialog.add("button", undefined, undefined, { name: "submit" });
submit.text = "Run Poser Frames!";
dialog.submit.onClick = function () {
thisRecipe = dialog.edittext1.text;
dialog.close();
};
dialog.show();
return thisRecipe;
}
* Photoshop registers your eventid on initialization. That is, the script must be in the presets folder at the time of launching Photoshop.
** working with variables written in the terminology section is not possible from the debugger (Photoshop does not record variables to the action, cannot read them from the action, since accesses the script by eventid). You need to either understand how it works, or or use your imagination by editing the script directly in the presets folder and displaying debugging information with alerts or through the console.
Copy link to clipboard
Copied
@jazz-y I think you just saved my life! This is exactly what I need. I'm grateful beyond words for this!
Copy link to clipboard
Copied
@jazz-y Might I ask how you would go about modifying that code to work for two variables from the dialog (one text field and one checkbox)? No matter what I try I just can't get that to work...
Copy link to clipboard
Copied
When working with many variables, I prefer to store them in a separate global object that all script functions have access to. I changed the code a bit to make things easier.
/*
// BEGIN__HARVEST_EXCEPTION_ZSTRING
<javascriptresource>
<name>Poser Frames</name>
<menu>automate</menu>
<enableinfo>true</enableinfo>
<eventid>f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3</eventid>
<terminology><![CDATA[<< /Version 1
/Events <<
/f35c20c1-2a5c-45d2-98e2-fead0d2bc8c3 [(Poser Frames) <<
/recipe [(Recipie text) /string]
/checkbox [(My checkbox) /boolean]
>>]
>>
>> ]]></terminology>
</javascriptresource>
// END__HARVEST_EXCEPTION_ZSTRING
*/
var isCancelled = false,
cfg = new Config;
main()
isCancelled ? 'cancel' : undefined
function main() {
if (!app.playbackParameters.count) {
//normal run (from scripts menu)
if (displayDialog() == 2) { isCancelled = true; return } else {
app.playbackParameters = cfg.toDescriptor();
}
}
else {
cfg.toObject(app.playbackParameters)
if (app.playbackDisplayDialogs == DialogModes.ALL) {
// user run action in dialog mode (edit action step)
if (displayDialog() == 2) { isCancelled = true; return } else {
app.playbackParameters = cfg.toDescriptor();
}
}
if (app.playbackDisplayDialogs != DialogModes.ALL) {
// user run script without recording
alert('variable recordered in action:\nRecipie: ' + cfg.recipe + '\nCheckbox value: ' + cfg.checkbox);
}
}
}
function displayDialog() {
var dialog = new Window("dialog");
dialog.size = [500, 170];
dialog.text = "Run Poser Frames with recipe";
dialog.orientation = "column";
dialog.alignChildren = ["left", "top"];
dialog.spacing = 10;
dialog.margins = 20;
dialog.statictext1 = dialog.add("statictext", undefined, undefined, { name: "label" });
dialog.statictext1.text = "Your recipe:";
dialog.statictext1.alignment = ["fill", "top"];
dialog.edittext1 = dialog.add("edittext", undefined, undefined, { multiline: true });
dialog.edittext1.alignment = ["fill", "top"];
dialog.edittext1.size = [400, 50];
dialog.edittext1.text = cfg.recipe;
dialog.checkbox = dialog.add('checkbox', undefined, 'sample text');
dialog.checkbox.value = cfg.checkbox
var submit = dialog.add("button", undefined, undefined, { name: "submit" });
submit.text = "Run Poser Frames!";
dialog.submit.onClick = function () {
cfg.recipe = dialog.edittext1.text;
dialog.close();
};
dialog.checkbox.onClick = function () { cfg.checkbox = this.value }
return dialog.show();
}
function Config() {
//defaults
this.recipe = ''
this.checkbox = false
this.toDescriptor = function () {
var d = new ActionDescriptor(),
s2t = stringIDToTypeID;
for (var i = 0; i < this.reflect.properties.length; i++) {
var k = this.reflect.properties[i].toString();
if (k == "__proto__" || k == "__count__" || k == "__class__" || k == "reflect") continue;
var v = this[k];
switch (typeof (v)) {
case "boolean": d.putBoolean(s2t(k), v); break;
case "string": d.putString(s2t(k), v); break;
}
}
return d;
}
this.toObject = function (d) {
var t2s = typeIDToStringID;
for (var i = 0; i < d.count; i++) {
var k = d.getKey(i);
switch (d.getType(k)) {
case DescValueType.BOOLEANTYPE: this[t2s(k)] = d.getBoolean(k); break;
case DescValueType.STRINGTYPE: this[t2s(k)] = d.getString(k); break;
}
}
}
}
Copy link to clipboard
Copied
Thasnk you for this! I managed to cobble together a working solution just after I posted this question, but your solution is so much more elegant! Very generous!
Copy link to clipboard
Copied
I'm curious about this one but I'd like more info if possible. Can you run me through a generic example of what you're hoping to accomplish?
You say a dialog comes up asking for some text input. You want to use this elsewhere duing the running of the action. Is this place where it's used elsewhere also within a script that is called in a later step in the action?
Step 1: Run "GatherInfo.jsx"
Step 2: Change mode to RGB
Step 3: Add Adjustment Layer: B&W.....Settings....
Step 4: Run "Change Adjustment Layer Name to String from 'GatherInfo.jsx'"
Obviously just a made up example, but is that what you're trying to do?
Copy link to clipboard
Copied
Hi! No, what I want to accomplish is simpler than that, I think.
My script renders fake film negative borders, like when you have your real film scanned with borders. It is possible to create quite a few looks by changing settings (coded as variable declarations) at the top of the script. Today, the only way for users to change those settings is to open the script and change those variable declarations. I was hoping to find a way to let users change those settings without opening the script.
So I’m thinking something like this:
1. When the user runs the script from the script menu (or automate menu) it displays a dialog asking for a single text string (containing settings in a specified format).
2. That text string is then exploded and used as user settings (overriding the hardcoded ones) when the rest of the script runs.
As I understand it, if the script is coded as a plugin, an Action should be able to record that text string during creation and then **not** display the dialog again when the action later runs. This way you could create multiple actions, with different script settings, from the one script.
Copy link to clipboard
Copied
Do you have to use an action or can you just use the script from start to finish? If all you need to do is override those settings in the script, you can have the dialog open, user inputs their preference settings, they click OK, the script can take that dialog input and set those settings to the desired values. The hardcoded values would have to be converted into variables but it shouldn't be too hard to do.
For what it's worth, you could get a bit fancier. Convert the hardcoded values to variables and use a popup dialog to select each setting and even save favorite settings for later recall.
Copy link to clipboard
Copied
... or just put variables in an action and Photoshop will do everything for you ¯\_(ツ)_/¯
Most likely the author's script is used in automation (batch or other processor). Running a script to change its settings for each group of files can be tedious for the user.
Copy link to clipboard
Copied
@jazz-y Interesting! How does one add variables to Actions?
Copy link to clipboard
Copied
@jugenjury Users tend to use this batch run script with many different settings, depending on the style they want for their images. Today one has to keep different versions of the script, with different hardcoded settings. My thinking is users could use different Actions (with separate settings) and just the one script, which would make updating the script much easier.
Copy link to clipboard
Copied
@hertze, i wrote an example a couple of posts above. One, two, ten variables - it doesn't matter. The principle is the same.

