Pyblish for Photoshop

I’ve had Photoshop in mind since day 1 but always imagined an implementation would have to involve JavaScript or VBScript and never once considered it to be possible with Python.

But then I saw this.

And apparently it’s way possible and has been possible for almost a decade. :open_mouth:

The challenge of integrating with Photoshop however lies in the fact that the Python-side isn’t integrated into the execution environment, which means Pyblish can’t either. Luckily, this isn’t as uncommon as I first thought. We’ve already experienced this with Modo, Softimage, Fusion and now Photoshop. Solving this for one, will likely pave the way for each of them.

I’ve got an idea for an implementation, but will need your help.

Basically, the Pyblish run-time needs to run within a Python environment. In case of Maya, Nuke and Houdini, this is straightforward as they each are providing the environment seamlessly within it’s own execution environment. What this means for Photoshop et. al. is that we are now looking at 2 separate processes running in tandem with the host.

This is how it looks currently, in Maya et. al.

And here’s how it will need to look like for Photoshop et. al.

Users interact with the GUI, and Pyblish interacts with the Python interpreter, whereas the Python interpreter interacts with the host.

The ingredients for this little adventure is this.

gui.py

import sys
import argparse
import xmlrpclib

parser = argparse.ArgumentParser()
parser.add_argument("publish", action="store_true")

args = parser.parse_args()
if args.publish is True:
  # Connect with python.py
  proxy = xmlrpclib.ServerProxy("http://127.0.0.1:9090")
  if proxy.publish():
    print("Successfully published!")
else:
  print("Available argument is 'publish'")

middleman.py

import threading
from SimpleXMLRPCServer import SimpleXMLRPCServer

# Host-specific library
import host

def publish():
  print("python.py publishing..")
  if host.export_all():
    return True
  return False

server = SimpleXMLRPCServer(("127.0.0.1", 9090))
server.register_function(publish)

worker = threading.Thread(target=server.serve_forever)
worker.daemon = True
worker.start()
print("Listening on 127.0.0.1:9090")

host.py

import time

def export_all():
  print("Exporting all..")
  time.sleep(2)
  print("Success!")
  return True

Experiment

To test things out, open up two terminals and run middleman.py and gui.py.

Terminal 1

$ python middleman.py
Listening on 127.0.0.1:9090

Terminal 2

$ python gui.py publish
Attempting to publish..
Successfully published!

This emulates Pyblish QML (gui.py), the individual process we would need to run in order to communicate with Photoshop (host.py) and the connection with the host (middleman.py).

If we can replace import host from middleman.py with a connection to Photoshop, and call an actual command instead of export_all(), we’re done.

The same will then apply to Modo, Softimage and Fusion.

Anyone brave enough to give it a go? :slight_smile:

1 Like

Does this mean this would be Windows only? Or does a python package exist that can provide the functionality for more platforms?

I have no idea. But looking at this thread, I’d assume there are similar solutions for other platforms.

It seems like there is also a socket option for PS and AE; http://download.macromedia.com/pub/developer/aftereffects/scripting/JavaScript-Tools-Guide-CC.pdf (p194).

Of course the problem is that we’ll be sending javascript across instead of python.

I’ve been reading those pages a few times now, trying to wrap my head around how this could work, but I cannot. I think the problem is that the server, as in your host Photoshop or After effects, will need to run Python in order to use Pyblish as it exists today.

The only way I see a plain socket connection work is if we also implement the publishing mechanism of Pyblish in JavaScript; which is possible, and will likely happen eventually, but hasn’t happened yet.

What this feature would allow us to do however is to build a frontend for Pyblish in Photoshop; for example, as an internal widget, docked somewhere.

This is how Pyblish QML works currently, it’s written in a completely independent language (which just so happens to also be Python, but could have been any language) and communicates with the Pyblish run-time across a socket.

That is, the client (JavaScript/Go/C++/Python/Whatever) connects to the server (Python-only) this way. Whereas this method does the opposite; it would involve a client, written in whatever Photoshop supports, such as JavaScript or Python, connecting to a server, written in JavaScript, running within Photoshop.

Does any of that make sense? :smile:

That does make sense:)

I guess this forces me even more so, to just validate instead of repairing as well.

For safekeeping and future readers.

We’ve got a Photoshop integration, thanks to @loonghao!