How To Get BatchPlay To Work With API 2

The following code which was recorded in Alchemist creates a Curves adjustment layer.

I just cannot get it to run using the API-2. Can anyone see what I have done wrong please.

const core = require("photoshop").core;

function curves() {

    await core.executeAsModal(() => {

        batchPlay(
            [{
                _obj: "make",
                _target: [{
                    _ref: "adjustmentLayer"
                }],
                using: {
                    _obj: "adjustmentLayer",
                    type: {
                        _obj: "curves",
                        presetKind: {
                            _enum: "presetKindType",
                            _value: "presetKindDefault"
                        }
                    }
                },
                _options: {
                    dialogOptions: "dontDisplay"
                }
            }], {
                synchronousExecution: false,
                modalBehavior: "fail"
            });
    })

}
document.getElementById("curves").addEventListener("click", curves);
1 Like

Download this sample plugin. It is a very basic working example of an API2 plugin. I made this for a bug report I submitted to Adobe. The bug has nothing to do with the executeAsModal part and the method in this plugin works for that.

https://damonbell.com/downloads/text-resize-bug_PS.ccx

Thanks Damon, I will do that now.
This move over to API-2 is giving me some issues at the moment.

There were a few things that changed, like the DOM for layer kind changed. PSAlerts are now done through “core”, not “app”. Everything worked though, except not being able to get user interaction with Photoshop dialogs. That killed the conversion for 3 of my 10 plugins. I am still going to convert the other 7 to API2.

The history state consolidation works great in API 2. You’ll need to put all of your batchPlay and other code into one executeAsModal function if you want to do that. Then you can use the history state option. Just read up on the docs for that.

What I have learnt so far is …

In the Manifest the option to include the API version is optional.
If you target the host at 23.0.0 it will default to API 2 and if you target the host at below 23.0.0 if defaults to API - 1

I’m guessing the way forward is to target Host = 23.0.0 and just hope all users update to the latest version of Photoshop when it is released

Are you sure about that? I have API 1 plugins that don’t include the API version in the manifest. They run fine as API 1 for 23.0.0.

I read it here, scroll down to near the bottom

Photoshop Product specific manifest (adobe.com)

As of now, my API 1 plugins are running fine in 23.0.0 without updating the manifest. However, it is easy to do so I will update it to add version 1 to it to ensure they continue to work in the future.

What is VERY concerning is the part in the link about API 1 being officially deprecated. This would be very bad for 3 of my 10 plugins which need user interaction with Photoshop dialogs. For some of my plugins, I use "dialogOptions": "display" in some of the plugins which does not work in API2.

I really need to know what the plan is for this.

@kerrishotts Is there a plan to implement a way in API 2 to allow for user dialog interaction with Photoshop dialogs. If so, will this be implemented before API 1 stops working as mentioned in the new docs?

From the Adobe docs:
With the introduction of apiVersion = 2, the original implementation is formally deprecated, and support for apiVersion 1 will be removed in a future major update to Photoshop. As such a number of new features are only available for apiVersion 2 plugins. apiVersion 2 only features include: new DOM v2, support for suspend and resume of multiple history states at the same time.

Out of interest, is the reason why you are still going to use API 1 because of this user interaction with dialogs.

When you are converting API to API2 are you re-writing them or just adding the required bits

The user dialog interaction is the only thing holding me back from converting to API 2 for 3 of the plugins. I have 7 others that I am converting to API 2.

Nothing needs rewritten. You should be able to use all of your current batchPlay code as is. Just use executeAsModal on the function the batchPlays are in. So if you have a function called runSomeTask() for example that has a bunch of batchPlay mixed with other JS coding, then use use the executeAsModal only for the runSomeTask() function, not each individual batchPlay.

So if I have you correct, it will go something like this…

await core.executeAsModal(() => {

    //  BatchPlay stuff goes here


   //  More BatchPlay stuff goes here


   //  Even More BatchPlay stuff goes here

})

Yes, and you can also have any other JS coding between the batch Plays. You can consolidate the entire history to that 1 function. The new suspend history works awesome, which really has me bummed because I need that too for the plugin I am currently working on. So basically, I had to decide between history state consolidation and user dialog interaction. The user dialog interaction was the far higher priority though.

Do you have any sample code for the history or is the documentation easy to follow

Not really without piecing somthign together from my rat’s nest of coding in my plugins.

Just make sure to use async on the execute as modal function. See the plugin example from the link of where it uses async.

Really, it is very simple once you figure out where to put the executeAsModal.

I still cannot get this BatchPlay to work with PS 23.0.0

I downloaded your ccx example and even put my BatchPlay code inside your exeModal function but yet it will not run for some reason.

As a last resort, I even recorded a new recording with Alchemist but nothing.

var app = require('photoshop').app;
var batchPlay = require("photoshop").action.batchPlay;
var core = require('photoshop').core;
var exeModal = require('photoshop').core.executeAsModal;
var psAlert = require('photoshop').core.showAlert;


document.getElementById("test").addEventListener("click", async function () {

  await exeModal(async function () {

    await batchPlay(
      [{
        _obj: "fill",
        using: {
          _enum: "fillContents",
          _value: "foregroundColor"
        },
        opacity: {
          _unit: "percentUnit",
          _value: 100
        },
        mode: {
          _enum: "blendMode",
          _value: "normal"
        },
        _options: {
          dialogOptions: "dontDisplay"
        }
      }], {
        synchronousExecution: false,
        modalBehavior: "fail"
      });


  });

});

The Manifest I tried looks like this

"host": [{
    "app": "PS",
    "minVersion": "23.0.0",
    "data": {
      "apiVersion": 2
    }
  }],
  "manifestVersion": 4,

It is because you have the modalBehavior option set to “fail”. It needs to be “execute” or default. Just use {} for the batch play options and it will set them to default.

So remove this

{
        synchronousExecution: false,
        modalBehavior: "fail"
      }

and replace it with
{}

Thank You, that has fixed it.
With your Dialog issue, do you see this as an oversight or something which has been done deliberately to only allow one plugin talking back to Photoshop at any given time

And another note with this. There are some timing issues thatcan occur on API 1 with it set to “fail” which will cause processing to just stop. I working with one of the Adobe devs to troubleshoot this. At times, Photoshop will go into a brief modal state and then the API 1 [processing will stop if that occurs and it is set to fail. The workaround in API 1 for this is to set modalBehavior to “wait” as a workaround. Since this was occurring randomly in several places, I set them all to “wait” for my API 1 plugins.

For the "dialogOptions": "display", I don’t know if it is a bug or by design. My best guess is that it is working as designed… at least for now. When running an executeAsModal, Photoshop is in a modal state so the user should not have any control of Photoshop dialogs. Using "dialogOptions": "display" will pop up the dialog but the user just can’t interact or even escape out of it. So it is doing exactly what I would expect.

If there were an option to not use executeAsModal in API 2 then you could have the option. As of now, executeAsModal is required so there is no workaround as far as I can tell.

Are you moving over to API 2 because you need access to the Single History state and extra DOM features and because API will be depreciated and want to stay ahead of the game.