How to communicate between Electron App and Photoshop plugin?

I have an Electron App which I want to link with a plugin within Photoshop. Basically I want to open the Electron App from the plugin within Photoshop and send things from plugin the Electron App and vice versa, Is this possible with Generator within Photoshop or which options do I have for this communication?

My Electron App will do some things that cannot be done in PS, like using WebGL and then I’ll export from this App, the thing is I want to open an .EXE ( the Electron App ) from a Photoshop plugin, is this possible?

I tried with the shell module but it is very limited as far as I’ve learned.

Hope this is clear enough.

Thanks in advance!

Webview wouldn’t solve it?

An option would be to have the plugin on my server an open it with WebView and send back information as blob message?

I mean if you need WebGL and nothing else… you could use Webview in UXP and avoid Electron entirely.

1 Like

But otherwise, stuff like that is certainly possible. I did it with UXP client plugin and server in NodeWebkit using websockets. https://www.youtube.com/watch?v=GBC1s0HR1z0

But automatic opening and closing it ugly part. I think I just showed a message to users about what they should open?

2 Likes

That plugins looks awesome, did you continue it? Looks very helpful Jarda!

I’m right now tryin with Webview, I managed to connect the plugin ( server side ) to the webview ( Photoshop UXP ), now I’m just trying to export a layer as blob and import it back using Node.js, seems the logic would work but I’m in the middle of that atm.

It looks awesome, I think it is awesome… I showed it to professionals they like it as well but nobody really needs it or uses it :smiley: …so no point in developing this. But I think it should still work so you can use it if you want to :smiley:

In my experience the fastest was to save image to filesystem and send string where image should be loaded from. But webview in UXP unlike nodewebkit can’t save to filesystem automatically.

Aren’t UXP blobs limited to UXP scope? Meaning it can’t get outside into different apps?

1 Like

Thanks man! Still think it is a great tool for fast prototyping!

About the UXP webViewHTMLElement, I cannot make it to work, I don’t understand very well the documentation is not clear enough for me to get it fast:

https://developer.adobe.com/photoshop/uxp/2022/uxp-api/reference-js/Global%20Members/HTML%20Elements/HTMLWebViewElement/

//Example

// Send message from plugin to WebView
let webViewDisplay = document.getElementById("webviewSample");
webViewDisplay.postMessage("PluginMessage1");

// Plugin receives message from WebView via "message" event.
window.addEventListener("message", (e) => {
  console.log(`Message from WebView(Origin:${e.origin}): ${e.data}\n`);

  if (e.data === "webviewmessage1") {
    webViewDisplay.postMessage("Thanks, Message1 recieved successfully");
  }
});

// Send message from plugin to WebView
let webViewDisplay = document.getElementById("webviewSample");
webViewDisplay.postMessage("PluginMessage1");

// Plugin receives message from WebView via "message" event.
window.addEventListener("message", (e) => {
  console.log(`Message from WebView(Origin:${e.origin}): ${e.data}\n`);

  if (e.data === "webviewmessage1") {
    webViewDisplay.postMessage("Thanks, Message1 recieved successfully");
  }
});
//Example

// WebView sends message to Plugin
window.uxpHost.postMessage("webviewmessage1");

// WebView receives messages from Plugin
window.addEventListener("message", (e) => {
  // (e) from Plugin
  // e.origin would be 'plugin id'
  // e.source would be 'window.uxpHost'
  // e.data is 'JSON.parse(JSON.stringify("PluginMessage1"))' which is "PluginMessage1"
  if (e.data === "PluginMessage1") {
    console.log(e.data);
  }
});

// WebView sends message to Plugin
window.uxpHost.postMessage("webviewmessage1");

// WebView receives messages from Plugin
window.addEventListener("message", (e) => {
  // (e) from Plugin
  // e.origin would be 'plugin id'
  // e.source would be 'window.uxpHost'
  // e.data is 'JSON.parse(JSON.stringify("PluginMessage1"))' which is "PluginMessage1"
  if (e.data === "PluginMessage1") {
    console.log(e.data);
  }

I just don’t undertand about the window.uxpHost.postMessage("webviewmessage1");, that gives me undefined. The window objects seems to not have a “uxpHost” object in it. I literally just copy a pasted these two chunks of code in my plugin to see what the heck it does and don’t understand it…

About the UXP blobs, i don’t really now the limitations haven’t get there yet, still stuck in sending message to webview and from it to the plugin. Any ideas how to simplify the explanation of this documentation?

What do you have in manifest file?

This is the manifest I’m using:

{
  "id": "xport",
  "name": "XPORT",
  "version": "1.0.0",
  "main": "index.html",
  "host": [
    {
      "app": "PS",
      "minVersion": "23.0.0",
      "data": {
        "apiVersion": 2,
        "loadEvent": "use"
      }
    }
  ],
  "requiredPermissions": {
    "localFileSystem": "fullAccess",
    "launchProcess": {
      "extensions": [
        ""
      ],
      "schemes": [
        "https"
      ]
    },
    "network": {
      "domains": "all"
    },
    "allowCodeGenerationFromStrings": true,
    "webview": {
      "allow": "yes",
      "domains": "all",
      "enableMessageBridge": "localAndRemote"
    }
  },
  "manifestVersion": 5,
  "entrypoints": [
    {
      "type": "panel",
      "id": "xport",
      "minimumSize": {
        "width": 333,
        "height": 790
      },
      "maximumSize": {
        "width": 1000,
        "height": 2160
      },
      "preferredDockedSize": {
        "width": 333,
        "height": 790
      },
      "preferredFloatingSize": {
        "width": 333,
        "height": 790
      },
      "label": {
        "default": "XPORT"
      },
      "icons": [
        {
          "width": 23,
          "height": 23,
          "path": "icons/dark.png",
          "scale": [
            1,
            2
          ],
          "theme": [
            "dark",
            "darkest",
            "medium",
            "light",
            "lightest",
            "all"
          ]
        }
      ]
    }
  ],
  "icons": [
    {
      "width": 48,
      "height": 48,
      "path": "icons/dark.png",
      "scale": [
        1,
        2
      ],
      "theme": [
        "darkest",
        "dark",
        "medium",
        "lightest",
        "light"
      ],
      "species": [
        "pluginList"
      ]
    }
  ],
  "runOnStartup": true
}

I don’t see problem in manifest.

As far as I understand, I’m having this undefined error because I’m trying to access window.uxpHost within a context where it doesn’t exists. In the documentation says that it should be called inside the “webview”, but what does that exactly means or which scope is that?

No… in webview you have to use this to get data out: Window: postMessage() method - Web APIs | MDN

It is a pure OS built-in browser with no additions.

1 Like

I was actually just doing this today. Not sure if I can explain it well enough, but I’ll try.

In your plugin, if you have a webview with id=“webviewsample” in your HTML,
Then you can send info to it via

var webViewDisplay = document.getElementById("webviewsample");
   webViewDisplay.postMessage("buttonClicked");

Then in your server code, add and event listener and watch for that message and do something

if (e.data == "buttonClicked") {
    runSomething();
  }

Then if you want to send some info back to your plugin (that also has an event listener)

window.uxpHost.postMessage("Some Message!", '*');
1 Like

I found what my problem was, so silly. I was trying to access window.uxpHost through the browser ( for testing ) but when I fired it from the UXP webview and it worked, so uxpHost of course doesn’t exists in chrome or any other browser but within the UXP plugin inside the webviewHTMLElement the uxpHosts do exists.

I know is something silly but I was driving me nuts all day lmao.

Thanks for your help guys! Now is time to test performance sending data. Gonna try with base64.

Let me know if you find a better way, but here is the way I am doing it…

Web script:

url = arrayBufferToBase64(e.data);
window.uxpHost.postMessage(url, '*');

In my plugin:

var buffer = e.data;
var newbuffer = base64ToArrayBuffer(buffer);

function base64ToArrayBuffer(base64) {
   var binaryString = atob(base64);
   var bytes = new Uint8Array(binaryString.length);
   for (var i = 0; i < binaryString.length; i++) {
     bytes[i] = binaryString.charCodeAt(i);
   }
   return bytes.buffer;
 }
1 Like

Would TextEncoder work? Would it be faster? TextEncoder: encode() method - Web APIs | MDN

That didn’t work for me, but it may be because I am not using node

It is not about NodeJS… but I don’t see it implemented in UXP


image

Yep, that was the error I got.