Skip to main content
Known Participant
April 15, 2020
Beantwortet

Interacting with user during a script - Photoshop

  • April 15, 2020
  • 6 Antworten
  • 5610 Ansichten

Hi everybody, hope you all are fine in this period! I would like to create a script (with Javascript) on Photoshop that opens an image and generates effect layers automatically (these steps are done). At this moment I would like that the script stops to let the user modify the effects. Once its done, I would like that the user can press a key or a "ok" in an alert box (even if I think that the alert box stops all the process) or something similar to let the script continue and - for example - save the image. Every help is welcomed 🙂

Take care of you guys and thank you for your time,

Antoine

Dieses Thema wurde für Antworten geschlossen.
Beste Antwort von Kukurykus

Ok so I think I am starting to understand 🙂 My questions now are the following: 

  • What do you mean by bind a shortcut to a script? You want that I press a key or that the script call another script?
  • Also with which part of my script should I replace the alert? The part before generating the layers or the one after the user did the changes?

If I understand well you are talking about a keyboard shortcut to call my script. The thing is that there are two parts. If I have to call a script after the user made some changes, it should be the part that crops and saves the image. But how it can start the loop again and do the same process for all the other pictures?

Finally I have to precise that the first part of my script is not simply opening the image. It opens them accordingly to a specific format and following a specific order. So we should also take this part in account and not just simply use open(fle).


Like actions can have shortcuts, Scripts too (Edit / Keyboard Shortcuts / File).

Script does not call another script. You simply call the same script, by pressing shortcut.

Till you elaborate script that works as you want, reslaunch Ps before each full script sequence:

 

if (!$.getenv('fls')) {
	fls = File('~/desktop/Folder').getFiles()
	$.setenv('fls', fls.toSource())
}

if ($.getenv('fls')) {
	if (documents.length) {
		//	2nd part of script
		;(aD = activeDocument).save(), aD.close()
	}
	fle = (fls = eval($.getenv('fls'))).shift()
	$.setenv('fls', fls.toSource()); if (fle) {
		open(fle)	//	1st part of script
	}
	if (!fle) $.setenv('fls', ''), alert('End!')
}

 

6 Antworten

Known Participant
April 24, 2020

You are totally right, it works perfectly once you understand the principle of Environments Variables. I learnt this thanks to you. Very powerful and simple method. You are the best, thank you again:)

Kukurykus
Legend
April 16, 2020

You should use Environment Variables for this.

JJMack
Community Expert
Community Expert
April 16, 2020

What I do is record infornation into the documents metadata info field so  I have a scratch pad area for each document within the document.  All my scripts share the info field.  They insert and remover their infornation in the field and preservet whatever else is there.  I started doing this in CS2. The field is empty by defailt.   In CC 2015.5 Adobe broke my script they add code that stop my scripts from removing their data and setting the field back to empty.  To get arount Adobe Change  I have install Open and New document scripts events that add "Garbage" to the info filed if it is not there.  Then my scripts work they have not problen setting info back to Garbage.

 

/* ======================================================================================
// 2009  John J. McAssey (JJMack)  http://www.mouseprints.net/
//  
// This script is supplied as is. It is provided as freeware. 
// The author accepts no liability for any problems arising from its use.
//
// This script is designed to be used by a Photoshop Action twice
// A good pratice to use when creating an actions that use this scipt is for the action 
// not to do a save or play some other action between its two useages of this Script.
// 
// The first time this script is used by an action the documents current resolution
// and ruler units are saved into the document's meta-data Info Instructions field.
//
// The second time this script used by the action the script retreives what was
// saved in the meta-data during the first usage, resolution and ruler units.
// The document is resized to the saved resolution,
// Photoshop's ruler units are set to saved units
// and the saved data is removed from the document's meta-data Info Instructions field.
//
// ===================================================================================== */

/*
<javascriptresource>
<about>$$$/JavaScripts/SaveAndRestoreResolution/About=JJMack's SaveAndRestoreResolution.^r^rCopyright 2009 Mouseprints.^r^rRun twice script utility for action.^rNOTE:Don't play other actions between runs!^r^rFirst Run records Photoshop's preferences Units and documents DPI resolution.^rSecond Run restores the recorded setting and removes the recording.</about>
<category>JJMack's Action Run Twice Utility</category>
</javascriptresource>
*/

if (app.documents.length > 0) { 
	if (app.activeDocument.info.instructions.indexOf("<Resolution>") == -1 ){ // no footprint fisrt useage 
		//alert("first");
		// Retreive Document information for Foot Print 
                var units = app.preferences.rulerUnits;
		app.preferences.rulerUnits = Units.PIXELS;	// set ruler units to PIXELS
                var typeunits = app.preferences.typeUnits;
		var res = app.activeDocument.resolution; 

		// put footprint in metadata info instructions
		app.activeDocument.info.instructions = app.activeDocument.info.instructions + "<Units>" + units + "</Units>"  + "<Tunits>" + typeunits + "</Tunits>" + "<Resolution>" + res + "</Resolution>"; 
		//alert( "Saved ="  + "<Units>" + units + "</Units>" + "<Tunits>" + typeunits + "</Tunits>" + "<Resolution>" + res + "</Resolution>" ); 

		app.preferences.rulerUnits = units;		// restore ruler units
	} 
	else { 
		//alert("second");

		// Retreive saved information
		unitsOffset = app.activeDocument.info.instructions.indexOf("<Units>") + "<Units>".length;
		unitsLength = app.activeDocument.info.instructions.indexOf("</Units>") -unitsOffset;	
		savedUnits = app.activeDocument.info.instructions.substr(unitsOffset, unitsLength);

		tunitsOffset = app.activeDocument.info.instructions.indexOf("<Tunits>") + "<Tunits>".length;
		tunitsLength = app.activeDocument.info.instructions.indexOf("</Tunits>") -tunitsOffset;	
		savedTunits = app.activeDocument.info.instructions.substr(tunitsOffset, tunitsLength);

		resOffset = app.activeDocument.info.instructions.indexOf("<Resolution>") + "<Resolution>".length;
		resLength = app.activeDocument.info.instructions.indexOf("</Resolution>") + -resOffset;	
		savedResolution = app.activeDocument.info.instructions.substr(resOffset, resLength);
		//alert("Resolution = " + savedResolution + " Units = " + savedUnits );

		// Restore resolution
		app.preferences.rulerUnits = Units.PIXELS;
		activeDocument.resizeImage(null, null, savedResolution, ResampleMethod.NONE);

		// Restore ruler units 
		// I get a message Enumerated value expected if I try to use var savedUnits app.preferences.rulerUnits = savedUnits;
		// perhaps if I knew Javascript I would not need to use the following if else if ..... 
		if ( savedUnits == "Units.INCHES" ){ app.preferences.rulerUnits = Units.INCHES;}
		else if ( savedUnits == "Units.CM" ){ app.preferences.rulerUnits = Units.CM;}
		else if ( savedUnits == "Units.PERCENT" ){ app.preferences.rulerUnits = Units.PERCENT;}
		else if ( savedUnits == "Units.MM" ){ app.preferences.rulerUnits = Units.MM;}
		else if ( savedUnits == "Units.PIXELS" ){ app.preferences.rulerUnits = Units.PIXELS;}
		else if ( savedUnits == "Units.POINTS" ){ app.preferences.rulerUnits = Units.POINTS;}
		else if ( savedUnits == "Units.PICAS" ){ app.preferences.rulerUnits = Units.PICAS;}

		// Restore Type units 
		if ( savedTunits == "TypeUnits.PIXELS" ){ app.preferences.typeUnits = TypeUnits.PIXELS;}
		else if ( savedTunits == "TypeUnits.POINTS" ){ app.preferences.typeUnits = TypeUnits.POINTS;}
		else if ( savedTunits == "TypeUnits.MM" ){ app.preferences.typeUnits = TypeUnits.MM;}
		

		// Remove footprint from metadata info instructions
		before = app.activeDocument.info.instructions.substr(0,app.activeDocument.info.instructions.indexOf("<Units>"));
		afterOffset = app.activeDocument.info.instructions.indexOf("</Resolution>") + "</Resolution>".length;
		after = app.activeDocument.info.instructions.substr(afterOffset, app.activeDocument.info.instructions.length - afterOffset);
		//alert ("before = " + before + " after = " + after);
		app.activeDocument.info.instructions = before + after;
	} 
} 
else { alert("You must have at least one open document to run this script!"); } 
JJMack
Chuck Uebele
Community Expert
Community Expert
April 16, 2020

Like JJ's comment, I've created a marker in the file that the script will detect and run a second part of a script. I only did this briefly, then opted for a script that created an XML file, where I could store that info, along with presets for a UI.

Known Participant
April 16, 2020

Ok I answer here but it will take in account all the answers. Fisrt of all thanks to everybody for your messages, I really appreciate it. If I understood well, I should separate my main script in two parts and after find a way to call the second (via a palette button, or maybe via a keyboard shortcut (it should work in Mac using Automator service)). The only problem is that the first script is a loop that opens all the files (one by one) from a specific folder. Once it opens one image - lets say the first from 100 pictures - it creates some effect layers and stops to let the user decides whether or not we want to modify, for example, the exposure. At this moment, if I understand well, the script is stopped and cant continue. Thats why we should call another script. This second script should save the image (and maybe other stuff but the in between steps are not a problem) AND MOSTLY continue the loop. Its this final step that makes me doubt because I dont know how the two scripts can communicate at which point of the loop we are. Maybe its the purpose of the marker that you and JJMack are talking about. As I said I am quite new to scritping (even if after hours of pain we improve) so I dont know what a marker is. If for you its the key of the problem that I am mentionning so I will have a deep look into it. If you have some reference, feel free to share with me. Thank you again!

Kukurykus
Legend
April 16, 2020

Save folowing script to 'Presets / Scripts' of your Photoshop folder.

Then launch Ps and bind 'File / Scripts / Your Script' to some shortcut:

 

if (!$.getenv('fls')) {
	fls = File('~/desktop/Folder').getFiles()
	$.setenv('fls', fls.toSource())
}

if ($.getenv('fls')) {
	fle = (fls = eval($.getenv('fls'))).shift()
	$.setenv('fls', fls.toSource()); if (fle) open(fle),
	refresh(), alert('Put here your script!')
	if (!fle) $.setenv('fls', ''), alert('End!')
}

 

JJMack
Community Expert
Community Expert
April 15, 2020

You can not start a script and have a stop in it like an Action.  In an Action when a stop step is executed the actions stops Playing the Action step after the Stop step in the action is Highlighted so the user can click the Play button in the Action Palette to continue the Action.  The user can do anything  before clicking the play button. They also do not have to ever click play again to continue the action.

 

Like Actions can have Interactive steps Scripts can have interactive steps. Also a Scripts can use actions and they can have interactive steps however, if the action a script uses has as Stop step when the action stops the script will continue its  processing  and never click the Action palette play button.

 

You can write a script that has different functions where it may do something and set a marker it has done part one and terminate.  When the run the script again it will sec it did the first part and do the second part.... That would be like an action with a stop step....

JJMack
Stephen Marsh
Community Expert
Community Expert
April 16, 2020

I would have said either split the script into sub-scripts and reference them from an action, or create a full extension/panel... However, JJMack's comment is intriguing:

 

"You can write a script that has different functions where it may do something and set a marker it has done part one and terminate.  When the run the script again it will sec it did the first part and do the second part.... That would be like an action with a stop step...."

Legend
April 15, 2020

Use BridgeTalk to create window in palette mode with "ok" button:

How can Scriptui SnpCreateDialog.jsx be changed to make "palette" that doesn't disappear?

 

Known Participant
April 15, 2020

Thank you for the link! I am quite new to scripting so I will try to read a bit about BridgeTalk and your link in these days. Just let me know if you are sure (or if there is a good chance) that the script will be stopped by this window and will still let us the possibility to interact with the software and then will restart when I will press "ok" 🙂 Thanks again!

Legend
April 16, 2020

No, script will not be stopped by this window. Moreover - script will continue after it appears (therefore, you must take care to break the script into parts and execute them separately).

A window in palette mode is one of the few opportunities to let the user to interact with the workspace while the script is running. For example, like this:

 

alert("put first part of your script here")

var bt = new BridgeTalk();
bt.target = "photoshop";
var f = ";f('" + $.fileName.toString() + "');"
bt.body = "var f=" + fnctn.toSource() + f;
bt.send();

function fnctn(scriptPath) {
    try {
        var w = Window.find("palette", "continue");
        if (w) {
            w.show();
            return;
        }

        var d = new Window("palette", "continue");
        d.b1 = d.add("button", undefined, "ok");
        d.b2 = d.add("button", undefined, "cancel");

        d.b1.onClick = function () {
            d.close();
            alert("put second part of you script here in you need to run it again");
            $.evalFile(scriptPath);
        }
        d.b2.onClick = function () {
            d.close();
            alert("put second part of you script here in you do not need to run it again");
        }
        d.show();
    }
    catch (e) {alert (e)}
}

 

(script must first be saved to disk since it uses file path to run it again in cycle mode)

Geppetto Luis
Legend
April 15, 2020

You can put a starting script

if you want to stop the script you can edit
DialogModes.NO
with
DialogModes.ALL

Known Participant
April 15, 2020

I dont see how we can choose when to start again the script... Maybe I understood wrongly what you meant 🙂