Skip to main content
Participant
December 23, 2009
Question

Placing a file in an Action, pathing issues

  • December 23, 2009
  • 1 reply
  • 2507 views

I have created an action that will Place several local files into a Photoshop Document. I have them stored in the Presets/Actions folder for Photoshop CS3.

Here is the example path: Macintosh HD:Applications:Adobe Photoshop CS3:Presets:Actions:BROWSERS:firefox:botBar.png

This works fine for me (of course), however I want others to be able to use the Action without relinking. Is it possible to edit the path to be relative to the .atn file (and does it even work like that?)

Theory:

So I have my browsers.atn file in the roof of Adobe Photoshop CS3/Presets/Actions and my graphics in Adobe Photoshop CS3/Presets/Actions/Browsers/firefox/file.png. Would I be able to link to it like: Browsers/firefox/file.png?

Sorry if this is confusing. If this won't work, do I have any other options?

This topic has been closed for replies.

1 reply

Inspiring
December 23, 2009

As I understand it paths in action can't be relative.

But Xbytor has code that can be used as in install script that will place the image files where you want them, edit the paths in the action to those new paths, then load the action. The code is part of xtools http://sourceforge.net/projects/ps-scripts/files/xtools/

Participant
December 23, 2009

This either won't work or is above my skill level. I thought I was close at several points but I couldn't get it to do what I wanted. I also tried converting it to XML and editing the path that way, that didn't work either. Thank you for your feedback and help.

Inspiring
December 24, 2009

Here is what works for me.

Create a folder for your installer.

Create a sub folder named 'files' and one named 'xtools'.

Put the script you want to install along with any image resources in the 'files' subfolder, you can also put atn files that don't need path correction in this folder.

Copy the ChangePaths-1_1.jsx to the 'xtools' folder.

Convert the atn files that do need path conversions to XML. Add the suffix '-in' to those xml files i.e. 'actionName-in.xml'. Once converted place in the 'files' folder with the others.

Copy the following script and name it 'Installer-1_2.jsx'. Put that file in the main folder.

// needs files to install placed in files sub folder
// ChangePaths-1_1.jsx in xtools sub folder, any actions that have
// paths recorded need to be convert to xml with '-in'
// added to the base name. Do not include those atn files
// Action sets that don't have paths can be placed in files
// as atn
//
//
#target photoshop
//
// Installer.jsx
//
// $Id: Installer.jsx,v 1.2 2009/02/02 19:48:34 anonymous Exp $
// Copyright: (c)2009, xbytor
// License: http://creativecommons.org/licenses/LGPL/2.1
// Contact: xbytor@gmail.com
//

RELEASE = "v1.2";
CHANGEPATHS_SCRIPT = "ChangePaths-1_1.jsx";

function throwFileError(f, msg) {
  if (msg == undefined) msg = '';
  Error.runtimeError(9002, msg + '\"' + f + "\": " + f.error + '.');
};

isCS5 = function()  { return !!app.version.match(/^12\./); };
isCS4 = function()  { return !!app.version.match(/^11\./); };
isCS3 = function()  { return !!app.version.match(/^10\./); };
isCS2 = function()  { return !!app.version.match(/^9\./); };

isCompatible = function() {
  return isCS2() || isCS3() || isCS4();
};

isWindows = function() {
  return $.os.match(/windows/i);
};
isMac = function() {
  return !isWindows();
};
isVista = function() {
  return $.os.match(/vista/i);
};
isVista64 = function() {
  return $.os.match(/vista\/64/i);
};
isPhotoshop = function() {
  return app.name.match(/photoshop/i);
};
listProps = function(obj) {
  var s = '';
  for (var x in obj) {
    s += x + ":\t";
    try {
      var o = obj;
      s += (typeof o == "function") ? "[function]" : o;
    } catch (e) {
    }
    s += "\r\n";
  }
  return s;
};
XStdlib = function() {};       // Let's borrow some stuff....
XStdlib.logStr = '';
XStdlib.log = function(msg) {
  var file;

  if (!XStdlib.log.enabled) {
    return;
  }

  if (!XStdlib.log.filename) {
    return;
  }

  if (!XStdlib.log.fptr) {
    file = new File(XStdlib.log.filename);
    //if (file.exists) file.remove();
    if (!file.open("w")) {
      Error.runtimeError(19, "Unable to open log file " + file + ": "
                          + file.error);
    }
    file.seek(0, 0); // jump to the end of the file
    if (isMac()) {
      file.lineFeed = "unix";
    }
    XStdlib.log.fptr = file;

  } else {
    file = XStdlib.log.fptr;
    if (!file.open("e"))  {
      Error.runtimeError(19, "Unable to open log file " + file + ": "
                          + file.error);
    }
    file.seek(0, 2); // jump to the end of the file
  }
 
  XStdlib.logStr += msg + '\r\n';
  if (!file.writeln(new Date() + " - " + msg)) {
    Error.runtimeError(19, "Unable to write to log file " + file + ": "
                       + file.error);
  }
 
   file.close();
};
XStdlib.log.filename = undefined; //"~/logfile.txt";
XStdlib.log.enabled = true;

XStdlib.exceptionMessage = function(e) {
  var str = '';
  var fname = (!e.fileName ? '???' : decodeURI(e.fileName));
  str += "   Message: " + e.message + '\n';
  str += "   File: " + fname + '\n';
  str += "   Line: " + (e.line || '???') + '\n';
  str += "   Error Name: " + e.name + '\n';
  str += "   Error Number: " + e.number + '\n';

  if (e.source) {
    var srcArray = e.source.split("\n");
    var a = e.line - 10;
    var b = e.line + 10;
    var c = e.line - 1;
    if (a < 0) {
      a = 0;
    }
    if (b > srcArray.length) {
      b = srcArray.length;
    }
    for ( var i = a; i < b; i++ ) {
      if ( i == c ) {
        str += "   Line: (" + (i + 1) + ") >> " + srcArray + '\n';
      } else {
        str += "   Line: (" + (i + 1) + ")    " + srcArray + '\n';
      }
    }
  }

  if ($.stack) {
    str += '\n' + $.stack + '\n';
  }

  return str;
};
XStdlib.btExec = function(code, btapp) {
  if (!btapp) { btapp = BridgeTalk.appSpecifier; }

  BridgeTalk.bringToFront(btapp);

  var bt = new BridgeTalk();
  bt.target = btapp;
  bt.body = code;
  bt.send();
};


XStdlib.PRESETS_FOLDER =
  new Folder(app.path + '/' +
             localize("$$$/ApplicationPresetsFolder/Presets=Presets"));
XStdlib.SCRIPTS_FOLDER =
  new Folder(app.path + '/' +
             localize("$$$/ScriptingSupport/InstalledScripts=Presets/Scripts"));

//
// Options
//
Options = new Object();
Options.testMode = false;

Options.psScriptsFolder = XStdlib.SCRIPTS_FOLDER;
Options.myPicturesFolder = undefined; // created in checkConfig
Options.filesFolder = undefined;      // created in checkConfig
Options.xtoolsFolder = undefined;     // created in checkConfig
Options.atnScript = undefined;        // created in checkConfig
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// need to set Options.name before using installer
Options.name = '';
Options.LOG_FILE = "~/" + Options.name + "-installer.log";
Options.LOG_ENABLED = true;

//
// Installer
//
Installer = function() {
};
Installer.logstr = '';
Installer.log = function(str) {
  Installer.logstr += str;
};
Installer.getScriptFolder = function() {
  return Installer.getScriptFile().parent;
};
Installer.getScriptFileName = function() {
  var f = Installer.getScriptFile();
  return (f ? f.absoluteURI : '');
};
Installer.getScriptFile = function() {
  if (!isCompatible()) {
    return undefined;
  }

  var path = '';

  if (isCS2()) {
    var dbLevel = $.level;
    $.level = 0;
   
    try {
      some_undefined_variable;
    } catch (e) {
      path = e.fileName;
    }
   
    $.level = dbLevel;

  } else {
    path = $.fileName;
  }

  return new File(path);
};
Installer.loadActionFile = function(file) {
  XStdlib.log("Loading action file: " + decodeURI(file.fsName));
  Installer.loadActionFiles([file]);
  XStdlib.log("Loading action file completed.");
  return true;
};
Installer.loadActionFiles = function(files) {
  XStdlib.log("Loading action file: " + decodeURI(files));
  for (var i = 0; i < files.length; i++) {
    var file = files;
    XStdlib.log("Action files: " + decodeURI(file));
    XStdlib.btExec('app.load(new File("' + file.absoluteURI + '"));');
  }
  XStdlib.log("Loading action files completed.");
  return true;
};
Installer.createActionFiles = function(script, xmlFiles, newPath) {
  for (var i = 0; i < xmlFiles.length; i++) {
    var infile = xmlFiles;
    var outfile = new File(infile.parent + '/' +
                           infile.name.replace(/\-in.xml$/i, ".atn"));

    XStdlib.log("Converting action file: " + decodeURI(infile.fsName));

    var estr = "//@show include\r\n";

    estr += '//@include "' + script + '";\r\n';
    estr += "function main() {\r\n";
    estr += "  changePaths(\"" + infile + "\", \"";
    estr += outfile + "\", \"" + newPath + "\");\r\n";
    estr += "};\r\n";
    estr += 'main()';

    eval(estr);
  }
  return true;
};

Installer.run = function() {
  var inst = new Installer();
  var opts = Options;

  return inst.install(opts);
};
Installer.prototype.install = function(opts) {
  var self = this;

  // Check the package folder and the Photoshop and Bridge folders for sanity
  if (!self.checkConfig(opts)) {
    return false;
  }

  var cstr = (opts.name + " " + RELEASE + " will be installed at:\r\n\t" +
              decodeURI(opts.psScriptsFolder.fsName) +
              "\r\n\r\nand images at:\r\n\t" +
              decodeURI(opts.myPicturesFolder.fsName) + "\r\n\r\n" +
              "Do you wish to continue?");

  if (!confirm(cstr)) {
    return false;
  }

  var folder = opts.filesFolder;
  var imageFiles = folder.getFiles("*.psd");
  if (!self.copyFiles(imageFiles, opts.myPicturesFolder)) {
    return false;
  }

  var scripts = folder.getFiles("*.jsx");
  if (!self.copyFiles(scripts, opts.psScriptsFolder)) {
    return false;
  }

  var atnXmlFiles = folder.getFiles("*.xml");
  if (!Installer.createActionFiles(opts.atnScript, atnXmlFiles,
                                   opts.myPicturesFolder)) {
    return false;
  }

  var atnFiles = folder.getFiles("*.atn");
  if (!Installer.loadActionFiles(atnFiles)) {
    return false;
  }
 
  return true;
};

Installer.prototype.checkConfig = function(opts) {
  var self = this;

  XStdlib.log("Checking configuration...");
  XStdlib.log("Checking for Photoshop");
  if (!isPhotoshop()) {
    return self.error("Please run this script from Photoshop.");
  }
  XStdlib.log("Photoshop good!\r\n");

  XStdlib.log("Checking for CS2/CS3/CS4");
  if (!isCompatible()) {
    return self.error(opts.name + " is compatible with only " +
                      "Photoshop CS2/CS3/CS4.");
  }
  XStdlib.log("CS2/CS3/CS4 good!\r\n");

  XStdlib.log("Checking for Photoshop Scripts folder: " +
             decodeURI(opts.psScriptsFolder));
  if (!opts.psScriptsFolder.exists) {
    return self.error("Photoshop Scripts folder not found.\r\nExpected: " +
                      opts.psScriptsFolder);
  }
  XStdlib.log("Photoshop Scripts folder good!\r\n");

  XStdlib.log("Checking for 'My Pictures' folder...");

  var docFolder = Folder.myDocuments;
  if (!docFolder) {
    if (isMac()) {
      docFolder = new Folder("~/Documents");
    } else {
      docFolder = new Folder("~/My Documents");
    }
  }

  var picFolder = new Folder(docFolder + "/My Pictures");
  if (!picFolder.exists) {
    return self.error("\"My Pictures\" folder not found.\r\nExpected: " +
                      opts.myPicturesFolder);
  }
  opts.myPicturesFolder = picFolder;

  XStdlib.log("'My Pictures' folder good!");

  XStdlib.log("Checking installation package");

  opts.sourceFolder = Installer.getScriptFolder();

  opts.filesFolder = new Folder(opts.sourceFolder + "/files");

  if (!opts.filesFolder.exists) {
    return self.error("Bad installation package, folder not found:\r\n" +
                      decodeURI(opts.filesFolder));
  }
  opts.xtoolsFolder = new Folder(opts.sourceFolder + "/xtools");
  if (!opts.xtoolsFolder.exists) {
    return self.error("Bad installation package, folder not found:\r\n" +
                      decodeURI(opts.xtoolsFolder));
  }

  var script = new File(opts.xtoolsFolder + '/' + CHANGEPATHS_SCRIPT);
  if (!script.exists) {
    return self.error("Bad installation package, file not found:\r\n" +
                      decodeURI(script));
  }
  opts.atnScript = script.absoluteURI;

  return true;
};

Installer.prototype.error = function(msg) {
  var emsg = "Error: " + msg;

  XStdlib.log(emsg);
  alert(emsg);
  return false;
};

Installer.prototype.copyFile = function(srcFile, target) {
  var self = this;

  if (!(target instanceof Folder)) {
    Error.runtimeError(9002, "Internal Error: copyFile(" +
                        srcFile + ", " + target + ")");
  }

  if (!target.exists) {
    Error.runtimeError(9002, "The folder " + decodeURI(target.fsName) +
                        " does not exist.");
  }

  var testRO = new File(target + '/test.tmp');
  if (!testRO.open("w")) {
    var msg = ("The folder " + decodeURI(target.fsName) +
              " is 'readonly'. Please either invoke Photoshop " +
              "with Administrator permissions for installation " +
              "(use 'Run as adminstrator' on XP/Vista) or change the " +
              "permissions on the folder to allow the installer to " +
               "write files to that folder.\r\n\r\n");
    var emsg = XStdlib.exceptionMessage(new IOError()) + "\r\n\r\n" + msg;
       XStdlib.log(emsg);
       alert(msg);
       return false;
      
  } else {
    testRO.close();
       testRO.remove();
  }

  XStdlib.log("Copy file from " + decodeURI(srcFile) + " to " +
             decodeURI(target));
  var file = new File(target + "/" + srcFile.name);
  if (!srcFile.copy(file)) {
    var msg = "Copy failed: " + srcFile.error + "\r\n" + decodeURI(srcFile);
    if (file.exists) {
      msg += ("\r\n\r\nAn existing copy of this file exists and must be " +
              "removed manually before attempting installation.");
    }
    return self.error(msg);
  }
  return true;
};

Installer.prototype.copyFiles = function(src, target) {
  var self = this;

  XStdlib.log("\r\nCopying files from " + decodeURI(src) + " to " +
             decodeURI(target));

  var files;
  if (src instanceof Folder) {
    files = src.getFiles();
  } else if (src instanceof Array) {
    files = src;
  } else {
    Error.runtimeError(19, "src");
  }

  for (var i = 0; i < files.length; i++) {
    var file = files;
    if (file instanceof Folder) {
      continue;
    }
    if (!self.copyFile(file, target)) {
      return false;
    }
  }
  return true;
};

Installer.popup = function(title, str) {
  var w = new Window('dialog', title, [200,200,1000,750]);
  var t = w.add('edittext', [10,10,790,490], '',
                {multiline:true, readonly:true});
  t.text = str;
  w.add('button', [300,500,350,520], 'OK');
  w.show();
};

Installer.main = function() {
  XStdlib.log.filename = Options.LOG_FILE;
  XStdlib.log.enabled = Options.LOG_ENABLED;

  var rc = false;
  XStdlib.log("Start");
  XStdlib.log("Version: " + RELEASE);
  XStdlib.log("App: " + app.name);
  XStdlib.log("App Version: " + app.version);
  XStdlib.log("OS: " + $.os);

  try {
    rc = Installer.run();

  } catch (e) {
    var msg = (XStdlib.exceptionMessage(e) + "\"\r\n" +
               "Installation terminated.");
    XStdlib.log(msg);
    alert(msg);
  }

  XStdlib.log("\r\n" + Options.name + " Installation completed status: " +
             (rc ? "good." : "*** failed ***"));
  XStdlib.log("Stop");

  if (confirm("Installation " + (rc ? "succeeded!" : "failed!") +
              "\r\n\r\nView log?")) {

    Installer.popup(Options.name + " Installation: " + XStdlib.log.filename,
                     XStdlib.logStr);
  }

  if (rc) {
    alert("You will need to restart Photoshop to enable " + Options.name + ".");
  }
};
Installer.main();

"Installer.jsx";
// EOF

Note it expects any image files to be psd files. You can change the mask in the line var imageFiles = folder.getFiles("*.psd"); to use other formats.

The install needs to be run from Photoshop and you might need to be logged is a administrator with some OSs.

The install script and concept is from Xbytor.