Batchplay problem when converting actions with Occultist and Alchemist. Need help

Hi, first thing to say I’m a noob. I love to automate my retouch workflows but my dev knowledge is close to zero.

I’ve built quite advanced CEP panel in the past but now I’m struggling with UXP and Batchplay.

I’m using Occultist and Alchemist to create batchplay script from PS action.
In case of some actions I’ve noticed that they will not work (I’m getting errors in PS) if I’ll not remove some square brackets [ ].

This is an example generated by Occultist that doesn’t work:

const batchPlay = require("photoshop").action.batchPlay;
const result = await batchPlay(
[
   {
      _obj: "make",
      _target: [
         {
            _ref: "layer"
         }
      ],
      layerID: 117,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "make",
      new: {
         _class: "channel"
      },
      at: [
         {
            _ref: "channel",
            _enum: "channel",
            _value: "mask"
         }
      ],
      using: {
         _enum: "userMaskEnabled",
         _value: "revealAll"
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   }
],{
   synchronousExecution: false,
   modalBehavior: "wait"
});

I’ve found out that if I’ll remove [ ] inside of _obj: it will work:

const batchPlay = require("photoshop").action.batchPlay;
const result = await batchPlay(
[
   {
      _obj: "make",
      _target: 
         {
            _ref: "layer"
         }
      ,
      layerID: 117,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "make",
      new: {
         _class: "channel"
      },
      at: 
         {
            _ref: "channel",
            _enum: "channel",
            _value: "mask"
         }
      ,
      using: {
         _enum: "userMaskEnabled",
         _value: "revealAll"
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   }
],{
   synchronousExecution: false,
   modalBehavior: "wait"
});

I have no idea why but it does.

This is how I execute the script:

async function test() {

// code generated by Ocultist / Alchemist

}
   
   document.querySelector("#btntest").addEventListener("click", test)

Unfortunately this simple trick doesn’t work in case of some objects like _obj: “applyImageEvent”

I’m using them in Frequency separation actions, High Pass sharpening etc. It’s crucial for me to make it work in UXP panel.

This is the part of the code that doesn’t work because if I’ll remove [ ] I’m getting errors:

 {
      _obj: "applyImageEvent",
      with: {
         _obj: "calculation",
         to: [
            {
               _ref: "channel",
               _enum: "channel",
               _value: "RGB"
            },
            {
               _ref: "layer",
               _name: "Frequency Separation LF"
            }
         ],
         calculation: {
            _enum: "calculationType",
            _value: "subtract"
         },
         scale: 2,
         offset: 128
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   }

And the full script I’m using for Frequency Separation:

   
async function fsgaussian() {

const batchPlay = require("photoshop").action.batchPlay;
const result = await batchPlay(
[
   {
      _obj: "make",
      _target: 
         {
            _ref: "layer"
         }
      ,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "mergeVisible",
      duplicate: true,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "set",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "targetEnum"
         }
      ,
      to: {
         _obj: "layer",
         name: "Frequency Separation LF"
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "make",
      _target: 
         {
            _ref: "layer"
         }
      ,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "mergeVisible",
      duplicate: true,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "set",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "targetEnum"
         }
      ,
      to: {
         _obj: "layer",
         name: "Frequency Separation HF"
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "set",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "targetEnum"
         }
      ,
      to: {
         _obj: "layer",
         opacity: {
            _unit: "percentUnit",
            _value: 0
         },
         layerEffects: {
            _obj: "layerEffects",
            scale: {
               _unit: "percentUnit",
               _value: 333.3333333333333
            }
         }
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "select",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "backwardEnum"
         }
      ,
      makeVisible: false,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "gaussianBlur",
      radius: {
         _unit: "pixelsUnit",
         _value: 4.5
      },
      _options: {
         dialogOptions: "display"
      }
   },
   {
      _obj: "select",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "forwardEnum"
         }
      ,
      makeVisible: false,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "applyImageEvent",
      with: {
         _obj: "calculation",
         to: [
            {
               _ref: "channel",
               _enum: "channel",
               _value: "RGB"
            },
            {
               _ref: "layer",
               _name: "Frequency Separation LF"
            }
         ],
         calculation: {
            _enum: "calculationType",
            _value: "subtract"
         },
         scale: 2,
         offset: 128
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "set",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "targetEnum"
         }
      ,
      to: {
         _obj: "layer",
         opacity: {
            _unit: "percentUnit",
            _value: 100
         },
         mode: {
            _enum: "blendMode",
            _value: "linearLight"
         },
         layerEffects: {
            _obj: "layerEffects",
            scale: {
               _unit: "percentUnit",
               _value: 333.3333333333333
            }
         }
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "select",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "backwardEnum"
         }
      ,
      selectionModifier: {
         _enum: "selectionModifierType",
         _value: "addToSelection"
      },
      makeVisible: false,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "make",
      _target: 
         {
            _ref: "layerSection"
         }
      ,
      from: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "targetEnum"
         }
      ,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "set",
      _target: 
         {
            _ref: "layer",
            _enum: "ordinal",
            _value: "targetEnum"
         }
      ,
      to: {
         _obj: "layer",
         name: "Frequency Separation 8bit"
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "select",
      _target: 
         {
            _ref: "layer",
            _name: "Frequency Separation LF"
         }
      ,
      makeVisible: false,
      layerID: 
         64
      ,
      _options: {
         dialogOptions: "dontDisplay"
      }
   },
   {
      _obj: "select",
      _target: 
         {
            _ref: "brush",
            _name: "Wet Brush FS MEDIAN LOW"
         }
      ,
      _options: {
         dialogOptions: "dontDisplay"
      }
   }
],{
   synchronousExecution: false,
   modalBehavior: "wait"
});

   
   }
   
   document.querySelector("#btnfsgaussian").addEventListener("click", fsgaussian)

What am I doing wrong? I’ve heard something about API changes and executeAsModal but I have no idea if it’s related.

When I’m debugging my plugin I’m getting one error related to API version but I don’t know how to update it to apiVersion 2. Maybe you could help with this as well?

Thank you all in advance, I will really appreciate your help!

I think in manifest version 5 with API version 2 in PS 23 inside executeAsModal you would probably wait forever because you start modal mode in first place but batchplay can’t run within modal mode so you would get into a deadlock.

Could you show your manifest?

Also, I made a new panel that could generate plugins for you Sorcerer - New Alchemist panel to generate plugins

Please check the video and try same/similar steps and let me know whether that worked.

Thank you very much for your will to help.

This is my manifest, it’s not completed yet but it will load plugin through Adobe UXP Developer Tool.

{
  "id": "MFUYXP66",
  "name": "ADV.Retouch UXP Edition",
  "version": "1.0.0",
  "main": "index.html",
  "host": [
    {
      "app": "PS",
      "minVersion": "22.0.0"
    }
  ],
  "manifestVersion": 4,
  "entrypoints": [
    {
      "type": "panel",
      "id": "vanilla",
      "minimumSize": {
        "width": 260,
        "height": 880
      },
      "maximumSize": {
        "width": 260,
        "height": 880
      },
      "preferredDockedSize": {
        "width": 260,
        "height": 880
      },
      "preferredFloatingSize": {
        "width": 260,
        "height": 880
      },
      "label": {
        "default": "ADV.RETOUCH UXP Edition"
      }
    }
  ],
  "icons": [
    {
      "width": 23,
      "height": 23,
      "path": "icons/iconNormal.png",
      "scale": [
        1,
        2
      ],
      "theme": [
        "darkest",
        "dark",
        "medium"
      ]
    },
    {
      "width": 23,
      "height": 23,
      "path": "icons/iconNormal.png",
      "scale": [
        1,
        2
      ],
      "theme": [
        "lightest",
        "light"
      ]
    }
  ]
}

Still work in progress:

I don’t think that the issue with some _obj: failing to run is related to manifest file. When I’m running the code generated in alchemist it also doesn’t work, it stops on _obj: “applyImageEvent”

Thank you!

Ok so you have
manifest version 4
PS 22
and no API version.

Since minimum PS version is 22 then API version is decided to be version 1 (for PS 23 it would be version 2)
Therefore executeAsModal does not apply in your case here.

For applyImageEvent… most of the time issue could be missing file (path) token since Alchemist can’t generate it or raw data type.

I can update manifest file if needed but will it change anything?

This is the recording of an issue. Action can create mask but the script generated in Occultist and played in Alchemist can’t.

After removing [ ] in _obj: it works fine.

Unfortunately it doesn’t work in case of this _obj:

{
      _obj: "applyImageEvent",
      with: {
         _obj: "calculation",
         to: [
            {
               _ref: "channel",
               _enum: "channel",
               _value: "RGB"
            },
            {
               _ref: "layer",
               _name: "Frequency Separation LF"
            }
         ],
         calculation: {
            _enum: "calculationType",
            _value: "subtract"
         },
         scale: 2,
         offset: 128
      },
      _options: {
        dialogOptions: "dontDisplay"
      }
   }

When I’m trying to remove [ ] in this obj, I’m getting a lot of errors:

 
{
      _obj: "applyImageEvent",
      with: {
         _obj: "calculation",
         to:
            {
               _ref: "channel",
               _enum: "channel",
               _value: "RGB"
            },
            {
               _ref: "layer",
               _name: "Frequency Separation LF"
            },
         calculation: {
            _enum: "calculationType",
            _value: "subtract"
         },
         scale: 2,
         offset: 128
      },
      _options: {
        dialogOptions: "dontDisplay"
      }
   }

Simply removing the brackets is a bad idea, as this is not a valid JavaScript object anymore. Each key can only hold one value, for multiple values you’ll need the array.

This descriptor works fine:

{
      "_obj": "applyImageEvent",
      "with": {
         "_obj": "calculation",
         "to": {
            "_ref": [
               {
                  "_ref": "channel",
                  "_enum": "channel",
                  "_value": "RGB"
               },
               {
                  "_ref": "layer",
                  "_enum": "ordinal",
                  "_value": "merged"
               }
            ]
         },
         "calculation": {
            "_enum": "calculationType",
            "_value": "subtract"
         },
         "scale": 2,
         "offset": 128
      },
   }
1 Like

Thank you very much Simon, it works! You’re my saver :slight_smile: As far as I see the difference is that each parameter is in " ". How did you find it out? Interesting thing is that Visual Studio Code doesn’t recognise (highlight) this part of code as it does with the rest. Most important is that it works but I’m wondering why Occultist generates wrong code.

Cheers!

I’ve noticed one more thing, the code now doesn’t take into account layer name for calculation, is it something that can be changed / added?

 {
               _ref: "layer",
               _name: "Frequency Separation LF"
            }

Ok I have the final solution:

{
      _obj: "applyImageEvent",
      with: {
         _obj: "calculation",
         to: {
            _ref: [
               {
                  _ref: "channel",
                  _enum: "channel",
                  _value: "RGB"
               },
               {
                  _ref: "layer",
                  _name: "Frequency Separation LF"
               }
            ]
         },
         calculation: {
            _enum: "calculationType",
            _value: "subtract"
         },
         scale: 2,
         offset: 128
      },
      _options: {
         dialogOptions: "dontDisplay"
      }
   }

Thank you all!

2 Likes

The quotation marks don’t make a difference, you can write object keys both ways. I also prefer the version without the quotes due to the better highlighting.

Yes, in most cases the layer reference can be adjusted to the specific needs (layer by name, layer by ID, etc.)

However, I think that both of these things are not what made the code work or not. The main difference is how the to (target reference) array is wrapped:

to: [
  reference,
  reference
],

vs.

to: {
  _ref: [
      reference,
      reference
  ]
}

I didn’t have a chance to look at Occultist yet. From what I’ve heard it it converts Actions to batchPlay?
Maybe @Jarda has an idea why Actions produce a different to property.

1 Like

I have some idea… the reason is somewhere here: alchemist/ATNDecoder.ts at master · jardicc/alchemist · GitHub

But it would take me a while to recall the differences :smiley: I would need some debugging.

1 Like

Yes, Occultist can convert an action to batchPlay but there is the difference in result comparing what Listener in Alchemist is providing.

That’s where my error came from.