XToolkit Beta1

Discussion of the xtools Toolkit

Moderators: Tom, Kukurykus

xbytor

XToolkit Beta1

Post by xbytor »

I didn't take all that much code to be able to read an ActionFile and execute it step by step. This is just a basic runner, more of a proof of concept than anything else.

There are a whole lot of interesting things that can be done with something like this. But, as is, it does illustrate the power of xtools.

Code: Select all//
// ActionRunner
//
// $Id: ActionRunner.js,v 1.1 2005/10/18 15:10:33 anonymous Exp $
// Copyright: (c)2005, xbytor
// License: http://creativecommons.org/licenses/LGPL/2.1
// Contact: xbytor@gmail.com
//
//@show include
//
//@includepath "/c/Program Files/Adobe/Adobe Photoshop CS2/xtools"
//
//@include "xlib/Action.js"
//@include "xlib/xml/atn2bin.jsx"
//

ActionRunner = function(action) {
  var self = this;

  self.action          = action;
  self.playbackOptions = undefined;
  self.enabled         = undefined;
  self.dialogMode      = undefined; // DilaogModes.ALL ERROR NO

  self.ip = 0; // instruction pointer
};
ActionRunner.prototype.typename = "ActionRunner";

ActionRunner.prototype.exec = function() {
  var self = this;
  while (self.step()) {
    ; // empty
  }
};

ActionRunner.prototype.step = function() {
  var self = this;
  var action = self.action;

  if (self.ip >= action.getCount()) {
    return false;
  }

  var ai = action.byIndex(self.ip);

  if (ai.enabled) {
    $.level = 1; debugger;
    if (ai.identifier == ActionItem.TEXT_ID && ai.name == "Scripts") {
      self.runScript(ai.descriptor);
    } else {
      var execId;
      if (ai.identifier == ActionItem.TEXT_ID) {
        execId = PSConstants.lookup(ai.name);
      } else {
        execId = ai.itemID;
      }
     
      var desc = ai.hasDescriptor ? ai.descriptor : undefined;
      var dmode = ai.withDialog ? DialogModes.ALL : DialogModes.ERROR;
      executeAction(execId, desc, dmode);
    }
  }

  self.ip++;
  return true;
};

ActionRunner.prototype.runScript = function(desc) {
  var file = desc.getPath(cTID("jsCt"));
  var str = '//@include "' + file.absoluteURI + '";\r\n';
  eval(str);
};

function main() {
  var infile = new File("/c/work/XActions.atn");

  var actFile = new ActionFile();
  actFile.read(infile);

  var act = actFile.actionSet.getByName("Test");
  var runner = new ActionRunner(act);
  runner.exec();
};

main();

"ActionRunner.js";

// EOF
xbytor

XToolkit Beta1

Post by xbytor »

Here's some docs, for those of you lurking and not playing.

README for xtools/xapps
$Id: README,v 1.2 2005/10/21 15:07:55 anonymous Exp $

This directory contains application scripts. These scripts may be run directly
from the File->Scripts menu. As a part of the installation process, an
ActionSet called XToolkit is loaded into Photoshop containing an Actions that
invoke these scripts.

These scripts are divided into two categories: Tookit Scripts and Sample
Scripts.

=============================== Toolkit Scripts ==============================

The scripts in this section are useful for the inteneded audience of this
tookit: other Photoshop Javasript authors.

ActionFileFromXML.js
ActionFileToXML.js
The two scripts convert Action (.atn) Files to and from XML. This
capability makes it possible to edit actions as:
- ActionDescriptor constructs
- XML DOM objects
- strings
ActionFileFromXML has sample code in it (in comments) that shows how
to change the paths of all scripts in an action file to a new
directory.

ActionLister.js
This script reads the runtime ActionsPalette for a list of all
ActionSets and Actions. The class definitions that this information
is put into is copiped from xlib/Action.js. The number of ActionSets
and Actions is popped up in an alert. The code in this script could be
used by UI code in other scripts to allow a user to select an Action
from the current runtime palette.

BackupActions.js
After bashing my ActionsPalette a couple of times while developing
some Action management routines, I wrote this script that makes backing
up my ActionsPalette a simple mouse click. With my luck, I should
probably hotkey the Action that calls this script as well.

FontLister.js
All of the information about fonts that can be determined from the
Javascript side is accessed here. For each font, the lister returns
the font's name, postscript name, family, and style. The 'main'
routine calls the functions to retrieve all of this information, then
writes it all out to a CSV file. Note: This will _not_ work in PS7.

Getter.jsx
This script accesses just everything that can be reached from the
Javascript API. This includes:
- Application Info
(Preferences, PresetManager Info, Fonts, etc...)
for each open document
- Document Info
- Background Info
- Layer Info
- Channel Info
- Path Info
- History Info

If you can get information you want from the Javascript API, take a
look at the output of this script. This has everything you can get to,
although you do have to go through the ActionDescriptor API to get at
it.

Install.js
This is the installation script for XToolkit. It's not all that complex
except for the part where a new .atn file is created by modifying an
existing one.

jsh.js
This is my most indispenible tool. It is an interactive command line
shell (sort of) for executing javascript code within Photoshop. I use
whenever I am writing new code.

PresetLister.js
This is another Lister script that lists out all of the currently
loaded brushes, colors, gradients, styles, patterns, shaping curves,
custom shapes, and tool presets. The 'main' function writes this info
out to a text file. Scripts developed by other people could probably
find something more useful to do with this information.


=============================== Sample Scripts ==============================

These scripts show how different parts of the toolkit can be used. Most of the
scripts here were written to support my workflow. Some are 'old' and my be a
bit rusty in places. They are provided here as examples, not finished products.

ActionStepper.js
ActionStepper runs all of the Actions in an ActionSet on the current
document. After an action is run, the new image is saved and the
document is reverted to is prior state before running the next action.
This is useful for things ActionSets like Image Effects or Frames.
If action's in the set require having a selection prior to running the
action, you should probably move them to a different action set and run
those with an active selection.

ColorBookDemo.js
A ColorBook, in PS-speak, is a stored color palette. This script reads
all of the color books from 'Presets/Color Books' and writes what
information it can out to a text file.

There rest of these scripts were written to support my specific needs. A lot of
my work last year was in attempting to make older digitial camera images (from
1996 on) more presentable as well as cataloging, updating metatdata, etc...
While it is unlikely that any of these scripts will be directly useful to
anybody, the may help to illustrate how different parts of the toolkit and
the Photoshop Javascript API can be utilized.

AddWatermark.js
This script is a descendent of the first non-trivial script I wrote in
Photoshop. There is no user interface to speak of. It's all configured
by code. There is support for saved options, but I don't know if that
still works.

AdjustLevels.js
AdjustRGBLevels.js
These are some alternatives to the Adjust Levels facilities in PS.

Cnvt.js
This is an export-style script. After I've completed tweaking a set of
images, I run this script to add a watermark and then save out to some
set of image types and sizes.

Normalilze.js
This script imports images and 'normalizes' them so that they have
consistent metatdata, color profile, bit depth, size, etc... A noise
reduction action may also be run as a part of the normalization
process.

Resize.js
A simple example of calling code in xlib/ResizeImage.js

UpdateMetadata.js
A basic script for updating metadata.
[/quote]
Andrew

XToolkit Beta1

Post by Andrew »

Hi X, thanks for this, it really helps.

Tell me, would it be difficult (I get the ipression it may not be) to extract from XTools a module / bunch of code, that reads an action in the actions palette (it may or may not have been saved as an atn - though I could live with making that a requirement), converts it to code and runs it - thereby allowing a script within an action to be run by another script.

I am working on a batching script right now for which that would be a delicious finishing touch (which I would credit you for of course). I already have a way to achieve it (by splitting the action and eval'ing the script), but just pointing at a single action straight from the actions palette would be better still.

Andrew
xbytor

XToolkit Beta1

Post by xbytor »

It is possible to do this. You would need the files stdlib, Action, ActionRunner, atn2bin, and maybe PSConstants, though that dependency can be removed.

To execute an action like you want you would need to extract the Action from the .psp file (or save it from the PS palette UI, if you can figure out how to do that from JS). That wouldn't be to hard to write. It's easiest if you have an atn file. And much faster. The code in ActionRunner can then process the Action without ever leaving the script.

Were you looking for a single file or can you live with multiple includes?

Either way, I can package up something off my current code base over the weekend if you like.

One fine point. This does _not_ convert the ActionFile to code: it loads the binary data and executes that I haven't implemented an Action->JSCode translator yet. That translator would result in code that looks like ScriptListener code, or, at least, what ScriptListener code would look like if I were the one writing the code generator. That's on my task list. There are a few people intersted in this, including me.
Andrew

XToolkit Beta1

Post by Andrew »

Thanks for the quick reply. I would prefer to put the code inside my script so the main issue is can the task be done - then the work is isolating the code. I don't mind doing a good bit of this.

To describe the task:

Assume we are running a script that uses doAction to target an action containing:

action steps Pre
script step
action steps Post

I want to be able to run that action from a script - so what the code needs to be able to do is:

run action steps 1
run the script via eval or some other method
run action step 2

More sophisticated (unnecessary) versions would also be able to handle:

action steps Pre 1
script 1 step
action steps Post 1
action steps Pre 2
script 2 step
action steps Post 2
etc

or even

action step Pre 1 might contain a reference to another action that runs a script as well.

I can already do the first and even the second version by getting the user to have the Pre and Post steps as different actions - so they build up the structure themselves. But obviously it would be far nicer to be able to allow them to just specify a single action target and away they go.

Andrew
Andrew

XToolkit Beta1

Post by Andrew »

Hi again

I have been looking at this more closely now. These action scripts are remarkable! I can convert to and from xml and edit the xml no problem. But I am beginning to think that until it is possble to edit an xml atn file and then run that edited xml dirctly (without loading) as an action - or the same with some quasi X-SL code - it is perhaps a bit cumbersone as it still leaves loading the atn into the actions palette and perhaps removing it from the palette later. So for now I am going to go with something along the lines of what I ws thinking previously, allowing a ganged set of scripts and actions to be run rather than trying to decode actions with scripts in them.

Andrew