Edit in GitHubLog an issue

batchPlay

At the heart of our APIs is batchPlay, a method that executes one or more Photoshop action commands and return their results.

batchPlay is an advanced API, and we recommend trying to first use the DOM APIs before resorting to using batchPlay.

API#

BatchPlay can directly be accessed from the Photoshop action module, and as most other APIs it is asynchronous by default and returns a promise.

Copied to your clipboard
require('photoshop').action.batchPlay(descriptors: ActionDescriptor[], options: Object): Promise<Object[]>

Below we will dive into both how action commands are defined in JavaScript, and what options are available.

Descriptors#

The first argument to batchPlay is an array of descriptors (also called action descriptors).

UXP plugins for Photoshop use a textual representation of these action descriptors. This format is sometimes referred to as actionJSON.

An action descriptor contains the following components:

  • The command. This describes the desired Photoshop command. The command is specified via the _obj keyword.
  • The target for the command. This describes the (DOM) element that the command should operate on. The target is specified via the _target keyword. This property is sometimes omitted. If omitted, the command operates on a default element. The default element is typically the object that is active in the UI.
  • Command parameters. Describes the various parameters for the command.
  • Command execution options. Options related to how the command should be executed.

The following is an example of an actionJSON command for hiding a layer :

Copied to your clipboard
1{
2 _obj: "hide",
3 _target:[
4 {_ref: "layer", _enum: "ordinal", _value: "targetEnum"},
5 {_ref: "document", _enum: "ordinal", _value: "targetEnum"}
6 ]
7}

The command is hide as specified by the _obj keyword.

The value of _target is called an action reference and specifies which layer should be hidden. The action reference specifies the target in reverse order - from most specific to least (similar to a postal address). To find the DOM object for a target you go from the last value in the list to the first. In this example we have:

  • {"_ref":"document", "_enum":"ordinal","_value":"targetEnum"} First find the target document. It is specified as ordinal and targetEnum. This means the active (front most) document.
  • In that document we look for the layer specified as {"_ref":"layer","_enum":"ordinal","_value":"targetEnum"}. This means the active (selected) layer.

For this command we are therefore targeting the selected layer in the front most document. targetEnum is the default value for ordinal enumerations and can be omitted. See the section on action references below for details.

This command modifies the Photoshop state and must therefore be executed from within a modal scope. See the documentation of executeAsModal for details. The following JavaScript uses batchPlay to hide the active layer:

Copied to your clipboard
1async function hideActiveLayer() {
2 return await require("photoshop").action.batchPlay([{_obj:"hide", _target:[{_ref: "layer", _enum: "ordinal"},{_ref: "document", _enum: "ordinal"}]}], {});
3}
4let result = require("photoshop").core.executeAsModal(hideActiveLayer, {"commandName": "Hide Layer"});

Here is another example of batchPlay and actionJSON. This examples returns the value of a specific document pixel. This example illustrates providing samplePoint as an additional command parameter.

Copied to your clipboard
1async function samplePixel() {
2 return await require("photoshop").action.batchPlay([{
3 _obj: "colorSampler",
4 _target: {_ref: "document",_enum: "ordinal",_value: "targetEnum"},
5 samplePoint: {
6 horizontal: 100,
7 vertical: 100
8 }
9 }], {});
10}
11let result = await require("photoshop").core.executeAsModal(samplePixel, {"commandName": "Sample Pixel"});

Sample output from the colorSampler command:

Copied to your clipboard
[{"colorSampler":{"_obj":"CMYKColorClass","black":0,"cyan":26.27,"magenta":4.71,"yellowColor":0},"sampledData":true}]

Accepted action descriptors#

The composition of action descriptors can be complicated. Photoshop provides a number of ways that help a developer understand which descriptors Photoshop accepts.

The first way is to use the Actions panel. Create a new action and record the commands that you want to run from JavaScript. Then select the action in the Actions panel, or one or more individual steps in the action. Now select Copy As JavaScript from the panel flyout menu. This will copy UXP compatible JavaScript for the selected items to the clipboard. Copy As JavaScript is available from the flyout menu when developer mode is enabled. The following is an example of copying a single "make layer" command as JavaScript:

Copied to your clipboard
1async function actionCommands() {
2 let command;
3 let result;
4 let psAction = require("photoshop").action;
5
6 // Make layer
7 command = {"_obj":"make","_target":[{"_ref":"layer"}],"layerID":2};
8 result = await psAction.batchPlay([command], {});
9}
10
11async function runModalFunction() {
12 await require("photoshop").core.executeAsModal(actionCommands, {"commandName": "Action Commands"});
13}
14
15await runModalFunction();

Another option is to create a listener function in JavaScript. This is done by providing the global event hook to a low level API. This call only works when developer mode is enabled.

Copied to your clipboard
require('photoshop').action.addNotificationListener(['all'], (event, descriptor) => {console.log("Event:" + event + " Descriptor: " + JSON.stringify(descriptor))});

Another option is to use the developer UI to log action descriptors to a file. When "developer mode" is enabled, then the following menu items will be available:

  • "Plugins > Development > Record Action Commands..." This menu item can be used to save any Photoshop command as an action descriptor to a file. After selecting the menu item and selecting the destination file, perform one of more Photoshop commands using the normal UI. Then choose "Plugins > Development > Stop Action Recording". The destination file will contain actionJSON for the performed commands.
  • "Plugins > Development > Record Action Notifications..." This menu item will save both commands and change notifications to the selected destination file.

Lastly, you can record your actions as a standard Photoshop action using the Actions panel. Then export actions to an actionJSON format by doing the following:

  • Select the action set that contains the command.
  • Press (macOS)"shift+option+command" or (Windows)"shift+control+alt" and choose "Save Actions..." from the panel fly-out menu.

Command execution options#

An action descriptor can include a _options property. If present then its value specifies how the command is executed. _options can contain the following values:

  • dialogOptions: string. This value controls how Photoshop shows UI during the execution of the command. The possible values are:
    • "silent": The command is executed without UI. If an error occurs, or if the command needs additional parameters, then a scripting error is returned. This is the default value.
    • "dontDisplay": The command is executed without UI unless an error occurs, or if the command need additional parameters. In that case UI may be shown.
    • "display": Standard UI related to the command is shown.

options#

The second argument of batchPlay adjusts the options. Below is the list of options that are most commonly needed.

synchronousExecution (default: false)#

If set to true, batchPlay will block the entire scripting thread until it resolves, then return the value(s). We use this in the DOM API for property getters and setters, as it allows for simpler code.

JavaScript code that use batchPlay directly should avoid using this keyword if possible, and instead use the default form that returns a promise.

historyStateInfo (default: none)#

This option is deprecated as of Photoshop 2022. New JavaScript code should use the history suspension mechanism provided by executeAsModal

Request Photoshop to describe the entire batchPlayed series of actions as a single history state. History state should have two properties:

  • name: A string to show the name of the history event in History panel

  • target: A document reference for where to create the history state at. Keep in mind that if you point at a different document, or if your batchPlays aren't all acting on the same document, the behavior is undefined.

    Plugins that use api version 2 may find it easier to use the history state functionality that is provided via the executionContext object.

Result value#

batchPlay returns a promise. This promise is rejected if the batchPlay command is invalid. This is the case when incorrect arguments are provided. An example of a batchPlay rejection is:

Copied to your clipboard
require("photoshop").action.batchPlay(true, {});

This example provides an incorrect initial argument to batchPlay. The initial argument is expected to be a descriptor list and not a boolean. For cases such as this, the promise is rejected with an appropriate error message. The above example generates the following rejection:

Copied to your clipboard
1[[PromiseState]]: "rejected"
2[[PromiseResult]]: Error: Argument 1 has an invalid type. Expected type: array actual type: boolean

A batchPlay command can also fail if a valid command cannot be procesed by Photoshop. This is most often the case if the specified target element does not exist.

The previously shown example to hide the active layer will fail if no documents are open, because the command can then not find the target layer to hide. For such cases the batchPlay promise is resolved successfully, and an error message is returned in a list form.

Copied to your clipboard
1[
2 {
3 _obj: "error"
4 message: "The object “current document” is not currently available."
5 result: -25922
6 }
7]

The elements in the returned list match the action descriptor list passed to batchPlay. The first item in the returned list is the result of the first action descriptor in the batchPlay, and so forth. The properties of the returned elements are:

  • _obj: string. The value is "Error"
  • message: string. A localized error message
  • result: number. An internal Photoshop error code. A "0" means "no error". -128 means that the user cancelled the operation. Other values are possible.

Action references#

Action references specify which DOM objects a command operates on. An action reference is specified using the _target keyword. An action reference is a list of item references that specifies how to find the DOM element starting from the application DOM element. Each item in the list can use one of the following forms:

Reference formSyntaxExampleNotes
ID{_ref:className, _id:number}{_ref:"document", _id: 123}
Index{_ref:className, _index:number}{_ref:"document", _index: 1}Indices are 1 based
Name{_ref:className, _name:string}{_ref:"document", _name: "Untitled-1"}
Enumeration{_ref:className, _enum: "ordinal", _value: enumerationSpecifier*}{_ref:"document", _enum: "ordinal", _value:"targetEnum"}
Property{_property:propertyName}{_property:"title"}

We recommend using the ID form whenever possible because the ID of an object does not change during the lifetime of the Photoshop session. The index will change if elements are added or removed in front of the specified object.

The enumerationSpecifier is command specific, but the most common value is targetEnum meaning the currently selected or active object of the specified class. Other possible values include: "first", "last", and "front". When using the enumeration form, targetEnum is the default value for the _value property.

Getting state from Photoshop#

batchPlay can be used to obtain state from Photoshop. To do this, use the action command "get" with a target property.

The following sample obtains the title of a target document.:

Copied to your clipboard
1var target = {_ref:[{"_property": "title"}, {_ref: "document", _id: someDocumentID}, {"_ref":"application"}]};
2var command = {"_obj": "get", "_target": target};
3let result = await photoshop.action.batchPlay([command], {});

A possible result from running this command is:

Copied to your clipboard
[{"title":"Untitled-1"}]

If you use the "get" command without a target property, then all possible properties for the target are returned. The following lists all possible document properties:

Copied to your clipboard
1var target = {_ref:[{_ref: "document", _id: someDocumentID}, {"_ref":"application"}]};
2var command = {"_obj": "get", "_target": target};
3let result = await photoshop.action.batchPlay([command], {});

A possible result from running this command may include the following:

Copied to your clipboard
[{"mode":{"_enum":"colorSpace","_value":"RGBColor"},"bigNudgeH":655360,"bigNudgeV":655360,"rulerOriginH":0,"rulerOriginV":0,"width":{"_unit":"distanceUnit","_value":504},"height":{"_unit":"distanceUnit","_value":360},"resolution":{"_unit":"densityUnit","_value":300},"title":"Untitled-1","fileInfo":{"_obj":"fileInfo"},"numberOfPaths":0,"numberOfChannels":3,"numberOfLayers":0,"targetPathIndex":-1,"workPathIndex":-1,"clippingPathInfo":{"_obj":"clippingInfo","clippingPathIndex":-1,"clippingPathFlatness":0}, . . . ]

Using "get" without a property is intended for use during the development of a plugin. This for allows a developer to understand which properties a given element supports.

A shipping plugin should not obtain all properties for a given target because this may be slow, and may become slower in the future when additional properties are added.

Multi-Get#

In some cases you may want to obtain several property values from the same target, or get the same property from several similar targets. Examples of this are:

  • Get the name, the id, and the color mode for a specific document.
  • Get the id's of all open documents.

While you can issue multiple "get" statements to get this information, it is more efficient to use the multiGet command. A multiGet command has the following form:

  • _obj: must be "multiGet".
  • _target: a target reference that specifies a base object.
  • extendedReference: a list describing what values to return from the base object. The extendedReference has either one or two elements. The first element is a property-list. The second element can be used to specify an element range.
  • options: describes how the command should react if any of the requested values are unavailable. options can include:
    • failOnMissingProperty: A boolean describing what should happen if one of the target elements do not expose one of the requested properties. The default value is true, meaning that the command fails if a requested property is not available.
    • failOnMissingElement: A boolean describing what should happen if one of the target elements do exist. The default value is true, meaning that the command fails if any of the requested element do not exist.

The following example illustrates how to get the value of multiple properties on the active layer:

Copied to your clipboard
1layerProperties =
2 { _obj: "multiGet",
3 _target: { _ref: [{_ref: "layer", _enum: "ordinal"}, {_ref: "document", _enum: "ordinal"}]},
4 extendedReference: [["name", "layerID", "opacity"]],
5 options: {failOnMissingProperty:false, failOnMissingElement: false}
6 };
7result = await require("photoshop").action.batchPlay([layerProperties], {});

This command will generate a result such as the following:

Copied to your clipboard
[{"name":"Layer 4","layerID":5,"opacity":255}]

In this example the base object is a layer. The extendedReference specifies the list of properties to return from the target layer.

The following example illustrates how to get the value of multiple properties on the first two layers:

Copied to your clipboard
1layerProperties =
2 { _obj: "multiGet",
3 _target: { _ref: [{_ref: "document", _enum: "ordinal"}]},
4 extendedReference: [["name", "layerID", "opacity"], {_obj: "layer", index:1, count:2}],
5 options: {failOnMissingProperty:false, failOnMissingElement: false}
6 };
7result = await require("photoshop").action.batchPlay([layerProperties], {});

This command will generate a result such as the following:

Copied to your clipboard
[{"list":[{"name":"Layer 1","layerID":2,"opacity":255},{"name":"Layer 2","layerID":3,"opacity":255}]}]

In this example we want to obtain the value from several layers, and this mean that the base object as specified by the _target is a document. The extendedReference is used in its two element form to specify a property list and a range of layers.

The element range specifier can use count equal to -1 to specify all elements. Therefore to get the name of all layers in a document, one can use the following multiGet command:

Copied to your clipboard
1layerProperties =
2 { _obj: "multiGet",
3 _target: { _ref: [{_ref: "document", _enum: "ordinal"}]},
4 extendedReference: [["name"], {_obj: "layer", index:1, count:-1}],
5 options: {failOnMissingProperty:false, failOnMissingElement: false}
6 };
7result = await require("photoshop").action.batchPlay([layerProperties], {});

This command will generate a result such as the following:

Copied to your clipboard
[{"list":[{"name":"Layer 1"},{"name":"Layer 2"},{"name":"Layer 3"},{"name":"Layer 4"}]}]

Legacy notes#

batchPlay is the evolution of executeAction from ExtendScript. Where executeAction could only play one descriptor at a time, batchPlay accepts an array of action descriptors.

In ExtendScript, we provided a class around constructing descriptors, references, and putting values in. With batchPlay, we have replaced these related classes with actionJSON.

If you have used executeAction in ExtendScript, you are probably familiar with 4 character codes (OSTypes) and helper methods around them. In actionJson we prefer extended string identifiers such as colorSampler. However, you can still use an OSType by prepending it with a $ sign and passing that as a string, like '$app ' (mind the space!).

  • Privacy
  • Terms of Use
  • Do not sell my personal information
  • AdChoices
Copyright © 2022 Adobe. All rights reserved.