Communicating between Photoshop and Maya (Python)

Can someone show me an example of passing a variable from Python to a Javascript? (both sides of things)
I’ve set up my Python code as discussed in this thread (using subprocess.Popen to open the Photoshop application, the workfile and execute my javascript).

I have a javascript file with my functions at the top, and the executing code at the bottom.
Atm the executing code is passing hardcoded variables internally (in the js file) to my functions - just for testing purposes.
But I want to change these vars to accept input comming from Maya/Python.

Ecexute the js from python with .ExecuteJavaScript() as a string and insert your values into the string. I would use json as the interchange between the two so all your transporting are strings.

Check out my pslib, it has a require function for loading modules, a json implentation because extendscript does support it, and underscore because the js version they use is way old.

[QUOTE=TheMaxx;23579]Ecexute the js from python with .ExecuteJavaScript() as a string and insert your values into the string. I would use json as the interchange between the two so all your transporting are strings.

Check out my pslib, it has a require function for loading modules, a json implentation because extendscript does support it, and underscore because the js version they use is way old.

https://github.com/theiviaxx/PSLib[/QUOTE]

I’m not sure I follow.
How would that code snippet be inserted into the code I already have? (I’m executing it with subprocess.Popen - see below)
I can’t even find any info about that command/object you refer to (ExecuteJavaScript) - does it belong to that pslib of yours?

import subprocess

photoshop = r"X:\Adobe\Adobe Photoshop CC (64 Bit)\Photoshop.exe" #appending script to the end of this raw string
script = r"X:\Lolpath	est.jsx"
texture = r"X:\Lolpath	est.psd"

subprocess.Popen((photoshop, texture, script))

I don’t know anything about JSON - never worked with it. I’m sure I’ll get into it sometime, but atm all I need is a one-direction connection from Python to Photoshop.
Maybe you could catch my interest if you provided me with some more info on the benefits of that library? :wink: If I understand you correctly it gives you a way to have a two-way connection between Python and Photoshop?

ah, i see how you’re doing it. I would keep all my business logic and functions in a file you distribute, then just make temp files from python that call into those functions with your values:

Distribute this with your other tools

dist/libs/funcs.jsx


(function() {
    var Test = {};

    Test.alertName = function(name) {
        alert(name);
    }

    module.exports = Test;
})();

Generate this from python and execute it

tmp/temp.jsx


(function() {
    // Think of this as a python import
    // In python it would look like:
    // import dist.libs.funcs as mylib
    var mylib = require('dist/libs/funcs');

    mylib.alertName('nightshade');
})();

As for getting back the value, i’m not sure where you would look, i doubt the stdout would have it. This approach would probably be a one way road. If you arent going back and forth between python and PS, then dont worry about json just yet.

My pslib does include the require function that lets you write and load modules according to the current js standards. Its similar to a python import.

Let me know if any of that makes sense

[QUOTE=TheMaxx;23583]ah, i see how you’re doing it. I would keep all my business logic and functions in a file you distribute, then just make temp files from python that call into those functions with your values:

Distribute this with your other tools


CODE

As for getting back the value, i’m not sure where you would look, i doubt the stdout would have it. This approach would probably be a one way road. If you arent going back and forth between python and PS, then dont worry about json just yet.

My pslib does include the require function that lets you write and load modules according to the current js standards. Its similar to a python import.

Let me know if any of that makes sense[/QUOTE]
Well I can’t say that code didn’t confuse me. I had to look up self invoking anonymous function expressions on google.
I’ve spoken to some other people regarding this and every single one of them - including you - suggest writing the jsx-file to the disc on the fly and then executing it.
So afaik it appears that you have to do just that (write a file) or modify an already existing jsx file by opening it in python, find the variable and edit it with string substitution - like this:

with open(script_input_not_edited_yet) as o: 
data=o.read() 
theInt=55 
data=re.sub(r'^(theInt\s*=)\s+\d+;', '\1'+str(theInt)+";") 
with open(script_path_after_edit, "w") as w: 
w.write(data) 

Maybe it’s better to just start looking into JSON… :expressionless:
Do you know of any blogs or have any example code on that matter? (tossing JSON objects in between these apps)

[QUOTE=TheMaxx;23583]ah, i see how you’re doing it. I would keep all my business logic and functions in a file you distribute, then just make temp files from python that call into those functions with your values:

Distribute this with your other tools


CODE

As for getting back the value, i’m not sure where you would look, i doubt the stdout would have it. This approach would probably be a one way road. If you arent going back and forth between python and PS, then dont worry about json just yet.

My pslib does include the require function that lets you write and load modules according to the current js standards. Its similar to a python import.

Let me know if any of that makes sense[/QUOTE]
Well I can’t say that code didn’t confuse me. I had to look up self invoking anonymous function expressions on google.
I’ve spoken to some other people regarding this and every single one of them - including you - suggest writing the jsx-file to the disc on the fly and then executing it.
So afaik it appears that you have to do just that (write a file) or modify an already existing jsx file by opening it in python, find the variable and edit it with string substitution - like this:

with open(script_input_not_edited_yet) as o: 
data=o.read() 
theInt=55 
data=re.sub(r'^(theInt\s*=)\s+\d+;', '\1'+str(theInt)+";") 
with open(script_path_after_edit, "w") as w: 
w.write(data) 

Maybe it’s better to just start looking into JSON… :expressionless:
Do you know of any blogs or have any example code on that matter? (tossing JSON objects in between these apps)

EDIT: Some more questions regarding the Maya<–>Photoshop pipe. Even with the use of writing a JSON-object to the disc, which can be readable by both Python and Javascript, it seems to me that the pipe between these apps would still be one-directional. Python can always tell Photoshop to do stuff via subprocess.Popen. But is it even possible for Photoshop to send instructions to Maya? I guess you could make some kind of Python -listener that looks at the JSON object, and starts doing stuff when changes has been made to the file (such as a variable being changed) - but maybe there are other ways?

this just popped up on planet tech art

This will get you information back, but its hacky as he says.

Writing javascript is a different beast and its going to feel a little weird for a while. I really need to get my tcp lib working again, that way you could use pure python to talk to PS and get a result back and even subscribe to events, like foregorund color change or whatever. Anyhow, thats still broken atm.

fyi, the self executing anonymous functions are called closures :slight_smile: They keep everything nice and isolated.

two other possibilities to consider, both a bit out of left field.:

pyjscompiles python into js (alternatively, CoffeeScriptis a somewhat pythonic ‘dialect’ of JS and RapydScriptaims at being more pythonic). So generating your intermediate JS can be less painful.

You might look into firing up a very dumb http or wsgi server in python. Extendscript will let you send HTTP requests using the Socket object:


reply = "";
conn = new Socket;
// access Adobe’s home page
if (conn.open ("www.undeadlabs.com:80")) {
// send a HTTP GET request
conn.write ("GET /index.html HTTP/1.0

");
// and read the server’s reply
reply = conn.read(999999);
conn.close();
};
print (reply);
// example stolen from the JavaScript Tools Guide 

The Extendscript docs also have an example of the making a socket connection as well - so you could start a server in JS/PS that listens for commands from Photoshop

[QUOTE=TheMaxx;23591]this just popped up on planet tech art

This will get you information back, but its hacky as he says.

Writing javascript is a different beast and its going to feel a little weird for a while. I really need to get my tcp lib working again, that way you could use pure python to talk to PS and get a result back and even subscribe to events, like foregorund color change or whatever. Anyhow, thats still broken atm.

fyi, the self executing anonymous functions are called closures :slight_smile: They keep everything nice and isolated.[/QUOTE]

Lol that’s interesting. Because I’ve been corresponding with Pete Hanshaw over LinkedIn today (friday).
So that must be a new blog post based on that correspondence :smiley:

So I’ve been researching socks connections and I’ve discovered that there are many options on the python side of things.
Many different third party modules around, and if you don’t wanna use that you can always use the Maya commandPort command - like in this example:
http://www.creativecrash.com/forums/mel/topics/online-control-of-maya-via-webpage#discussion_post_263927
(Maya <-> web browser communication)

The biggest issue is on the Photoshop side. Correct me if I’m wrong here but:
VBscript and javascript are client-side
Neither language has proper native socks support (bi-directional communication). The only examples I’ve found are of these scripts connecting to a remote website, tossing a GET command at the server and recieving something (like an entire webpage). POST requires third-party libraries.

So yeah I’m stuck here, and getting more and more frustrated that Adobe haven’t made any Python interpreter for their applications (Adobe prefers to prioritize new Lightroom -sliders for the world’s Photographers, instead of giving us game developers something cool to play with). Just have a look at: http://www.youtube.com/watch?v=_cHmnVjptjY
Doesn’t that seem useful?

I’ve tried contacting that guy (he actually lives in the same city as I - works for DICE as a software engineer) but haven’t recieved a response yet.
According to the comments there he abandoned that project because DICE found other ways to improve their workflows.

Ok i finally got time to get a working version out the door. So you’ll need to have PS 5.5+ to get this to fly and just go back forth between PS. I’ll have to post all of the events, but here is an example.

In photoshop go to Edit > Remote Connections and enable them and set the password to “Swordfish” then in python:


>>> pip install pyps


from pyps import Connection, EventListener

conn = Connection()
conn.connect(passwd='Swordfish')
conn.send('alert("Hello");', True)

print conn.send('$.version;', True)

def callback(message, *args):
    print message.command
    print message.content

def callback2(message, *args):
    print message.command
    print message.content
    print args

listener = EventListener(conn)
listener.start()
listener.subscribe('foregroundColorChanged', callback)
listener.subscribe('toolChanged', callback2, (True, 'xxx'))
listener.subscribe('currentDocumentChanged', callback)

## -- We need to keep the EventListener alive
while True:
    time.sleep(1.0)

Please let me know if you run into any bugs or problems.

Yea, that pyps module you got there - where did you get it from and how do I install it?
Also, you say that PS 5.5+ is needed: are you refering to PS CS5 or Photoshop -version- 5.5? And what is it that is missing in earlier versions of PS that prevents this from working?

I wrote it
Get it from pypi or use pip to install it
CS 5.5
Cs5.5 introduced a tcp connection to use with the ipad companion apps. If you have cs 5, its a free upgrade.

[QUOTE=TheMaxx;23604]I wrote it
Get it from pypi or use pip to install it
CS 5.5
Cs5.5 introduced a tcp connection to use with the ipad companion apps. If you have cs 5, its a free upgrade.[/QUOTE]

Ok, I downloaded it from pypi, extracted to X:\Autodesk\Maya2014\Python\Lib\site-packages
Maya does not find the module when I run that code. # ImportError: No module named pyps #
I think you are overestimating me. Give me verbose instructions.

haha, ok. You should probably get pip installed using maya. This will help you with everything else:

http://www.pip-installer.org/en/latest/installing.html

download https://raw.github.com/pypa/pip/master/contrib/get-pip.py and run it with

X:\Autodesk\Maya2014\bin\mayapy.exe get-pip.py

That will install pip for you. Now you can either put it on your path or call it explicitly. To put it on your path

set PATH=%PATH%;X:\Autodesk\Maya2014\Python\Scripts

Now you can run it like this:

pip install pyps

This will grab any dependencies too. If maya doesnt find it, check your path in maya:


import sys
print '
'.join(sys.path)

And make sure X:\Autodesk\Maya2014\Python\Lib\site-packages\ is in there

The biggest issue is on the Photoshop side. Correct me if I’m wrong here but:
VBscript and javascript are client-side
Neither language has proper native socks support (bi-directional communication). The only examples I’ve found are of these scripts connecting to a remote website, tossing a GET command at the server and recieving something (like an entire webpage). POST requires third-party libraries.

“Real” JS is client side only and is security-sandboxed. Photoshop and other adobe apps - at least in the CS era and later - run ‘Extendscript’, a custom flavor of JS which also includes extra functions for local file system and socket access. If they ran ‘real’ JS you would not be able to write files out of them.

If you change the line

print(reply)

to

alert(reply);

and run the example above in Photoshop you should see a big page of http request gibberish (if you point it at website that returns simple text it may be easier).

I hate to be the negative one here but I don’t think we are closer to a solution.
TheMaxx: Too many dependencies, Complicated installation, will not work for Photoshop prior to CS5 as you said yourself. Sadly I can’t use that for any future tool. :frowning:
Theodox: Thanks for clearing that up - I knew there was something different about JS in Photoshop.
I’ve tried doing a HTTP GET request by using the socket -object in Photoshop in order to retrieve a webpage. I placed that stuff in a variable and used alert on it to confirm that Photoshop indeed recieved the data as it should. However I have yet to see a working example of sending (or POSTing) data out from Photoshop.

The kind of data I’m interested in sending are single string commands. I thought that maybe I could just use the system buffer (another idea I had) for this but it seems that Javascript is unable to place anything there automagicly.

Sigh…
Maybe I should just postpone this project, pick up a C++ book, learn the basics of that this year and come back next year instead? After seeing that Python interpreter for Photoshop (link) it made me wish that I could at least comprehend the basics of how he did that. I don’t mind research and study - but I’m rather impatient and visionary as a person which I think isn’t a very great combo.

Thanks for trying to help out though: I appreciate it a lot more than I might show.

I’ll be adding to my pslib an http module that will let you do http requests with data and file attachements. I have everything working, just need to clean it up and polish some stuff.

Sorry about the CS5+ req.

Why can’t you add the pywin32 stuff in with your scripts?

I’m not sure when Adobe added Socket to their flavor of Javascript ; whenever it was it is the lower limit for anybody doing IO stuff with Adobe JS.

As for send/receive, the Javascript scripting doc from Adobe includes an example showing a chat server in PS. I have not tried it but i don’t see any reason to think it would not work – the socket object clearly has a writeline method for sending. You’d have to cook up a simple terminal system (conceptually, more or less the same thing people do when they control Maya using commandPort from Eclipse or another text editor).

Not great, but there it is. Sorry it’s so nasty. Would be nice if COM didn’t stink :wink:

Here’s a simple working example of a TCP server running in photoshop remote controlled from Python. Tech Art Survival Guide: Talking to Photoshop via TCP