20 Replies Latest reply on Mar 25, 2018 8:30 PM by JJMack

    Keeping variables across runs of a script

    picknos

      Well, I'm a noob at Photoshop scripting. I knew Javascript, and I've been trying to work my way with the Photoshop DOM for about a month, but now I'm trying to do something that I can't find anywhere, neither in Google nor in the documentation... Sorry if this sounds obvious.

       

      First I'm asking to open a PDF file, and then I ask to select a folder where the pages will go. Then I save in an array the file object for the PDF, the folder object, the current page... so I can get it later. Now I open the first page, and stop the script to do some manual work. After that, I would load the script, check if the array where I saved that exists, and if it does, save that page and open the next.

       

      Now, I can't find any way to keep variables between runs of a script, nor to keep the script waiting in the background. Somewhere in the Javascript reference it says that the variables are kept, but every time it asks me to select the PDF again. So I'm kind of lost there. Could you help me?

       

      By the way, I'm using Photoshop CS5, and I script with Javascript.

        • 1. Re: Keeping variables across runs of a script
          c.pfaffenbichler Level 9

          First off converting pdfs in Photoshop may be inadvisable depending on the kind of editing you have to do.

           

          Other than that you could always write a txt-file to store the information to some pre-determined location (kind of a preference-file so to speak) and have the Script check for it before the dialog is raised.

          If such a file is found you can have the Script evaluate it and when the last page of the pdf is reached remove it.

          Hope this is halfway clear …

           

          But wouldn’t it be easier to just run the Script across the whole of the pdf, save the individual documents but not close them, so that you can just edit and close them one by one? (Depending of the number of pages this could admittedly be risky or get very slow.)

          • 2. Re: Keeping variables across runs of a script
            Michael L Hale Level 5

            If you  want to use the DOM to save the variables between runs instead of a file as C.Pfaffenbichler suggested, you need to use app.setCustomOptions() and app.getCustomOptions(). CustomOptions is covered in the Javascript guide under the application object. Some of the Adobe scripts that ship Photoshop use CustomOptions if you need to see a working example.

            1 person found this helpful
            • 3. Re: Keeping variables across runs of a script
              picknos Level 1

              Well, thanks to both, I'll try to see what I can do ^^

               

              But well, this kind of suggested that variables are kept:

               

              "Scripting shares a global environment, so any script executed at startup can define variables and functions that are available to all scripts. In all cases, variables and functions, once defined by running a script that contains them, persist in subsequent scripts during a given application session. Once the application is quit, all such globally defined variables and functions are cleared. Scripters should be careful about giving variables in scripts unique names, so that a script does not inadvertently reassign global variables intended to persist throughout a session."

              (Javascript Tools Guide CS5, page 12)

               

              That's why I kept trying to keep the array instead of going for something else...

               

              Message was edited by: picknos

              • 4. Re: Keeping variables across runs of a script
                Michael L Hale Level 5

                Although you can use globally defined variables, they need to be in a startup script to stay in memory. Normal scripts( ones run using File-Scripts ) can set global variables but the are removed when the script stops.

                 

                However globally defined variables are for the most part a bad practice. They take up limited resources and it's easy to overwrite variables thus breaking some other script( or have some other script change the values in your global variables ).

                 

                The cross-DOM Adobe scripts are good examples of scripts that need global variables and methods. Even they limit globals to the minimum required and use local variables where they can.

                • 5. Re: Keeping variables across runs of a script
                  picknos Level 1

                  Oh, I see. Thanks to all of you.

                  • 6. Re: Keeping variables across runs of a script
                    JJMack Most Valuable Participant

                    I'm late to this thread.  I couple of years ago I started to do some Scrip hacking.  I don't  know much about scripting only hack I use downloaded script as a starting point.  I wanted to Pass Pram to Scripts and also remember things between  two executions of a script.

                     

                    When CS3 was released I discovered that Adobe added Plug-in support to scripting for Fit Image was converted to a script in CS3.  That ment tha I now hat a way to pass Parms to a Script.  I coyld write it as a Plugin and the record using it in an action.  Thar Parms I wanted to pass would be recorded by the Action and when the action was played the parme would be passed to the script and Its dialog would not be displayed.

                     

                    For me Actions are easy where Scripts are work.  I wanted to create Scripts that could be used as utilities for actions put in a little logic. I wanted to create scripts that could be used twice in an action once in the the beginning of an action to save some of the documents current setting the action would then be free to make changes to to these setting for when the script would be run the second time at the end of the action the script would retrieve the saved setting and restore document  to its original settings.   I did not want  to write files yet I wanted to keep the information with the document.and be able to write and use more then on script if needed perhaps process more then one document at a time. I did not want to write one supper save everything and restore everything script.   I was able to actually hack these.    I used a field in the documents meta-data.  These scripts first look for its footprint in the current document metadata. If its not there its the first pass and the  information is placed into the meta data. The second time the script is run the information is retrieved and removed from the meta-data  and the document originale settings are restored.  Done properly the meta-data never gets written.  The Action can not contain any stops or saves btween the to executions of the scripts.

                     

                    Examples cam be found in my crafting actions package

                    http://www.mouseprints.net/old/dpr/JJMacksCraftingActions.zip

                    Contains:

                    Action Actions Palette Tips.txt

                    Action Creation Guidelines.txt

                    Action Dealing with Image Size.txt

                    Action Enhanced via Scripted Photoshop Functions.txt

                    CraftedActions.atn Sample Action set includes an example Watermarking action http://www.mouseprints.net/old/dpr/WM900x600.jpg

                    Sample Actions.txt Photoshop CraftedActions set saved as a text file. This file has some additional comments I inserted describing how the actions work.

                     

                    12 Scripts for actions

                    • 7. Re: Keeping variables across runs of a script
                      c.pfaffenbichler Level 9

                      If you want to give writing a txt-file a try here is something that may help getting started.

                      Of course you should have the Script remove the txt-file when the operation has run out, in your case when the last page of the pdf has been processed.

                       

                      // define the path of the intended txt-file;
                      var thePref = "~/Desktop/pref.txt";
                      // check for existence of file:
                      if (File (thePref).exists == true) {
                           var theText = readPref (thePref);
                           alert (theText);
                           }
                      else {
                      // dialog;
                           var dlg = new Window("dialog", "please enter a number", [500,300,750,380]);
                      // filter for checking if entry is numeric, thanks to xbytor;
                           numberKeystrokeFilter = function() {
                                this.text = this.text.replace(",", "");
                                this.text = this.text.replace(".", "");
                                this.text = this.text.replace("-", "");
                                if (this.text.match(/[^\-\.\d]/)) {
                                     this.text = this.text.replace(/[^\-\.\d]/g, "")
                                     };
                                if (this.text == 0) {this.text = 1}
                                };
                      // field for entry;
                           dlg.someText = dlg.add("edittext", [15,15,110,35], "3", {multiline:false});
                           dlg.someText.active = true;
                           dlg.someText.onChange = numberKeystrokeFilter;
                      // ok- and cancel-button;
                           dlg.buildBtn = dlg.add("button", [13,45,118,68], "OK", {name:"ok"});
                           dlg.cancelBtn = dlg.add("button", [128,45,240,68], "Cancel", {name:"cancel"});
                           dlg.center();
                      // show dialog;
                           var myReturn = dlg.show ();
                           alert (myReturn);
                           if (myReturn == 1) {
                                var theText = dlg.someText.text;
                      // write pref;
                                writePref (theText, thePref);
                                alert ("done")
                                }
                           };
                      ////// read prefs file //////
                      function readPref (thePath) {
                        if (File(thePath).exists == true) {
                          var file = File(thePath);
                          file.open("r");
                          file.encoding= 'BINARY';
                          var theText = new String;
                          for (var m = 0; m < file.length; m ++) {
                            theText = theText.concat(file.readch());
                            };
                          file.close();
                          return String(theText)
                          }
                        };
                      ////// function to write a preference-file storing a text //////
                      function writePref (theText, thePath) {
                        try {
                          var thePrefFile = new File(thePath);
                          thePrefFile.open("w");
                          for (var m = 0; m < theText.length; m ++) {
                            thePrefFile.write(theText[m])
                            };
                          thePrefFile.close()
                          }
                        catch (e) {};
                        };

                      2 people found this helpful
                      • 8. Re: Keeping variables across runs of a script
                        NightSkyGuy Level 1

                        picknos I found this: extendscript - Saving per-user or per-document preferences in a Photoshop script

                        on StackExchange.  I realize it's a very old question, but I figure below together with the answer given by c.pfaffenbichler would help subsequent readers.

                         

                        Overflowconst kMyFlag = app.stringIDToTypeID( "myFlag" );
                        const kMyNumber = app.stringIDToTypeID( "myNumber" );
                        const kMySettings = "mySettings";

                        function saveSettings()
                        {
                         
                        var desc = new ActionDescriptor();
                          desc
                        .putBoolean(kMyFlag, true);
                          desc
                        .putInteger(kMyNumber, 42);

                         
                        // "true" means setting persists across Photoshop launches.
                          app
                        .putCustomOptions( kMySettings, desc, true );
                        }

                        function getSettings()
                        {
                         
                        var desc = app.getCustomOptions( kMySettings );
                         
                        return [desc.getBoolean( kMyFlag ), desc.getInteger( kMyNumber )];
                        }

                         

                        Note further in the same answer set is an example of saving options "per document" using app.activedocument.info.instructions

                        • 9. Re: Keeping variables across runs of a script
                          alex.furer Level 1

                          Hi there, Glad that I found this script c.pfaffenbichler Thank you! My work is a collection of scripts to copy an image/photograph and create a document for printing with a frame around the image and a watermark.

                           

                          Now I am trying to run my scripts in a batch and therefore save the dialog settings so the next time the script gets called the values are loaded automatically.

                           

                          Whilst it ain't entirely clear to me how to achieve this, I think this script gives me a good starting point.

                           

                          Problem is that I got stuck at the beginning. I changed the script to add new lines after every value it reads from the input dialog by adding "\n" on the replace loop. But it seems to only add the new line on the second number I enter in the input dialog.

                           

                          Here's the output of entering 30,40,50,60:

                          3040

                          50

                          60

                           

                          I must be doing something wrong I guess. And I apologize right here and now, I am not a programmer per se. I can cobble together bits from other people and the reference manual and I am am capable of adding the missing pieces so the script does what I want.

                           

                          Update:

                          I was able to find where the problem is. The regular expression works fine: Scriptular - Javascript Regular Expression Editor

                           

                          But in this part something happens:

                          // filter for checking if entry is numeric, thanks to xbytor;
                               numberKeystrokeFilter = function() {
                                    this.text = this.text.replace(",", "");
                                    this.text = this.text.replace(".", "");
                                    this.text = this.text.replace("-", "");
                                    if (this.text.match(/[^\-\.\d]/)) {
                                         this.text = this.text.replace(/[^\-\.\d]/g, "gg") // Set new line here "\n"
                                         alert("Found NewLine");
                                         };
                                    if (this.text == 0) {this.text = 1}
                                    };
                          

                           

                          With the alert("Found NewLine"); I can see that the result is: 3040gg50gg60 or using the \n it is: 304050\n60\n (where the \n shows as empty character in Photoshop)

                           

                          Any advice would be greatly appreciated.

                          • 10. Re: Keeping variables across runs of a script
                            c.pfaffenbichler Level 9

                            Could you please post the complete code you use for entering the values?

                            • 11. Re: Keeping variables across runs of a script
                              alex.furer Level 1

                              Thank you for getting back! Here you go:

                               

                              #target photoshop
                              // Got this from: https://forums.adobe.com/thread/771241
                              
                              // define the path of the intended txt-file;
                              var thePref = "~/Desktop/pref.txt";
                              // check for existence of file:
                              if (File (thePref).exists == true) {
                                  var theText = readPref (thePref);
                                  alert (theText);
                                  }
                              else {
                              // dialog;
                                  var dlg = new Window("dialog", "please enter a number", [500,300,750,380]);
                              // filter for checking if entry is numeric, thanks to xbytor;
                                  numberKeystrokeFilter = function() {
                                        this.text = this.text.replace(",", "");
                                        this.text = this.text.replace(".", "");
                                        this.text = this.text.replace("-", "");
                                        if (this.text.match(/[^\-\.\d]/)) {
                                            this.text = this.text.replace(/[^\-\.\d]/g, "gg") // Set new line here "\n"
                                            alert("Found NewLine");
                                            };
                                        if (this.text == 0) {this.text = 1}
                                        };
                              // field for entry;
                                  dlg.someText = dlg.add("edittext", [15,15,110,35], "3", {multiline:false});
                                  dlg.someText.active = true;
                                  dlg.someText.onChange = numberKeystrokeFilter;
                                 
                              // ok- and cancel-button;
                                  dlg.buildBtn = dlg.add("button", [13,45,118,68], "OK", {name:"ok"});
                                  dlg.cancelBtn = dlg.add("button", [128,45,240,68], "Cancel", {name:"cancel"});
                                  dlg.center();
                              // show dialog;
                                  var myReturn = dlg.show ();
                                  alert (myReturn);
                                  if (myReturn == 1) {
                                        var theText = dlg.someText.text;
                              // write pref;
                              alert(theText);
                                        writePref (theText, thePref);
                                        alert ("done")
                                        }
                                  };
                              ////// read prefs file //////
                              function readPref (thePath) {
                                if (File(thePath).exists == true) {
                                  var file = File(thePath);
                                  file.open("r");
                                  file.encoding= 'BINARY';
                                  var theText = new String;
                                  for (var m = 0; m < file.length; m ++) {
                                    theText = theText.concat(file.readch());
                                    };
                                  file.close();
                                  return String(theText)
                                  }
                                };
                              ////// function to write a preference-file storing a text //////
                              function writePref (theText, thePath) {
                                try {
                                  var thePrefFile = new File(thePath);
                                  thePrefFile.open("w");
                                  for (var m = 0; m < theText.length; m ++) {
                                      alert("m= : " +theText[m]);
                                    thePrefFile.write(theText[m])
                                    };
                                  thePrefFile.close()
                                  }
                                catch (e) {};
                                };
                              
                              • 12. Re: Keeping variables across runs of a script
                                c.pfaffenbichler Level 9

                                I suspect I don’t understand what you are trying to so.

                                If you want to create multiple values why not use multiple edittext fields?

                                And if you want the text to contain commas then you would need to remove the line that replaces them with nothing.

                                • 13. Re: Keeping variables across runs of a script
                                  alex.furer Level 1

                                  You are right! I do have multiple text input fields and those only contain one value each. So I will have separate values. Cool.

                                   

                                  But I guess my concept is flawed. I wish Photoshop would record the values form the dialog when I run my script into the action as well. Just like it does when I record a Gaussian Blur filter value into an action.

                                   

                                  But hey, thanks for chiming in! You made me re-think my concept and I realized that it's flawed. I need to find a way to record running my scripts including the values I set. So Auto Hotkey for Windows or Selenium may be my solution.

                                   

                                  ~~~~~~~~~~~~~~~~~~

                                   

                                  Nevertheless here a proper documentation of my issue with your script. Maybe it helps someone else if we solve this, or call me out and make me realize that I don't understand your script... Then I'd be very sorry to have wasted your time

                                   

                                  As far as I understand, should write numbers to a text file eliminating the separator e.g. "," (comma).

                                   

                                  - Entering "30,40,50,60" into the dialog of your initial script saves "30405060" into a text file.

                                   

                                  - What I needed was that the text file contains:

                                  "30

                                  40

                                  50

                                  60"

                                   

                                  - Currently, with my alterations of replacing with "\n", the script saves:

                                  '3040

                                  50

                                  60"

                                  into a text file.

                                   

                                  It seems that the first comma does not get replaced with the new line "\n".

                                   

                                  - If I do the same thing and replace the comma with "gg" the result is:

                                  "3040gg50gg60"

                                   

                                  Again the first instance of the separator is ignored and not replaced.

                                  • 14. Re: Keeping variables across runs of a script
                                    c.pfaffenbichler Level 9

                                    One can record Scripts into Actions, but it seems like a hassle to me.

                                    https://www.davidebarranca.com/2012/11/action-recordable-scripts-in-photoshop/

                                     

                                    // define the path of the intended txt-file; 

                                    var thePref = "~/Desktop/pref.txt"; 

                                    // check for existence of file: 

                                    if (File (thePref).exists == true) { 

                                        var theText = readPref (thePref); 

                                        alert (theText);

                                        } 

                                    else { 

                                    // dialog; 

                                        var dlg = new Window("dialog", "please enter a number", [500,300,750,380]); 

                                    // filter for checking if entry is numeric, thanks to xbytor; 

                                        numberKeystrokeFilter = function() { 

                                              this.text = this.text.replace(".", "");

                                              this.text = this.text.replace("-", "");

                                              if (this.text == 0) {this.text = 1}

                                              }; 

                                    // field for entry; 

                                        dlg.someText = dlg.add("edittext", [15,15,110,35], "3", {multiline:false}); 

                                        dlg.someText.active = true; 

                                        dlg.someText.onChange = numberKeystrokeFilter; 

                                        

                                    // ok- and cancel-button; 

                                        dlg.buildBtn = dlg.add("button", [13,45,118,68], "OK", {name:"ok"}); 

                                        dlg.cancelBtn = dlg.add("button", [128,45,240,68], "Cancel", {name:"cancel"}); 

                                        dlg.center(); 

                                    // show dialog; 

                                        var myReturn = dlg.show (); 

                                        alert (dlg.someText.text); 

                                        if (myReturn == 1) { 

                                              var theText = dlg.someText.text.split(","); 

                                              var theText = theText.join("\n"); 

                                    // write pref; 

                                    alert(theText); 

                                              writePref (theText, thePref); 

                                              alert ("done") 

                                              } 

                                        }; 

                                    ////// read prefs file ////// 

                                    function readPref (thePath) { 

                                    if (File(thePath).exists == true) { 

                                    var file = File(thePath); 

                                    file.open("r"); 

                                    file.encoding= 'BINARY'; 

                                    var theText = new String; 

                                    for (var m = 0; m < file.length; m ++) { 

                                    theText = theText.concat(file.readch()); 

                                    }; 

                                    file.close(); 

                                    return String(theText) 

                                    }; 

                                    ////// function to write a preference-file storing a text ////// 

                                    function writePref (theText, thePath) { 

                                    try { 

                                    var thePrefFile = new File(thePath); 

                                    thePrefFile.open("w"); 

                                    for (var m = 0; m < theText.length; m ++) { 

                                    thePrefFile.write(theText[m]) 

                                    }; 

                                    thePrefFile.close() 

                                    catch (e) {}; 

                                    }; 

                                    1 person found this helpful
                                    • 15. Re: Keeping variables across runs of a script
                                      alex.furer Level 1

                                      WOW - You know what you're doing. Thanks for the fix/addition!!! And thanks for the pointer. I'll take a close look!

                                      • 16. Re: Keeping variables across runs of a script
                                        c.pfaffenbichler Level 9

                                        But I have to admit I never implemented the recoding of Script-dialog-values into Actions, like I indicated it seems a bit cumbersome even if it might be useful at times.

                                        1 person found this helpful
                                        • 17. Re: Keeping variables across runs of a script
                                          alex.furer Level 1

                                          I can see that looking at the link you provided. I guess I will throw all scripts into one big one, or keep them separate so I can go back to editing my photos instead of coding, and use AutoHotkey to automate a batch of images.

                                           

                                          Thanks again for your help and effort. Mucho apprish!

                                          • 18. Re: Keeping variables across runs of a script
                                            JJMack Most Valuable Participant

                                            alex.furer  wrote

                                             

                                            But I guess my concept is flawed. I wish Photoshop would record the values form the dialog when I run my script into the action as well. Just like it does when I record a Gaussian Blur filter value into an action.

                                            Photoshop does not do that but Photoshop Scripts can do that and some do.

                                             

                                            Some Photoshop Scripts are a Photoshop Plug-in.  That is these Scripts support being recorded into Actions.  They will record the Dialog Settings you used recording the action in the action step you recorded.  When the Action is played the Plug-in Script will bypass displaying its dialog and use the setting recorded into the Action step sot the Action can be batched.  The Action step will always use those recorded setting.  Even if  you make that action step interactive turn on the step's dialog the Script will pre-populate its dialog with the recorded values in the Action step.   For an example of a Plug-in script all you need do is edit Adobe Photoshop Plug-in script "Fit Image.jsx"

                                             

                                            It is quite more  complex the most complex Plug-in Script I know of is X's  Image Processo Pro Plug-in Script once installed you will find in Photoshop menu File>Automate>Image Processor Pro...  Adobe added Plug-in support into Photoshop scripting in CS3....

                                             

                                            You need to program Action support into your scripts with dialog the you want to batch. So you can record them into a Actions which can be batched.  Or make the script a batch processor process a file list or all open document or files selecte in bridge

                                            • 19. Re: Keeping variables across runs of a script
                                              Pedro Cortez Marques Level 3

                                              HI Michael L Hale

                                              The app.putCustomOptions() and app.getCustomOptions() works really well.

                                              When it is persistent, does is it stored in the photoshop "registry"?

                                              And is this secure enought and fast to put and get?

                                               

                                              Do you think it is safe to move all variables from external objects, like JSON, xml, etc to this other method app.putCustomOptions()?

                                              I like it a lot but I want to know if it is something that you are using for a long time and with success.

                                               

                                              Finally, last question.

                                              If I want to save some variables inside a document (like a psd) when I save it, I am using XMP metadata on the image or XMP inside a specific layer metadata.

                                              Would you do the same if you needed to have those vars in a psd image?

                                              • 20. Re: Keeping variables across runs of a script
                                                JJMack Most Valuable Participant

                                                Michael is no longer with us. IMO keeping data with a document in metadata is a good way just keep in mind document are often saved or duplicated with new names for version. Some saved image files may have metadata striped.  PSD files should not see metadata striped. If you use metadata you may want to save the document when you change the data to force the data to disk and also include the current backing file path in the metadata to be able to tell version from the original document.  Keeping data in the document I think would be better then an associated external files for copying and renaming documents may loose the associated with the external file.

                                                1 person found this helpful